我是怎么用 Python 自动绕过四种主流验证码的(字符、滑块和文字点按)

张开发
2026/4/14 14:13:56 15 分钟阅读

分享文章

我是怎么用 Python 自动绕过四种主流验证码的(字符、滑块和文字点按)
这是我课程的一个实践作业目标是自动登录几个网站并通过验证码验证。原本以为只要获取页面元素只要做好定位就行但是被不同类型验证码给卡了---为什么会有这个项目做数据作业时我需要自动登录豆瓣、当当、B站、古诗文网时候本以为 Selenium 点几下就行了结果全都被验证码拦住了。四个网站四种完全不同的验证码形式网站验证码类型豆瓣滑块嵌套在 iframe 里当当滑块背景图需要下载B站文字点选需要 AI 识图古诗文网字符验证码需要 OCR每一种破解思路都不一样踩了不少坑这篇文章就是把这些经历整理下来。项目整体设计在乱写代码之前我先想了一下架构。验证码虽然形态各异但识别 → 操作 → 验证结果的流程是通用的所以我抽了一个BaseSolver基类再派生出三条分支BaseSolver ├── SliderSolver # 滑块类 │ ├── DoubanSolver │ └── DangdangSolver ├── ClickSolver # 点选类 │ └── BilibiliSolver └── OcrSolver # 字符类 └── GushiwenSolver配置统一走config.py支持.env环境变量账号密码不用硬编码在代码里。工具函数放在utils/下图像处理和人类行为模拟分开管理。一、滑块验证码看起来简单其实有坑核心思路滑块验证码的破解分三步找缺口位置 → 生成轨迹 → 模拟拖动。找缺口我用的是 OpenCV 边缘检测def find_gap_by_edge_detection(img_path, search_region_ratio0.33): img cv2.imread(img_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred cv2.GaussianBlur(gray, (5, 5), 0) edges cv2.Canny(blurred, 50, 150) h, w edges.shape search_start int(w * search_region_ratio) # 只搜索右侧区域 right_region edges[:, search_start:] col_sums np.sum(right_region 0, axis0) if len(col_sums) 0 and np.max(col_sums) 10: max_col_idx np.argmax(col_sums) return search_start max_col_idx return 260 # 找不到就用默认值兜底只搜索右侧 2/3 区域是个小技巧——缺口不可能出现在最左边这样能过滤掉很多干扰边缘。轨迹生成让滑动看起来像人直接move_by_offset(distance, 0)一步到位会直接被检测出来。我用了一个加速-减速的物理模型来生成轨迹def get_slide_track(distance): track [] current 0 mid distance * 3 / 5 # 前 60% 加速后 40% 减速 t 0.2 v 0 while current distance: a random.uniform(2, 4) if current mid else -random.uniform(3, 5) v0 v v v0 a * t move v0 * t 0.5 * a * t * t move max(move, 1) if current move distance: track.append(distance - current) break track.append(move) current move return track每一步还加了随机的 Y 轴微小偏移再配上逐字符输入的延迟human_type整体行为更接近真实用户。豆瓣的坑iframe 切换豆瓣的滑块套在一个captcha.gtimg.com的 iframe 里背景图是 base64 编码内嵌在src里的需要先解码再存图获取滑块元素前也要先切换 frame。这个坑让我调试了很久才发现iframe self.driver.find_element(By.XPATH, //iframe[contains(src, captcha.gtimg.com)]) self.driver.switch_to.frame(iframe) # ... 操作滑块 ... self.driver.switch_to.default_content()二、文字点选验证码把 AI 当工具用B站用的是极验的文字点选验证码——题目图片里显示几个汉字要你按顺序点击大图里对应的字。这个我没想到手写算法的好办法最后用了通义千问的视觉 API 来解。思路是把题目图和点击区域大图都截图拼接成一个 prompt 发给模型让它返回需要点击的坐标列表。BilibiliSolver继承自ClickSolver只需要实现三个方法获取题目图、获取点击区域图、获取点击区域的 DOM 元素。基类负责调用 AI 和执行点击。这部分让我意识到不是所有问题都要自己解能用 AI API 的地方就用。三、字符验证码接入第三方打码平台古诗文网登录需要输入图片里的字符验证码。这类验证码识别准确率要求高我用了超级鹰打码平台它的接口很简单class ChaojiyingClient: def __init__(self, username, password): self.username username self.password hashlib.md5(password.encode()).hexdigest() self.api_url http://upload.chaojiying.net/Upload/Processing.php def recognize(self, img_bytes, codetype1902): data {user: self.username, pass2: self.password, codetype: codetype} files {userfile: (captcha.jpg, img_bytes)} r requests.post(self.api_url, datadata, filesfiles, timeout15) result r.json() if result.get(err_no) 0: return result[pic_str], result.get(pic_id) return None, None有个细节值得一提识别失败时要调用report_error(pic_id)把题分退回来不然白花钱。几个通用经验重试机制要做好。验证码不可能次次成功滑块偏差、网络延迟、AI 识别错误都会失败。我在基类里统一了最多重试 3 次的逻辑可以通过配置覆盖。配置要与代码分离。账号、API Key、驱动路径全部走.env文件不要硬编码。.env.example提交到仓库真实的.env加进.gitignore。截图调试很重要。每次获取到验证码图片都保存一份到screenshots/目录失败时可以直接看图找问题省去很多盲猜。等待要随机化。固定的time.sleep(2)在某些情况下会被识别。操作之间用random.uniform(min, max)做随机延迟更难被检测。项目结构captcha_solver/ ├── config.py # 统一配置管理 ├── solvers/ │ ├── base.py # 基类 │ ├── slider.py # 滑块求解器 │ ├── click.py # 点选求解器 │ └── ocr.py # 字符验证码求解器 ├── utils/ │ ├── human.py # 人类行为模拟输入/延迟/轨迹 │ └── image.py # 图像处理边缘检测找缺口 ├── examples/ │ ├── douban_demo.py │ ├── dangdang_demo.py │ ├── bilibili_demo.py │ └── gushiwen_demo.py ├── .env.example └── requirements.txt最后这个项目本质上是在练习如何把自动化操作、计算机视觉、第三方 API 调用这几件事组合起来解决一个具体问题。代码本身不复杂但调试过程让我学到了很多——尤其是 iframe 切换、浏览器指纹反检测这些细节文档里几乎找不到全靠试错。完整源码已上传至 Gitee感兴趣可以去看看 thttps://gitee.com/zzh2947533750/captcha_solver.git如果你在运行时遇到问题欢迎提 Issue 或者在评论区留言。

更多文章