“网络爬虫”又称“网络蜘蛛”,是一种在互联网上自动采集数据的自动化程序。爬虫的规模可大可小,大到百度、谷歌搜索,小到文本采集、自动采集图片等。
下面介绍如何获取准备爬取内容的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所示。
出于降低编程难度以及代码重用等方面的考虑,通常将每个功能封装为一个个函数。
图4就是我们需要的HTML内容,我们将通过python的requests库对其进行获取。
通过requests库获取目标页面的HTML源码如下所示。考虑到代码比较容易理解,所以不在此处做过多说明。
import requests def 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.text else: return |
从上述的源码可以看出,我们可通过requests库的get函数直接获取到目标页面的HTML源码。
requests库的的其他常用方法如图5所示。
另外,在使用requests库时,我们还可以添加一些字段,如表1所示。
表1
params |
字典或字节序列,作为参数增加到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 requests from fake_useragent import UserAgent #生成随机UA url = '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) |
其他字段对于一般爬虫而言不一定有用,但笔者也将它们列举出来,希望可以为读者拓宽思路。
XPath
XPath即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"的标签 |
其中,网页http://example.com/elsie的内容如下。
<!DOCTYPE html> <body> |
输出结果如下。
[<a href="http://example.com/elsie" id="link1" title="12"><!-- Elsie --></a>] |
正则表达式是一种文本模式,包括普通字符和特殊字符。正则表达式使用单个字符串来描述、匹配一系列某个句法规则的字符串。
虽然繁琐,但正则表达式同时也是强大的,学会应用之后可以提高效率。许多程序设计语言都支持利用正则表达式进行字符串操作。
常用的正则表达式如表2所示。
表2
用户名 |
/^[a-z0-9_-]{3,16}$/ |
密码 |
/^[a-z0-9_-]{6,18}$/ |
十六进制值 |
/^#?([a-f0-9]{6}|[a-f0-9]{3})$/ |
电子邮箱 |
/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/ |
URL |
/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/ |
IP 地址 |
/((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/ |
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提取数据。
我们以https://www.cnbeta.com/为例,爬取页面的内容,如图10、11所示:
这是一个动态页面,动态页面通过json进行传输数据,所以我们对动态页面的爬取就是对动态页面的js的提取。该网站不仅对referer和UA进行了校验,同时还在页面中通过JavaScript语句进行动态链接请求,从而导致不能动态获取页面中的信息,所以只是展示一个jsonpath提取json数据的小栗子,代码示例如下。
#下面据一个提取json数据的小例子 Import jsonpath def get_infos(html): html = json.loads(html) list_html = jsonpath.jsonpath(html,'$..data_list') for infos in list_html: for info in infos: title=[jsonpath.jsonpath(info,'$..post_title')] title = str(title) title=title[3:-3] first_url=jsonpath.jsonpath(info,'$..url') first_url = str(first_url) first_url=first_url[2:-3] time=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') |
大家可能都有过给浏览器设置HTTP代理的经验,HTTP代理服务器可以比作客户端与Web服务器(网站)之间的一个信息中转站,客户端发送的HTTP请求和Web服务器返回的HTTP响应通过代理服务器转发给对方,如图12所示:
爬虫程序在爬取某些网站时也需要使用代理,常见原因可包括:
由于网络环境因素,直接爬取速度太慢,使用代理可提高爬取速度。
某些网站对用户的访问速度进行限制,爬取过快会被封禁 ip,使用代理的话可以防止被封禁。
由于地方法律或政治原因,某些网站无法直接访问,使用代理则可以绕过访问限制。
通过python查看IP的代码如下所示:
import requests 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) ip = response.text.replace('\n','') print(ip) |
想要更换IP,就需要使用到大量的IP。
首先付费版代理IP有如:
免费版代理IP有如:
编写爬虫爬取上面的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) |
上述代码也可以用来检测爬取到的代理能否正常使用。
API 中文名叫【编程应用接口】,换句话说,这是一种接口,在爬虫中也被广泛使用。
爬虫是通过访问其他网站,然后从中提取结构化的数据,进行抓包分析,正则,bs4 ,js 逆向等等,整体比较麻烦。相比之下,API接口的调用就会方便得多。如果对方开放了 API 接口,则可以考虑使用接口,这可达到事半功倍的效果,因为对方如果有 API接口,说明对方有对外开放数据,那我们获得数据也就方便,只需要请求接口,得到返回的 json 数据即可,不用担心反爬。
大家常听到的 API 类型,应该是【天气预报API】,【百度地图API】之类的,现在有很多 API 服务,我们可以根据需求寻找对应的。
若遇到了Ajax动态加载的情况怎么办?这和前面通过json提取动态页面是一样的。
可以看到调用api接口后,得到一个json数据,所以这里我们可以使用上文提到的json数据提取方法进行数据的提取。
网络运营者采取自动化手段访问收集网站数据,不得妨碍网站正常运行;此类行为严重影响网站运行,如自动化访问收集流量超过网站日均流量三分之一,网站要求停止自动化访问收集时,应当停止。
以下是司法解释里面提到以下集中类型的数据,无论是“非法提供”和“非法获取”都可以入刑:
第一类:高度敏感信息,包括四种信息:行踪轨迹信息、通信内容、征信信息、财产信息。涉及高度敏感信息的违法活动,由于定罪门槛最低,因此严格限制在此四类,不做任何扩展;
第二类:敏感信息,即住宿信息、通信记录、健康生理信息、交易信息等其他可能影响人身、财产安全的公民个人信息。与第一类相比较,《解释》对第二类信息的界定仍留有空间,意味着在司法实践中,仍有可能会出现目前所列举之外的第二类信息类型;
第三类:其他个人信息。即上述第二、三类以外的个人信息。个人信息的类型是定罪量刑的重要依据。越敏感信息,达到定罪门槛的信息数量越少。
本文作者:安全狗
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/157549.html