道高一尺,魔高一丈。互联网上的爬虫、反爬与反反爬之间的博弈堪称互联网中的壮举。
本文记录集中常见的反爬机制,与响应的反反爬策略,仅供学习交流使用。万不可用来做违法乱纪的勾当。
那我们就开始吧。
robots 协议,防君子不防小人的反爬机制
- robots 协议:
- 是一个纯文本的协议,协议中规定了该网站中哪些数据可以被哪些爬虫爬取,哪些不可以被爬取
- 一般在网站的门户页面后面加上
/robots.txt
即可查看该网站的 robots 协议
- 破解:
UA 检测和 UA 伪装
UA 检测:网站后台会检测请求对应的 User-Agent,以判定当前请求是否为异常请求。
UA 检测对应的反反爬策略是 UA 伪装:我们使用一个浏览器的 User-Agent,而不是爬虫的,去访问网页。
伪装流程:
- 使用抓包工具捕获到某一个基于浏览器请求的 User-Agent 的值,将其伪装作用到一个字典中,将该字典作用到请求方法(get,post)的 headers 参数中即可。
- 因为 UA 检测机制很多网站都会有,所以一般我们写爬虫代码的时候,都会加上 User-Agent 请求头,有备无患
使用代码表示就是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| keyword = input('enter a keyword:') headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36' } params = { 'query':keyword } url = 'https://www.sogou.com/web'
response = requests.get(url=url, params=params, headers=headers) response.encoding = 'utf-8' page_text = response.text fileName = keyWord + '.html' with open(fileName, 'w', encoding='utf-8') as fp: fp.write(page_text) print(fileName, '爬取完毕!!!')
|
页面动态加载
有时候,直接通过 get 请求到的网址并不包含我们想要的数据。数据是通过 ajax 等方法,异步请求得到的。这时候,如果我们直接使用聚焦爬虫,分析一整个页面的内容,是无法获取到数据信息的。
应付页面动态加载的方式也很简单,因为数据一定是通过请求获得的,所以只要我们捕获到浏览器向后端请求数据所用的各种参数,就可以得到我们需要的数据。
比如豆瓣电影的页面就是动态加载的,数据通过 ajax 请求获得。要爬取豆瓣电影的信息,只需要用浏览器的抓包工具,找到这个请求,然后把需要的参数都带上,即可实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=0&limit=20' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36' }
data = { 'type': '5', 'interval_id': '100:90', 'action': '', 'start': '0', 'limit': '20', } response = requests.get(url=url, headers=headers, data=data)
data_list = response.json()
for movie in data_list: title = movie['title'] score = movie['score'] print(title, score)
|
图片懒加载
图片懒加载常见于一些图片比较多的网站。懒加载的目的不单单是为了反爬,它可以减少用户打开网页所需要的时间,提高用户体验。不过这也确实给我们爬虫造成一些困扰。
图片懒加载的解决的解决要灵活处理,根据网页实现懒加载方式的不同,会有不同的处理方式。
比如站长素材的缩略图,通过将 img 标签的 src 属性先命名为 src2。等图片出现到浏览器视野中的时候,src2 会被更名回 src,从而实现图片的懒加载。
但是对于 requests 请求来说,并不会有图片出现在浏览器视野中,所以图片的 src 属性全都为 src2。此时如果还用 src 属性查找图片链接,是找不到的,应该使用 src 2 来查找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import os import requests from lxml import etree headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36' } img_dir = 'ZhanzhangGirls' if not os.path.exists(img_dir): os.mkdir(img_dir) url = 'http://sc.chinaz.com/tag_tupian/YaZhouMeiNv.html' response = requests.get(url=url, headers=headers) response.encoding = 'utf-8' data_text = response.text tree = etree.HTML(data_text) img_list = tree.xpath('//div[@id="container"]//img') for img in img_list: title = os.path.join(img_dir, img.xpath('./@alt')[0] + '.jpg') img_url = img.xpath('./@src2')[0][:-6] + '.jpg' img_data = requests.get(url=img_url, headers=headers).content with open(title, 'wb') as fp: fp.write(img_data) print(title, '下载完成!')
|