当前位置: 首页 > news >正文

爬虫反爬进阶——IP代理池、请求指纹、字体反爬实战

入门级反爬(User-Agent、IP 封禁、请求频率限制)好解决,但到了进阶阶段,会遇到更多花样。这篇讲三个最实用的反爬对抗技术。

一、IP 代理池——突破封 IP

爬得稍微快一点,网站就封 IP。解决方案是维护一个代理池,IP 被封了自动换。

1. 免费代理获取(思路)

importrequestsfrombs4importBeautifulSoupimporttimedeffetch_free_proxies():"""从免费代理网站采集代理IP(示例)"""proxies=[]url="https://www.free-proxy-list.com/"resp=requests.get(url,headers={"User-Agent":"Mozilla/5.0"})soup=BeautifulSoup(resp.text,"html.parser")forrowinsoup.select("table tr")[1:]:# 跳过表头cols=row.select("td")iflen(cols)>=2:ip=cols[0].text.strip()port=cols[1].text.strip()proxies.append(f"{ip}:{port}")returnproxies

需要注意的是:免费代理质量很差(90% 不可用,速度慢),小规模采集凑合用,大规模采集建议买付费代理。

2. 验证代理是否可用

importthreadingdefcheck_proxy(proxy):"""测试代理是否可用"""try:resp=requests.get("http://httpbin.org/ip",proxies={"http":proxy,"https":proxy},timeout=5)ifresp.status_code==200:print(f"✅{proxy}可用 -{resp.text.strip()}")returnTrueexcept:passreturnFalse# 多线程验证所有代理defvalidate_all(proxies):valid=[]threads=[]lock=threading.Lock()defcheck(p):ifcheck_proxy(p):withlock:valid.append(p)forpinproxies:t=threading.Thread(target=check,args=(p,))t.start()threads.append(t)fortinthreads:t.join()returnvalid

3. 代理池管理器

importrandomimporttimeimportrequestsclassProxyPool:"""简单的代理池管理器"""def__init__(self):self.proxies=[]self.blacklist=set()defadd_proxy(self,proxy):ifproxynotinself.blacklist:self.proxies.append(proxy)defget_proxy(self):"""随机返回一个代理"""ifnotself.proxies:returnNonereturnrandom.choice(self.proxies)defmark_bad(self,proxy):"""标记代理不可用"""ifproxyinself.proxies:self.proxies.remove(proxy)self.blacklist.add(proxy)print(f"💀 代理{proxy}已移除,剩余{len(self.proxies)}个")defrequest_with_retry(self,url,max_retries=5):"""带代理重试的请求"""foriinrange(max_retries):proxy=self.get_proxy()ifnotproxy:print("代理池已空,等待补充...")returnNonetry:resp=requests.get(url,proxies={"http":proxy,"https":proxy},timeout=10,headers={"User-Agent":"Mozilla/5.0"})ifresp.status_code==200:returnrespelse:self.mark_bad(proxy)except:self.mark_bad(proxy)time.sleep(0.5)print(f"重试{max_retries}次全部失败:{url}")returnNone

4. 付费代理推荐

免费代理不稳定,真干活建议买:

  • 快代理:国内最大的代理服务商,动态代理按量计费
  • 芝麻代理:价格便宜,几块钱能用一天
  • 站大爷:支持动态按需提取

一般几十块钱能用几个月,省心很多。

二、请求指纹——伪装浏览器特征

现在的反爬不仅看 IP 和 UA,还会检测TLS 指纹、Headers 顺序、WebDriver等。

1. 完整的请求头伪装

headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8","Accept-Encoding":"gzip, deflate, br","Connection":"keep-alive","Referer":"https://www.google.com/","Sec-Ch-Ua":'"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"',"Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":'"Windows"',"Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"none","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1",}

2. 随机切换

importrandomfromfake_useragentimportUserAgent ua=UserAgent()classRandomHeaders:"""随机生成请求头"""@staticmethoddefget_headers():user_agents=[ua.chrome,ua.edge,ua.firefox,]return{"User-Agent":random.choice(user_agents),"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language":random.choice(["zh-CN,zh;q=0.9,en;q=0.8","en-US,en;q=0.9,zh-CN;q=0.8","zh-CN,zh;q=0.9",]),"Referer":random.choice(["https://www.baidu.com/","https://www.google.com/","https://www.bing.com/",]),}

3. 使用 requests 会话重用

# 每次都新建会话,容易被识别# 正确的做法是复用 Sessionsession=requests.Session()session.headers.update(RandomHeaders.get_headers())# 连续请求,保持同一指纹resp1=session.get("https://example.com/page1")resp2=session.get("https://example.com/page2")

三、字体反爬——最常见的反爬手段

很多网站(大众点评、猫眼电影、58同城)用自定义字体来加密数字,你爬下来看到的是乱码。

原理

正常数字:0 1 2 3 4 5 6 7 8 9 加密后: ➀ ➁ ➂ ➃ ➄ ➅ ➆ ➇ ➈ ➉ 网页通过 @font-face 加载一个自定义字体文件(.woff 或 .ttf) 字体文件里把字符映射关系打乱了 所以浏览器能正确显示,但你爬到的文本是乱码

解决方案

