一入爬虫深似海,从此早睡是路人
“网络爬虫”又称“网络蜘蛛”,是一种在互联网上自动采集数据的自动化程序。爬虫的规模可大可小,大到百度、谷歌搜索,小到文本采集、自动采集图片等。
1 获取目标地址
下面介绍如何获取准备爬取内容的 URL。以阿里云漏洞预警页面为例,我们要得到的是漏洞预警标题、同标题 URL、漏洞预警公告时间等信息。图 1 中 URL 就是我们准备爬取的地址:
可获取目标的 Python 爬虫代码片段如下:
#获取目标 urls = ['https://help.xxxxxx.com/n***/92****/{}.html'.format(str(i)) for i in range(0,2,1)]for url in urls:html = get_html(url)其爬取结果如图 2 所示:
爬虫的本质是网络请求,在请求一个网页获得响应后获取 html 源码,接着处理获取到的 html 源码,并提取想要的数据,如图 3 所示。
出于降低编程难度以及代码重用等方面的考虑,通常将每个功能封装为一个个函数。
2 获取当前 URL 的 HTML
图 4 就是我们需要的 HTML 内容,我们将通过 python 的 requests 库对其进行获取。
通过 requests 库获取目标页面的 HTML 源码如下所示。考虑到代码比较容易理解,所以不在此处做过多说明。import requestsdef get_html(url):'''获得 HTML'''headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/53
7.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'}response = requests.get(url, headers=headers)if response.status_code == 200:response.encoding = 'utf-8'return response.textelse:return
从上述的源码可以看出,我们可通过 requests 库的 get 函数直接获取到目标页面的 HTML 源码。
requests 库的的其他常用方法如图 5 所示。
另外,在使用 requests 库时,我们还可以添加一些字段,如表 1 所示。
表 1params 字典或字节序列,作为参数增加到 url 中 data 字典、字节序列或文件对象,作为 Request 的内容 json JSON 格式的数据,作为 Request 的内容 headers 字典,HTTP 定制头 cookies 字典或 CookieJar,Request 中的 auth : 元组支持 HTTP 认证功能 files 字典类型,传输文件 timeout 设定超时时间,秒为单位 proxies 字典类型,设定访问代理服务器,可以增加登录认证 allow_redirects True/False,默认为 True,重定向开关 stream True/False,默认为 True,获取内容立即下载开关 verify True/False,默认为 True,认证 SSL 证书开关 cert 本地 SSL 证书 auth 元组,支持 HTTP 认证功能
使用参数 cookies、proxite 与 verify 的代码示例如下:
• 小例子• cookies = {'cookies_are':'working'}• proxite = {• 'http':'http://127.0.0.1:8080',• 'https':'https://127.0.0.1:8080'• }• res = requests.get(url, cookies=cookies, proxite=proxite, verify=False• )#verify=False 在请求的时候把 verify 参数设置为 False 就可以关闭证书验证了
另外在 header 内添加些其他能用到的字段,可以达到自己编辑 http 响应头的目的,代码片段如下。
headers = {'Proxy-Connection': 'keep-alive','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36','Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8','Accept-Encoding': 'gzip, deflate','Accept-Language': 'zh-CN,zh;q=0.9'}不同页面 HTML 的获取条件是不一样的。对此,我们在使用的时候需要根据实际情况进行编写,一般情况下添加 UA 即可。如果我们的目标是一个网站登录后的页面,为了能爬取到 HTML,我们还需要用到 cookie 字段,如图 6 所示,或者表单模拟用户登录。
#表单模拟用户登录 import requestsfrom fake_useragent import UserAgent#生成随机 UAurl = 'https://*****.com/login'headers = {'User-agent' : UserAgent().random,}data = {'name' : '你的','password' : '你的'}response = requests.post(url,headers=headers,data=data)response.encoding = 'utf-8'print(response.text)
其他字段对于一般爬虫而言不一定有用,但笔者也将它们列举出来,希望可以为读者拓宽思路。
3 数据提取
XPathXPath 即 XML 路径语言(XML Path Language),它是一种用来确定 xml 文档中某部分位置的语言。
xml 文档(html 属于 xml)是由一系列节点构成的树,例如:
<html><body><div ><p>Hello world<p><a href="/home">Click here</a></div></body></html>
xml 文档的节点有多种类型,其中最常用的有以下几种:• 根节点整个文档树的根。• 元素节点 html、body、div、p、a。• 属性节点 href。• 文本节点 Hello world、Click here。
节点间的关系有以下几种:• 父子 body 是 html 的子节点,p 和 a 是 div 的子节点。反过来,div 是 p 和 a 的父节点。• 兄弟 p 和 a 为兄弟节点。• 祖先/后裔 body、div、p、a 都是 html 的后裔节点;反过来 html 是 body、div、p、a 的祖先节点。
XPath 常用的基本语法如图 7 所示。
下面,我们看看 XPath 的 3 个常用函数的使用。String(arg):返回参数的字符串 Contains(str1,str2):判断 str1 中是否包含 str2,返回布尔值 Text():提取文本
举下面这个例子说明:<div class="c-span9 c-span-last"><div><span class=" newTimeFactor_before_abs c-color-gray2 m">2020 年 6 月 19 日 </span></div><style>.user-avatar {}</style><div class="f13 c-gap-top-xsmall se_st_footer user-avatar"><a target="blank" href="http://www.baidu.com/;" style="text-decoration:none;position:relative;"><div class="c-img c-img-circle c-gap-right-xsmall" style="display: inline-block;width: 16px;height: 16px;position: relative;top: 3px;vertical-align:top;"><img src=""></div>知乎</a><div class="c-tools c-gap-left" id="tools_4828209406812473379_2" data-tools="{"title":"通俗的讲,网络爬虫到底是什么? - 知乎","url":"http://www.baidu.com/link?url=7rZRcme-wDX4h3VV5_YIsgYiQ9k-Vno9y5n5VMA9uSZT9_bMdDBN9RdvSMVyQsPWu91QvJbSz5Zsa6mngIvqj"}"><i class="c-icon f13"></i></div><span><span></span></span><style>.snapshoot, .snapshoot:visited {color: #9195A3!important;}.snapshoot:active, .snapshoot:hover {color: #626675!important;}</style><a data-click="{'rsv_snapshot':'1'}" href="http://cache.baiducontent.com" target="_blank" class="m c-gap-left c-color-gray kuaizhao snapshoot">百度快照</a></div></div>例如这个 html 代码,假设我需要提取的是百度快照四个字。就可以构造如下的 XPath。
//div[@class="c-row c-gap-top-small"]/div/div/a[2]
可以看到效果如图 8 所示。
CSS 选择器
CSS 选择器的语法比 XPath 更简单一些,但功能不如 XPath 强大。实际上,当我们调用 Selector 对象的 CSS 方法时,在其内部会使用 Python 库 cssselect 将 CSS 选择器表达式翻译成 XPath 表达式,然后调用 Selector 对象的 XPATH 方法。CSS 选择器的常用的基本语法如图 9 所示。
CSS 选择器的例程如下所示。print(soup.select('a[href="http://example.com/elsie"]')) # 寻找 a 标签中 href="http://example.com/elsie"的标签 print(soup.select('a[href^="http://example.com/"]')) # 寻找 href 属性值是以"http://example.com/"开头的 a 标签 print(soup.select('a[href$="tillie"]'))#寻找 href 属性值是以 tillie 为结尾的 a 标签 print(soup.select('a[href*=".com/el"]'))#寻找 href 属性值中存在字符串”.com/el”的标签 a
正则数据提取正则表达式是一种文本模式,包括普通字符和特殊字符。正则表达式使用单个字符串来描述、匹配一系列某个句法规则的字符串。
虽然繁琐,但正则表达式同时也是强大的,学会应用之后可以提高效率。许多程序设计语言都支持利用正则表达式进行字符串操作。
常用的正则表达式如表 2 所示。表 2 用户名 /^[a-z0-9_-]{3,16}/十六进制值 /^#?([a-f0-9]{6}|[a-f0-9]{3})//^[a-z\d]+(.[a-z\d]+)@(\da-z?)+(.{1,2}[a-z]+)+$/URL /^(https?://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-])/?/HTML 标签 /^<([a-z]+)([^<]+)(?:>(.)</\1>|\s+/>)$/删除代码\注释 (?<!http:|\S)//.Unicode编码中的汉字范围 /^[\u2E80-\u9FFF]+/
由于正则表达式比较晦涩,难以记忆,所以在更多的情况下进行爬虫时使用的是 xpath、css 选择器。在编写爬虫时,并无规定章法(习惯什么用什么,想用什么用什么,能用什么用什么)。
下面举两个数据提取的整合方式如下:
案例 1:由 xpath 提取该标签下的文本内容,通过正则提取价格的数字部分 ['99.00', '88.00', '80.00']
selector = response.css('ul.pager li.next a::attr(href)').extract()#通过 css 选取目标范围 selector.xpath('.//li/b/text()').re('\d+.\d+')
案例 2:#套路于上一个例子是一样的,通过字典的形式进行数据封装,正则数据过滤在封装数据时一同进行。selector = response.css('ul.pager li.next a::attr(href)').extract()#通过 css 选取目标范围 selector.xpath('.//li/b/text()').re('\d+.\d+')#由 xpath 提取该标签下的文本内容,通过正则提取价格的数字部分 ['99.00', '88.00', '80.00']#举例如下:def get_infos(html):html = etree.HTML(html)infos = response.css('ul.pager li.next a::attr(href)').extract()for info in infos:exp_name = info.xpath('./a/text()')[0]url_info = info.xpath('./a/@href')[0]time_day = info.xpath('./span[@class="y-right"]/text()')[0]data = {'漏洞名称': exp_name.replace('\n', '').replace(' ', '').re('\d+.\d+'),'漏洞地址': 'https://help.xxxx.com{}'.format(url_info),'日期': time_day.re('\d+.\d+'),#'时间': time,}print(data)print('\n')
JSON 数据提取
JSON 是一种轻量级的数据交换格式。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。在易于人阅读和编写的同时,JSON 也易于机器解析和生成,并能有效地提升网络传输效率。
一般在爬取动态页面时才会使用到 JSON 提取数据。
我们以https://www.cnbeta.com/为例,爬取页面的内容,如图 10、11 所示:
这是一个动态页面,动态页面通过 json 进行传输数据,所以我们对动态页面的爬取就是对动态页面的 js 的提取。该网站不仅对 referer 和 UA 进行了校验,同时还在页面中通过 JavaScript 语句进行动态链接请求,从而导致不能动态获取页面中的信息,所以只是展示一个 jsonpath 提取 json 数据的小栗子,代码示例如下。
#下面据一个提取 json 数据的小例子 Import jsonpathdef get_infos(html):html = json.loads(html)list_html = jsonpath.jsonpath(html,'..post_title')]title = str(title)title=title[3:-3]first_url=jsonpath.jsonpath(info,'..post_date')first_content=jsonpath.jsonpath(info,'$..content')data = {'安全讯息': title,'讯息地址': 'https://s.tencent.com{}'.format(first_url),'日期': time,'内容简介': first_content,}print(data)print('\n')
4IP 代理
大家可能都有过给浏览器设置 HTTP 代理的经验,HTTP 代理服务器可以比作客户端与 Web 服务器(网站)之间的一个信息中转站,客户端发送的 HTTP 请求和 Web 服务器返回的 HTTP 响应通过代理服务器转发给对方,如图 12 所示:
爬虫程序在爬取某些网站时也需要使用代理,常见原因可包括:• 由于网络环境因素,直接爬取速度太慢,使用代理可提高爬取速度。• 某些网站对用户的访问速度进行限制,爬取过快会被封禁 ip,使用代理的话可以防止被封禁。• 由于地方法律或政治原因,某些网站无法直接访问,使用代理则可以绕过访问限制。
通过 python 查看 IP 的代码如下所示:
import requestsheaders = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'}url = 'http://icanhazip.com/'response = requests.get(url,headers=headers)ip = response.text.replace('\n','')print(ip)想要更换 IP,就需要使用到大量的 IP。
首先付费版代理 IP 有如:• 芝麻代理http://www.zhimaruanjian.com• 阿布云:https://center.abuyun.com/login• 代理云http://www.dailiyun.com
免费版代理 IP 有如:• http://www.data5u.com/http://www.66ip.cn/• http://www.goubanjia.com/• http://www.66ip.cn/
编写爬虫爬取上面的 IP、端口信息的结果如图 13 所示:
IP 代理使用如下的代码示例如下:
import requests
代理服务器
proxyHost = "http-dyn.abuyun.com"proxyPort = "9020"
代理隧道验证信息
proxyUser = ''proxyPass = ''proxyMeta = "http://%(user)s:%(pass)s@%(host)s:%(port)s" % {"host": proxyHost,"port": proxyPort,"user": proxyUser,"pass": proxyPass,}#可以读取文件批量便利 proxies = {"http": proxyMeta,"https": proxyMeta,}headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'}url = 'http://icanhazip.com/'response = requests.get(url,headers=headers,proxies=proxies)ip = response.text.replace('\n','')print(“成功获取到代理”,ip)
上述代码也可以用来检测爬取到的代理能否正常使用。
5API 接口调用
API 中文名叫【编程应用接口】,换句话说,这是一种接口,在爬虫中也被广泛使用。
爬虫是通过访问其他网站,然后从中提取结构化的数据,进行抓包分析,正则,bs4 ,js 逆向等等,整体比较麻烦。相比之下,API 接口的调用就会方便得多。如果对方开放了 API 接口,则可以考虑使用接口,这可达到事半功倍的效果,因为对方如果有 API 接口,说明对方有对外开放数据,那我们获得数据也就方便,只需要请求接口,得到返回的 json 数据即可,不用担心反爬。
大家常听到的 API 类型,应该是【天气预报 API】,【百度地图 API】之类的,现在有很多 API 服务,我们可以根据需求寻找对应的。
若遇到了 Ajax 动态加载的情况怎么办?这和前面通过 json 提取动态页面是一样的。
可以看到调用 api 接口后,得到一个 json 数据,所以这里我们可以使用上文提到的 json 数据提取方法进行数据的提取。
6 法律法规
网络运营者采取自动化手段访问收集网站数据,不得妨碍网站正常运行;此类行为严重影响网站运行,如自动化访问收集流量超过网站日均流量三分之一,网站要求停止自动化访问收集时,应当停止。
以下是司法解释里面提到以下集中类型的数据,无论是“非法提供”和“非法获取”都可以入刑:
第一类:高度敏感信息,包括四种信息:行踪轨迹信息、通信内容、征信信息、财产信息。涉及高度敏感信息的违法活动,由于定罪门槛最低,因此严格限制在此四类,不做任何扩展;
第二类:敏感信息,即住宿信息、通信记录、健康生理信息、交易信息等其他可能影响人身、财产安全的公民个人信息。与第一类相比较,《解释》对第二类信息的界定仍留有空间,意味着在司法实践中,仍有可能会出现目前所列举之外的第二类信息类型;
第三类:其他个人信息。即上述第二、三类以外的个人信息。个人信息的类型是定罪量刑的重要依据。越敏感信息,达到定罪门槛的信息数量越少。
最后:点赞加关注楼主哦 私信我免费分享网络安全资料
版权声明: 本文为 InfoQ 作者【Thrash】的原创文章。
原文链接:【http://xie.infoq.cn/article/09d8434085da8f9afae3c1f20】。文章转载请联系作者。
评论