请求头,也就是在发起HTTP请求时,网站服务器会通过请求头不同的参数来返回不同的数据。如果在请求的过程中被网站识别为是爬虫,很有可能被封。所以为了告诉网站:我是正常用户,不要封我!就必须伪装请求头。然而,在不伪装请求头的情况下,请求参数是什么呢?通过以下属性可以获得:
例7-10 伪装请求头
url = 'https://xa.nuomi.com/364'
html = requests.get(url)
html.encoding = html.apparent_encoding
for key, value in html.request.headers.items():
print(key, ':', value)
运行结果为:
图7-19
html.requests.headers存储了爬虫发起请求时,请求头中包含的参数。常见的参数是
表7-7 常见HTTP请求头参数
可以看到,User-Agent中显示的浏览器类型是'python-requests/2.18.4'。在不设置请求头的情况下,requests库会默认把请求头设置为“库名+库的版本号”(这简直就是在拿着话筒对网站说:我是爬虫,求封!)。那么,如何修改这个请求头呢?还是调起开发者工具,点击Network,选中Doc标签。点击左下方出现的列表中的任何一个即可(如果没有显示,则按F5刷新),Headers滚动到最下方,复制User-Agent和Cookie的即可。
图7-20
例7-11
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36',
'Cookie': "输入你的Cookie",
}
url = 'https://xa.nuomi.com/364'
html = requests.get(url, headers=headers)
html.encoding = html.apparent_encoding
for key, value in html.request.headers.items():
print(key, ':', value)
运行结果如下图
图7-21
可以看到,我们的请求头已经变成了正常用户的请求参数。这么做,已经能够解除大部分网站的封锁了。如果不放心,还可以构造其他参数,如Referer、Accept、Connection等,只要在开发者工具面板中能看到的参数,都可以放进去(但是一般网站不会对这些参数进行验证,有些网站甚至会对加了某些参数的访问进行限制)。
7.3.2 进阶 —— IP池正常情况下,不同用户的访问IP是不一样的。那么,通过IP自然能识别出访问的用户是否相同。如果同一IP(同一用户)在短时间内异常频繁访问,速度快到正常用户不可能达到的次数(比如1秒钟上百次),那么必然可以认为是爬虫在访问了。
应对方法是,构建代理IP池把HTTP请求通过这些代理IP进行转发。这么操作后,在网站服务器显示的访问IP就不是爬虫发起的IP了,而是代理IP的地址。网上有很多免费的代理IP,但是这些IP往往不是匿名的,也就是说,网站仍然能够“看到”爬虫的IP,这些IP其实是没有效果的。但是,为了便于演示,我们随机挑选一些IP代理用于教学(IP代理的存活期一般只有几分钟,因此在读者拿到这本书时,代理IP必然已经失效,请自行查找)。真实使用中,读者可以自行搜索“代理IP池”进行选择。
例7-12 代理IP
import random
# 1. 构建IP池
proxies = []
ips = ['123.170.255.128', '115.28.209.249']
ports = ['808', '3128']
for ip, port in zip(ips, ports):
proxies.append(
{'http': 'http://%s:%s' % (ip, port)}
)
# 2. 构建请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36',
'Cookie': "输入你的Cookie",
}
# 3. 发起HTTP请求
url = 'https://xa.nuomi.com/364'
html = requests.get(url, headers=headers, proxies=random.choice(proxies))
html.encoding = html.apparent_encoding
# 4. 解析网页
soup = BeautifulSoup(html.text, 'lxml')
cate_rows = soup.select('div.filter-wrapper > div:nth-of-type(1) > div > div > div > a')
cate_nums = {}
for row in cate_rows:
name = row.get_text()
ele = row.get('mon').split('=')[1].split('&')[0]
href = 'http://xa.nuomi.com/' + ele
cate_nums[name] = hrefprint(name, href)
最终运行结果如下图
图7-22
成功得到了解析的数据,这说明IP池是有效的。
注意:
1. 代理池的构建方式一定要使用字典{'http': IP+Port},或者{'https': IP+Port}的方式,否则会
报错:str object has no attribute 'get'
图7-23
2. 由于代理池经常会失效,因此需要设置timeout以及try....except句柄用于处理HTTP请求出错的情况。
例7-13
url = 'https://xa.nuomi.com/364'
try:
html = requests.get(url, headers=headers, proxies=random.choice(proxies), timeout=0.1)
html.encoding = html.apparent_encoding
except requests.ConnectTimeout or requests.ConnectionError:
print('请求超时')
图7-24
注意,这里为说明问题,timeout设置了0.1秒,实际使用中,一般设置3-5秒即可。
7.3.3 其他其他爬虫伪装方法,还包括宽带断网重连(路由IP一般是动态的,每次连接都不一样),selenium模拟浏览器等方法。目的都是一样的——千方百计让爬虫产生和正常用户一样的数据。这些方法不再详细描述,学有余力的读者可自行学习。
好了,今天就讲到这里。
▼往期精彩回顾▼初步搭建数据科学工作环境Conda的使用
Spyder入门
Jupyter入门
Markdown
简单读写数据
数据类型
数据结构
控制流
函数与模块
Numpy
pandas1
pandas2
pandas3
pandas4
绘图模块1
绘图模块2
绘图模块3
绘图模块4
统计建模1
统计建模2
统计建模3
统计建模4
机器学习模块1
机器学习模块2
文本分析1
文本分析2
下载本系列相关数据