fromfontTools.ttLibimportTTFontimportreimportrequestsdefparse_font_anti_spider(html_text,font_url):"""解析字体反爬"""# 1. 下载字体文件resp=requests.get(font_url)withopen("temp.woff","wb")asf:f.write(resp.content)# 2. 解析字体映射关系font=TTFont("temp.woff")cmap=font.getBestCmap()# 3. 建立映射关系# cmap 返回的是 {unicode编码: 字形名称}# 比如 {0xe001: 'one', 0xe002: 'two', ...}# 需要根据字形名称找到对应的数字unicode_to_digit={}num_map={"one":"1","two":"2","three":"3","four":"4","five":"5","six":"6","seven":"7","eight":"8","nine":"9","zero":"0",}forunicode_val,glyph_nameincmap.items():# 字形名称可能类似 "uniE001" 或 "one"glyph_name=glyph_name.lower()foreng,digitinnum_map.items():ifenginglyph_name:unicode_to_digit[chr(unicode_val)]=digit# 4. 替换加密字符forenc_char,digitinunicode_to_digit.items():html_text=html_text.replace(enc_char,digit)returnhtml_text

在线字体反爬(动态加载更麻烦)

很多网站已经升级到了动态字体——每次请求都生成新的字体文件,映射关系每次都不一样:

# 解决方案思路:# 1. 每次请求都下载最新的字体文件# 2. 通过字形轮廓计算来识别数字# 更简单的方法:用 OCR 识别# from PIL import Image# import pytesseract# 但准确率不如直接解析字体文件

四、Selenium 防检测

用 Selenium 时,网站可以通过window.navigator.webdriver检测到你是自动化工具。

1. 隐藏 WebDriver 特征

fromseleniumimportwebdriverfromselenium.webdriver.chrome.optionsimportOptions options=Options()options.add_argument("--disable-blink-features=AutomationControlled")options.add_experimental_option("excludeSwitches",["enable-automation"])options.add_experimental_option("useAutomationExtension",False)driver=webdriver.Chrome(options=options)# 注入 JS 修改 navigator 属性driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{"source":""" Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] }); Object.defineProperty(navigator, 'languages', { get: () => ['zh-CN', 'zh'] }); """})

2. 使用 undetected-chromedriver

有个专门的库解决了大部分检测问题:

pipinstallundetected-chromedriver
importundetected_chromedriverasuc driver=uc.Chrome()driver.get("https://example.com")# 自动隐藏了 WebDriver 特征,比手动配置稳定得多

五、实际工作流:如何选择反爬策略

反爬级别特征应对方法
⭐ 入门级封 IP、限频率加延时 + 轮换 UA
⭐⭐ 初级检测请求头、验证码Session 复用 + 代理池
⭐⭐⭐ 中级字体反爬、动态加载下载字体解析 + 抓接口
⭐⭐⭐⭐ 高级WebDriver 检测、风控系统undetected-chromedriver + 行为模拟
⭐⭐⭐⭐⭐ 顶级滑块验证、人机识别打码平台 + 行为轨迹模拟

核心原则:反爬对抗不是越强越好,够用就行。加 3 秒延迟 + 轮换 UA 能解决 80% 的问题,没必要一上来就上分布式代理池。


💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。

http://www.jsqmd.com/news/1083684/

相关文章:

  • 淮南装修公司排名大全
  • HarmonyOS7 网络卡顿别只会重试:QUIC、持久连接和预建链优化
  • Navicat重置教程:macOS上无限试用Navicat Premium的终极指南
  • VRPN:异构设备网络化集成的核心协议与实战指南
  • 【课程设计/毕业设计】基于 SpringBoot+Vue 的企业员工运维日志管理系统的设计与实现 基于 SpringBoot+Vue 的员工工作轨迹记录管理系统【附源码、数据库、万字文档】
  • Python 爬虫实战:北极星日淘日本本土商品数据同步采集(反爬+增量更新)
  • ArkUI 状态管理与页面交互核心:@State、弹窗与路由
  • 3分钟搞定!Soundflower虚拟音频驱动让Mac应用间音频流转如此简单
  • 基于CAMx的空气质量模拟及污染来源解析技术与案例分析
  • 2026年国内用户使用 ChatGPT Plus / Pro:为什么我更建议先考虑稳定,而不是只看价格?
  • 终极宝可梦随机化器:Universal Pokemon Randomizer ZX完全指南,5分钟打造你的专属冒险
  • 【供应链建设】伸缩延长杆源头工厂供应商的工程能力是建立供应链的关键
  • 靠谱AI营销的企业
  • ThinkAdmin路径遍历漏洞CVE-2020-25540深度剖析与防御实战
  • Qwerty Learner:如何通过打字练习重构你的英语肌肉记忆?
  • 如何快速掌握鼠标连点器:面向新手的完整自动化工具指南
  • Python 高性能并发:从 GIL 瓶颈到协程调度的工程突围
  • GitHub今日热榜 | 2026-06-25:Agent开发环境爆发,7个项目首次入榜
  • 鸿翼OpenContent™ AI智能多模态数据管理平台介绍与功能场景
  • TranslucentTB:Windows任务栏透明化终极指南,打造个性化桌面体验
  • MultiWFN安装配置全攻略:从源码编译到量子化学分析环境搭建
  • 聚氨酯封边岩棉夹芯板的优异性能与广泛应用分析
  • Spring Boot 集成 Tess4J 实现图片OCR文字识别
  • 5分钟快速上手《经济研究》LaTeX投稿模板:终极排版解决方案
  • 如何快速备份QQ空间:GetQzonehistory完整数据备份指南
  • 全栈开发别再瞎加班了!10 个 AI 神器 + 3 个实战项目,效率直接翻 3 倍
  • 【软工方法论28】代码评审最佳实践
  • 并发限制卡死你?用“动态分配“让空闲许可自动补位
  • 鸿蒙物理 108 篇 第四十一篇 三才气运互通机理
  • 仙人掌图非线性选择器一致性条件:图论与非线性霍奇理论的交叉探索