反反爬大全
📋导航
一. 反爬虫措施
-
基于
验证码
的反爬虫:现在大部分的网站都会有验证码,有传统验证码、逻辑验证码,还有滑动验证码等 -
基于
Headers
的反爬虫:大部分网站会对Headers中的User-Agent和Referer字段进行检测,例如检测ua的访问次数,如果达到一定数量进行反爬,不返回数据。突破办法是可以根据浏览器正常访问的请求头对爬虫的请求头进行修改,尽可能和浏览器保持一致;或者使用UA池。 -
基于
用户行为
的反爬虫:突破方法可以是使用代理ip池、cookie池、将访问网页的时间间隔设置为随机。 -
同一个IP短时间内多次访问同一页面会被检测到,可以使用大量的IP代理进行绕过
-
访问页面的间隔比较固定,表现得不像人在访问,可以将访问间隔设置成随机的,尽可能模拟人的访问频率
-
同一账户短时间内多次进行相同操作,可以注册较多的账户登录,构成一个Cookie池对用户状态进行自动切换
-
页面存在的数据量和爬虫获取的数据量不一致,例如一个页面只有60条数据,但是通过爬虫获取到了61条数据,多出来的那一条数据就是反爬措施,需要检验数量。
-
基于
动态页面
的反爬虫:突破方法是selenium+phantomJS。现在越来越多的网站采用动态加载技术,无法直接从页面上获取数据,需要分析Ajax请求,然后进行模拟发送获取数据。如果能够直接模拟Ajax请求,这当然是最好的结果,但是有些网站把Ajax请求的所有参数全部加密了,无法构造自己所需要的数据的请求,这就大大增加了爬取的难度。如果能忍受较低的效率和较大的内存消耗,我们可以使用selenium+phantomJS进行突破。或者找到数据所在的API接口。 -
基于
js加密
的反爬虫:用户通过浏览器获取数据的时候,是不断向服务器发送请求的,返回给用户一个个响应,html、js、css、jpg这些构成了整个网页。在发送请求的时候,js文件中会有一些逻辑代码,逻辑代码会将正常的数据加密,再次向浏览器发送请求,服务端收到密文之后会去校验密文符不符合要求,如果密文错误或者没有携带密文,则不会给客户端返回数据。
二. 反反爬措施
1. 代理IP池与代理IP池
如何获取更多的代理ip?
- vpn。厂商有提供vpn服务,可以分配不同的网络线路,并可以自动更换ip,实时性很高,速度很快。稳定可靠的vpn价格不低,适合商用。
- ip代理池。厂商将很多ip做成代理池,提供api接口,允许用户使用程序调用。稳定的ip代理池价格也是很贵的,不适合个人学习使用。
- ADSL宽带拨号。拨号上网的特点是断开再重新连接时分配的ip会变化,爬虫可以利用这个原理更换ip,但是由于更换ip需要断开再重新连接,效率不高,适合实时性不高的场景。有些提供宽带拨号的服务商提供的是专门的VPS拨号主机,例如无极网络,价格不是很贵,也相对比较稳定,ip基本上是秒切换。
1.1 代理ip
"http": "http://ip地址:端口号"
或者"https": "http://ip地址:端口号"
- 构造代理ip字典,第一个http/https和网址有关系,第二个http和ip地址有关
- 如果代理ip需要使用身份认证,则使用
"http://user:password@ip地址:端口号"
import requests
proxies = {"https": "http://ip地址:端口号"}
response = requests.get(url, proxies=proxies) # 使用proxies关键字参数携带
如果需要使用socks协议代理:需要安装,pip install "requests[socks]"
import requests
proxies = {
"http": "socks5://user:password@host:port" ,
"https": "socks5://user:password@host:port"
}
response = requests.get(url, proxies=proxies)
1.2 代理ip池
import requests
import random
from bs4 import BeautifulSoup
def get_douban_books(url, proxies):
headers = { 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36' }
res = requests.get(url, proxies=proxies, headers=headers)
soup = BeautifulSoup(res.text, 'html.parser')
items = soup.find_all('div', class_='pl2')
for i in items:
tag = i.find('a')
name = tag['title']
link = tag['href']
print(name, link)
url = 'https://book.douban.com/top250?start={}'
urls = [url.format(num * 25) for num in range(10)]
# IP 代理池
proxies_list = [
{ "http": "http://10.10.1.10:3128", "https": "http://10.10.1.10:1080", },
{ "http": "http://10.10.1.11:3128", "https": "http://10.10.1.11:1080", },
{ "http": "http://10.10.1.12:3128", "https": "http://10.10.1.12:1080", }
]
for i in urls: # 从 IP 代理池中随机选择一个
proxies = random.choice(proxies_list)
get_douban_books(i, proxies)
2.2 字体反爬
字体反爬是一种常见的网站反爬虫技术,它通过将文本内容使用自定义的字体来呈现,通过在线加载来引用样式,在浏览器上正常显示,但是爬虫无法直接读取到明文内容,抓取下来的数据要么是乱码,要么就变成其他字符。
解决方法:网站定义了字体文件,找到字体文件后,通过解析字体文件获取对应的字符映射关系(也就是进行相应的查找替换)。(可以使用FontCreator软件打开字体文件)
- 字体反爬网站【练习】:猫眼电影、大众点评、58同城、汽车之家、天眼查、起点中文网、实习僧
- 起点中文网字体反爬【案例】:http://t.csdn.cn/UQwav
2.3 ua池
2.3.1 手动构造user_agent池
使用random模块随机使用ua;在多次发送请求时循环取出容器里的ua
import random
import requests
ua_pool = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.5005.63 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.5005.63 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.5005.63 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.5005.63 Safari/537.36"
]
# 手动构造ua信息,存放在列表中,复制user_agent后,修改一下参数,例如修改浏览器的版本号,后放到列表中
# 方法一
ua = random.choice(ua_pool) # random.choice(可迭代对象),随机生成可迭代对象中的一个值
print(ua)
headers = { "user_agent": ua }
print(headers)
# 方法二
num = random.randint(0, 4) # 随机生成0-5之间的整数,作为ua_pool列表中的索引值
print(num)
headers = { "user_agent": ua_pool[num] }
print(headers)
# 方法三
for ua in ua_pool:
headers = { "user_agent": ua }
print(headers)
response = requests.get(url=....)
2.3.2 使用模块自动生成ua(推荐)
FakeUserAgent().random
:返回不同操作系统或不同浏览器版本的uaFakeUserAgent().Chrome
:只生成谷歌浏览器的ua
from fake_useragent import FakeUserAgent # 通过FakeUserAgent类里面的random方法随机生成
user_agent ua = FakeUserAgent().random # 这里的random和内置的random模块不是同一个方法
print(ua)
headers = { "user_agent": ua }
print(headers)
3. 验证码
3.1 滑动验证码
如果遇到验证码的情况,也可以采取多账号登录后,保存cookie信息,组建cookie池绕过
突破的技术要点:
- 模拟点击验证按钮
- 识别滑动缺口的位置(计算图片中缺口的偏移量)
首先要获取不带缺口的图片,利用Selenium选取图片元素,得到其所在位置和宽高,随后获取整个网页的截图,再从截图中裁切出来即可。其次要获取带缺口的图片,要使得图片出现缺口,我们只需要点击一下滑块即可,触发这个动作之后,图片中的缺口就会显现。接下来对比图片获取缺口,遍历图片的每个坐标点,获取两张图片对应像素点的 RGB 数据,后判断二者的 RGB 数据差异,如果差距超过在一定范围内,那就代表两个像素相同,继续比对下一个像素点,如果差距超过一定范围,则判断像素点不同,当前位置即为缺口位置。 - 模拟拖动滑块
3.2 传统验证码
传统验证码也就是传统的输入型验证码,包括数字、字母、汉字
突破的技术要点:
- selenium截图保存到本地
- 使用tesseract识别。cmd -> tesseract 图片路径 输出文件路径,例如:tesseract test.jpg res -l eng,会生成res.txt文本