如何处理目标网站返回的验证码

谷德IP代理 2026-03-24 10:19:23

你肯定碰到过这种糟心事吧?半夜两点,你吭哧吭哧写了一段自认为完美的爬虫代码,信心满满点了运行。日志唰唰唰往上跳,结果突然卡壳了——状态码明明是200,返回的却不是你要的数据,而是一长串HTML,明晃晃写着“请输入验证码”。爬虫直接被关门外了,啥也干不了。


那感觉就跟你兴冲冲冲到自助餐厅,结果大门锁着,保安还堵在门口让你先做套数学题一样,憋屈得不行。


验证码说白了就一个目的:简单粗暴,就是不想让机器进去。

如何处理目标网站返回的验证码

验证码到底防的是谁?


验证码的核心就一件事——分清人和机器。人眼瞅着扭曲的字母、点选带红绿灯的图片,几秒就搞定,可对机器来说,这就是最难啃的骨头。


常见的验证码就三类:


字符型验证码是最老的那种,一串歪歪扭扭的字母数字,背景还画满干扰线。早年Google的reCAPTCHA就这德行,字符转个30度,颜色对比度压到40%以下,故意让人眼都费劲,更别说机器。


图形选择型验证码更折磨人——九宫格里让你选出所有带汽车的图。这得懂图像语义,光靠像素识别根本没用。


行为轨迹型验证码就是滑动拼图,得把缺口对上。它不光看结果对不对,还盯着你拖动的速度、轨迹,看是不是真人的操作习惯。


爬虫要是硬刚这些,基本没戏,得换个思路绕过去。


为啥代理IP是第一道关?


好多人都漏了关键问题:你的爬虫为啥会触发验证码?


大多时候,不是它认出你是爬虫,而是你访问太频繁了。同一个IP短时间刷几百次请求,服务器一眼就看出不对劲,不会直接封你,但会甩个验证码——人能手动填,机器过不去,直接卡死。


所以对付验证码,第一步是让它别弹出来。


代理IP就是干这个的。用一组IP轮换着发请求,每个IP的访问频率看着都正常,服务器就不会轻易把你当成爬虫。


代理池的逻辑特别简单:


import requests
import random


proxy_pool = [
    'http://111.222.111.222:8080',
    'http://111.222.111.223:8080',
    'http://111.222.111.224:8080',
]


proxy = {'http': random.choice(proxy_pool)}
response = requests.get('https://目标网站.com', proxies=proxy)


免费代理多但不稳定,付费的贵点却省心。你不用找最好的,只要有一批能用的,失效了能自动切换就行。


验证码真跳出来了,该怎么搞定?


要是代理IP没挡住,验证码还是弹了,那就得正面硬刚了。


OCR是最直接的法子,用Tesseract这类库把图片里的文字读出来。但直接识别基本白搭,验证码设计的时候就是专门针对OCR的。


得先给图片做预处理:


from PIL import Image
import pytesseract


image = Image.open('captcha.jpg')
gray = image.convert('L')  # 转灰度图
binary = gray.point(lambda x: 0 if x < 128 else 255, '1')  # 二值化
text = pytesseract.image_to_string(binary, config='--psm 7')


灰度化去掉颜色干扰,二值化变成纯黑白,有时候还得去噪、做边缘检测、分割字符。一套流程下来,识别率能从不到30%提到七八十。


但要是验证码太复杂——比如字符粘在一起、背景和字颜色差不多、干扰线密得像蜘蛛网,传统OCR就顶不住了。


这时候就得靠深度学习。用CNN卷积神经网络训个识别模型,让它见过成千上万张验证码,自己学会区分字符。CRNN架构还能处理变长字符,对付扭曲的字特别好用。


训模型成本不低,得收集数据、标注、调参数,但要是长期对付同一种验证码,这笔投入很值。


点选式验证码该咋破?


字符验证码还好说,图形点选的才是真麻烦。


你大概率碰到过:一张大图里有几个物体,让你按顺序点。OCR完全没用,因为根本没文字。


破这种验证码的思路就一个:把图片扔给人工打码平台,让人帮你点。听着不高级,但这是最实用的办法。


云打码的流程特别直白:

1. 截下验证码的图片

2. 上传到打码平台

3. 平台有人(或者高级AI)识别,返回点击坐标

4. 脚本拿到坐标,模拟点击


流程大概是这样:


触发验证码 → 截图 → 调用打码API → 解析返回坐标 → 逐个点击 → 提交验证


打码平台按次收费,一次几分到几毛不等,要是抓的数据量大,这笔钱省不了。


别忘装成真人,行为得像人


技术手段用得再溜,行为不像人,照样会被拦。


想想真人咋逛网页:浏览器五花八门,请求间隔忽长忽短,鼠标移动有轨迹,不是直上直下的。


你的爬虫要是总用同一个User-Agent,每次请求间隔精准0.5秒,还跳过所有图片和CSS,这不等于明着跟服务器说“我不是人”吗?


随机换User-Agent:


user_agents = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/91.0',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Firefox/89.0',
    # 再多加几十个
]
headers = {'User-Agent': random.choice(user_agents)}


请求间隔也随机化:


import time
import random
time.sleep(random.uniform(1, 3))  # 1到3秒随机停


条件允许的话,用Selenium或Playwright这类浏览器自动化工具,让脚本真的打开浏览器操作。虽然慢一点,但行为特征跟真人几乎没差别。


嫌麻烦?直接把验证码问题外包出去

最后说个偷懒的招。要是你不想自己折腾OCR、训模型、维护代理池,直接用现成的数据采集服务就行。有些平台把代理IP池、验证码识别、浏览器解锁全封装好了,你只需要丢个URL,它们直接返回处理好的数据。本质就是把爬虫里最麻烦的部分外包出去,省下来的时间去做数据分析——这才是真正有价值的事。


回到凌晨两点那个场景


半夜两点,你的爬虫又被验证码拦住了。现在你知道该咋做了:先查是不是IP被盯上了,是的话加代理池轮换。要是验证码还跳,看类型——字符型就做OCR预处理,复杂的就上深度学习或打码平台。同时记得拉长请求间隔,打散User-Agent,尽量装成真人。


验证码就是人机博弈,服务器要拦机器,你要让爬虫装成人。这场博弈没尽头,技术在升级,防御也在升级。但只要你的爬虫看起来够像普通人——不太快、不太准、不那么规律,大多时候,门都会为你打开。