爬虫(12) - 反爬虫(1) | 详解
反爬虫
反爬虫:限制爬虫程序访问服务器资源和获取数据的行为
限制手段
请求限制、拒绝响应、客户端身份验证、文本混淆和使用动态渲染技术等
反爬虫的分类
- 身份识别反爬虫:验证请求头信息、验证请求参数、使用验证码等
- 爬虫行为反爬虫:对ip进行限制、使用蜜罐获取ip、假数据等
- 数据加密反爬虫:自定义字体、数据图片、编码格式等
爬虫与反爬虫-攻与防
爬虫 | 反爬虫 |
代码向目标网站发起网络请求,爬取网站数据 | 监控异常流量,请求并非来自浏览器,直接拒绝 |
模拟浏览器UA,欺骗目标网站 | 监控到大量请求均来自同一个浏览器标识,限制访问频率 |
使用随机IP或分布式对目标网站发送请求 | 在一些入口或者表单处增加验证码,区别正常用户和爬虫 |
简单的验证码可以识别,复杂的验证码则通过接入打码平台,继续对目标网站发起请求 | 查看网站信息时,要求登录后才可以查看 |
注册多个账号 | 通过混淆规则对网站的信息进行混淆,增加爬虫抓取难度 |
当解密成本较高时,采用屏幕截图的方式获取数据 | 根据自动化测试框架或浏览器的特征区别用户和爬虫 |
成本太高,有可能放弃爬取 | 成本太高,无法完全限制爬取 |
身份识别反爬虫
基于身份识别反爬和解决思路
headers反爬-通过User-agent字段
正常访问网站,请求会携带User-agent标识访问网站的浏览器等相关信息。通过Request等方式请求网站,不会携带User-agent,只会有Request版本等相关信息。因此一些网站通过请求的User-agent判定请求是否是正常访问的请求
解决思路:携带正确的User-agent和使用随机的User-agent
headers反爬-通过cookie字段
网站通过请求是否携带cookie用户身份标识判定请求是否为爬虫请求
解决思路:注册多个账号请求登陆后数据或破解JS生成cookie逻辑;使用Selenium模拟用户UI操作
headers反爬-通过Referer字段
通过Referer跳转判定用户操作是否为爬虫行为;即你访问的域名是要通过重定向跳转到另外一个链接才能访问到真正的网站,如果你是直接访问Referer的地址,而不是通过跳转访问目标网站的,像这类型行为就可以判定为爬虫行为
解决思路:请求头中添加伪造Refer字段
基于请求参数反爬
- 一些网站会通过请求参数设置一定的关联逻辑关系。当不清楚逻辑关系,一味只知道传参,那这类型的请求就会被判定为爬虫行为
- 解决思路:仔细分析抓到的包,搞清楚请求之间的联系
验证码反爬
- 通过验证码增加爬虫难度
- 解决思路:通过图像识别工具,例如Pytesseract来破解简单的验证码;比较复杂的验证码,我们需要通过专业的商业打码平台进行破解。
- 这个是重点,下面将重点阐述记录
验证码处理和识别
验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试,实际上用验证码是现在很多网站通行的方式,我们利用比较简易的方式实现了这个功能。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类。
常见验证码分类 | |||
验证码作用:防止恶意破解密码、刷票、论坛灌水、刷网页、识别人类/机器人等 | |||
类型 | 示例 | 场景 | 处理方案 |
英文数字 | ![]() |
注册 登录 频繁发送请求 ........ ...... .... |
手动输入 图像识别引擎 打码平台 |
中文汉字 | ![]() |
||
坐标型 | ![]() |
||
问答型 | ![]() |
||
行为识别型 | ![]() |
||
图片识别型 | ![]() |
图片识别引擎
OCR(Optical Character Recognition)是指使用扫描仪或数码相机对文本资料进行扫描成图像文件,然后对图像文件进行分析处理,自动识别获取文字信息及版面信息的软件。
Tesseract,一款由HP实验室开发由Google维护的开源OCR引擎,特点是开源,免费,支持多语言,多平台。
step-1:下载
官网下载:https://digi.bib.uni-mannheim.de/tesseract/,下载最新版本,点击下一步安装即可,记录安装路径
step-2:安装PIL和pytesseract
调用图片识别引擎,需要安装PIL和pytesseract
pip install pillow #一个python的图像处理库,pytesseract依赖 pip install pytesseract
step-3:调用调试
1 #导入pillow 和pytesseract 2 from PIL import Image 3 import pytesseract 4 5 #打开图片 6 ima=Image.open("test1.png") 7 #查看图片 8 # ima.show() 9 10 #调用引擎进行识别,传入我们安装Tesseract的路径 11 pytesseract.pytesseract.tesseract_cmd=r"D:\Tesseract-OCR\tesseract.exe" 12 test=pytesseract.image_to_string("test1.png") 13 print(test)
打码平台
超级鹰:https://www.chaojiying.com/
step-1:注册账号
注册账号,微信公共号绑定账号,免费白嫖1000积分
step-2:生成软件ID
生成软件ID,名称随便取,记录下你生成的软件ID,等会调用方法,传参要用
step-3:下载开发文档
下载开发文档,等会调试接口用,看该平台能否成功解析验证码
step-4:调试
修改开发文档,Demo刚下载下来后,会报错,在print加上括号即可
Chaojiying_Client 传入用户名、密码以及你生成的软件ID; chaojiying.PostPic 根据价格体系中对验证码类型的定义,传入验证码类型ID
运行chaojiying.py文件,解析成功
点选式验证码
前置说明:通过http://121.41.201.214:8083/#/useOnline/pointFixed网站进行实战练习
目录说明:
- chaojiying.py:官方文档,依据自身账号进行修改
- handle_click_choic_captcha.py:入口执行文件,访问网站,调用打码平台接口,针对返回数据,进行页面验证码点选式操作
- setting.py:存放打码平台超级鹰的用户名、密码、软件ID
code:
chaojiying.py
1 import requests 2 from hashlib import md5 3 from setting import username, password, soft_id 4 5 6 class Chaojiying_Client(object): 7 8 def __init__(self, username, password, soft_id): 9 self.username = username 10 password = password.encode('utf8') 11 self.password = md5(password).hexdigest() 12 self.soft_id = soft_id 13 self.base_params = { 14 'user': self.username, 15 'pass2': self.password, 16 'softid': self.soft_id, 17 } 18 self.headers = { 19 'Connection': 'Keep-Alive', 20 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', 21 } 22 23 def PostPic(self, im, codetype): 24 """ 25 im: 图片字节 26 codetype: 题目类型 参考 http://www.chaojiying.com/price.html 27 """ 28 params = { 29 'codetype': codetype, 30 } 31 params.update(self.base_params) 32 files = {'userfile': ('ccc.jpg', im)} 33 r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, 34 headers=self.headers) 35 return r.json() 36 37 def ReportError(self, im_id): 38 """ 39 im_id:报错题目的图片ID 40 """ 41 params = { 42 'id': im_id, 43 } 44 params.update(self.base_params) 45 r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers) 46 return r.json()
setting.py
1 username = "超级鹰账号" 2 password = "超级鹰密码" 3 soft_id = "超级鹰生成的软件ID"
handle_click_choice_captcha.py
1 # http://121.41.201.214:8083/#/useOnline/pointFixed 2 # 打开目标网站 3 # 截取全屏图片 4 # 获取验证码的区域,获取验证码的控件 5 # 截取验证码的图片 6 # 将验证码的图片发送给超级鹰 7 # 根据超级鹰返回的文字的坐标执行点 击操作 8 from selenium import webdriver 9 from selenium.webdriver.common.by import By 10 from selenium.webdriver.support.ui import WebDriverWait 11 from selenium.webdriver.support import expected_conditions as EC 12 import time 13 from PIL import Image 14 from chaojiying import Chaojiying_Client 15 from setting import username,password,soft_id 16 from selenium.webdriver import ActionChains 17 18 class click_choice_captcha(object): 19 def __init__(self): 20 self.driver=webdriver.Chrome() 21 self.driver.maximize_window() 22 def handle_captcha(self): 23 try: 24 self.driver.get("http://121.41.201.214:8083/#/useOnline/pointFixed") 25 if WebDriverWait(self.driver,5,0.5).until(EC.presence_of_element_located((By.CLASS_NAME,"verify-img-panel"))): 26 time.sleep(2) 27 captcha_element=self.save_img() 28 if captcha_element: 29 nodes=self.handle_chaojiying() 30 if nodes: 31 print("验证码识别成功,开始点击验证码") 32 for i in nodes.split("|"): 33 print(i) 34 ActionChains(self.driver).move_to_element_with_offset(captcha_element,\ 35 int(i.split(",")[0]),int(i.split(",")[1])).click().perform() 36 time.sleep(1) 37 except Exception as e: 38 print("验证码识别失败") 39 self.driver.quit() 40 else: 41 time.sleep(2) 42 self.driver.quit() 43 44 self.driver.quit() 45 def handle_chaojiying(self): 46 """识别验证码""" 47 chaojiying=Chaojiying_Client(username,password,soft_id) 48 with open("captcha.png","rb") as f: 49 img=f.read() 50 return_data=chaojiying.PostPic(img,9103) 51 print("超级鹰返回的验证码数据为{}".format(return_data)) 52 return return_data.get("pic_str") 53 def save_img(self): 54 """截取图片,保存图片""" 55 try: 56 # 截取全屏图片 57 self.driver.save_screenshot("browser.png") 58 # 找到验证码的控件 59 captcha_element=self.driver.find_element(by=By.XPATH,value="//div/img") 60 # 获取到验证码左上角的坐标 61 location=captcha_element.location 62 # 获取验证码的大小,宽和高 63 size=captcha_element.size 64 # print(location,size) 65 # 整张验证码的大小,尺寸 66 rangle=(location.get("x"),location.get("y"),location.get("x")+size.get("width"),\ 67 location.get("y")+size.get("height")+50) 68 # 打开全屏图片 69 img=Image.open("browser.png") 70 # 通过前面定义的验证码的大小绘制整个验证码的区域 71 captcha=img.crop(rangle) 72 captcha.save("captcha.png") 73 except Exception as e: 74 return False 75 else: 76 # 便于后期获取到验证码坐标之后进行点击操作 77 return captcha_element 78 79 if __name__=="__main__": 80 c=click_choice_captcha() 81 c.handle_captcha()
执行结果
滑动验证码
前置说明:
链接:https://pan.baidu.com/s/16K8LX5qF4JjXL0EI2OwbzQ?pwd=xzm2
提取码:xzm2
下载示例项目sliding_captcha,该项目利用flask创建本地一个站点,这个站点的内容就是一个滑动模块;
运行server.py文件,访问控制台输出站点URL,即可访问滑动模块;如果运行sercer.py文件报错,需要安装下flask
pip install flask
code:
在 handle_sliding_captcha.py 文件中编写你的滑动验证码逻辑;大概思路就是:截取完整验证码图片和带有缺口验证码图片,两张图片进行对比得出差异角标,拖动滑块,完成验证
1 # 找到下面的滑块 2 # 找到验证码的控件 3 # 截取一张完整的验证码图片 4 # 点击下面的滑块,图片上显示缺口 5 # 隐藏缺口图片 6 # 截取一张带有缺口的验证码图片 7 # 对比两张图片的不同,不同出会返回数值,即为缺口的坐标 8 # 执行滑动操作,对上滑块 9 10 from selenium import webdriver 11 from selenium.webdriver.common.by import By 12 import time 13 from selenium.webdriver import ActionChains 14 from PIL import Image,ImageChops 15 16 # 关注浏览器的版本和driver版本适配 17 driver=webdriver.Chrome() 18 driver.maximize_window() 19 driver.get("http://127.0.0.1:5000") 20 time.sleep(3) 21 # 找到下面的滑块 22 sliding_element=driver.find_element(by=By.ID,value="jigsawCircle") 23 # 找到验证码图片的控件 24 captcha_element=driver.find_element(by=By.ID,value="jigsawCanvas") 25 # 截取一张完整的验证码的图片 26 captcha_element.screenshot("before.png") 27 # 按一下下面的滑块 28 action=ActionChains(driver) 29 # 点一下,持续鼠标左键不放开 30 action.click_and_hold(sliding_element).perform() 31 # 出现了缺口和缺口图片,在验证码上 32 # 隐藏缺口图片 33 script='document.getElementById("missblock").style["visibility"]="hidden";' 34 # 通过driver执行JS代码 35 driver.execute_script(script) 36 captcha_element.screenshot("after.png") 37 image_before=Image.open("before.png").convert("RGB") 38 image_after=Image.open("after.png").convert("RGB") 39 # 执行对比操作,使用getbbox来返回不同点的坐标 40 diff=ImageChops.difference(image_before,image_after).getbbox() 41 print(diff) 42 # 将缺口图片显示 43 script='document.getElementById("missblock").style["visibility"]="visible";' 44 # 通过driver执行JS代码 45 driver.execute_script(script) 46 # 执行滑动操作,执行直线操作 47 action.move_by_offset(diff[0]-10,0) 48 action.release().perform() 49 time.sleep(5) 50 driver.quit()
执行结果
运行 handle_sliding_captcha.py 文件,验证码验证成功,控制台成功输出
爬虫行为反爬虫
- 通过请求ip/账号单位时间内请求频率、次数反爬
- 使用ip代理、多个账号反反爬
- 通过同一ip/账号请求间隔进行反爬
- 使用ip代理,设置随机休眠进行反反爬
- 通过js实现跳转反爬
- 多次抓包,分析规律
- 通过蜜罐(陷阱)捕获ip
- 完成爬虫之后,测试爬取/仔细分析相应内容,找出陷阱
- 通过假数据进行反爬
- 长期运行,对比数据库中数据同实际页面数据
- 阻塞任务队列
- 分析获取垃圾url规律,对url进行过滤
- 阻塞网络IO
- 审查抓取连接,对请求时间计时
数据加密反爬虫
- 通过自定义字体反爬
- 切换到手机版/解析自定义字体
- 通过js动态生成数据进行反爬
- 分析js生成数据的流程,模拟生成数据
- 通过数据图片化进行反爬
- 通过使用图片引擎,解析图片数据
- 通过编码格式进行反爬
- 测试不同格式解码,获取正确的解码格式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)