1. 项目概述:当UI自动化遇上验证码
做UI自动化测试或者数据采集的朋友,肯定都绕不开一个“老朋友”——验证码。无论是登录、注册还是关键操作,这个小小的图片或者滑块,往往就是自动化脚本的“终结者”。我最近在做一个电商后台的自动化巡检项目,就频繁被各种验证码卡住,从简单的数字字母,到复杂的滑块、点选,再到行为验证,真是让人头疼。所以,我花了些时间,系统地研究和实测了在Python Selenium框架下,解决验证码问题的几种主流思路。今天就把这四种亲测有效(且免费)的方法,结合我的踩坑经验,详细拆解给大家。无论你是做自动化测试还是爬虫,这篇文章应该都能给你提供一套清晰的“破局”思路。
这四种方法并不是孤立的,它们代表了四种不同的解决层级:从“绕开”(人工介入)到“合作”(第三方平台),再到“硬刚”(本地识别)和“终极规避”(环境与协议)。我会按照从易到难、从临时到稳定的顺序来讲解,并重点分析每种方法的适用场景、核心原理以及你肯定会遇到的实操细节。我们的目标是:让你的Selenium脚本在面对验证码时,不再是“一碰就死”,而是能根据实际情况,选择最合适的策略继续跑下去。
2. 方法一:半自动化策略——人工介入与Cookie复用
这是最直接、最省事,也往往是项目初期或低频任务中最实用的方法。它的核心思想是:在验证码出现的关键节点,让脚本暂停,等待人工识别并输入,然后脚本再接管后续流程。或者,更聪明一点,直接复用已经通过验证的登录状态(Cookie),避免再次触发验证。
2.1 人工手动输入验证码
这个方法听起来很“低级”,但在很多内部系统、测试环境或者验证码出现频率不高的场景下,性价比极高。你不需要研究任何识别算法,只需要让脚本“等一等”你。
核心实现步骤:
定位与截图 :当脚本运行到出现验证码的页面时,使用Selenium定位到验证码图片元素,然后将其截图保存到本地。
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get(\”your_login_page_url\”)
# 假设验证码图片的id是 ‘captcha_image’
captcha_element = driver.find_element(By.ID, \’captcha_image\’)
captcha_element.screenshot(\’captcha.png\’) # 截图保存
这里有个关键点:有些网站的验证码是CSS Sprite(雪碧图)或者动态背景,直接对 img 元素截图可能不完整。更稳妥的做法是截取整个浏览器窗口的图,然后根据验证码元素的坐标进行裁剪。不过对于大多数情况,直接对元素截图够用了。
脚本等待与人工输入 :截图后,脚本暂停运行。我们在代码里弹出一个输入框,或者直接在控制台提示,让人工去查看刚保存的 captcha.png 图片,识别出验证码。
# 方式1:使用内置input函数在控制台等待输入
captcha_code = input(\”请查看当前目录下的captcha.png图片,并输入验证码: \”)
# 方式2:使用更友好的图形化输入(如tkinter),适合做成小工具
# import tkinter as tk
# from tkinter import simpledialog
# root = tk.Tk()
# root.withdraw() # 隐藏主窗口
# captcha_code = simpledialog.askstring(\”验证码\”, \”请输入验证码:\”)
回填与继续 :获取到人工输入的验证码后,脚本将其填入网页对应的输入框,并继续执行后续操作(如点击登录按钮)。
driver.find_element(By.ID, \’captcha_input\’).send_keys(captcha_code)
driver.find_element(By.ID, \’login_button\’).click()
实操心得与避坑指南:
注意 :这种方法的最大缺点是“非全自动”。但它有几个意想不到的优点:首先,100%准确,不用担心识别率问题;其次,对于复杂的、变化频繁的验证码(如点选成语、旋转图片),这是成本最低的解决方案;最后,它完全免费,不依赖任何外部API。
- 超时处理 :一定要为 input() 或图形化输入设置一个超时机制。否则如果人工离开,脚本会永远卡住。可以用 threading 模块开一个计时线程,超时后自动填入一个错误码或终止脚本。
- 路径问题 :确保截图保存的路径是脚本可写且人工方便查看的。可以考虑用绝对路径,或者弹窗时直接显示图片。
- 适用场景 :非常适合 开发调试阶段 、 内部管理系统自动化 、 每日仅需执行数次 的定时任务。我最初在调试登录流程时,就全靠这个方法,快速打通了流程,后续再考虑优化。
2.2 Cookie复用大法
如果说手动输入是“临时通行证”,那Cookie复用就是“永久VIP卡”。一旦用户成功登录一次,浏览器就会获得一个包含会话信息的Cookie。我们只要把这个Cookie保存下来,并在新的Selenium会话中加载,就可以直接跳过登录(包括验证码)环节,访问需要登录态的页面。
核心实现步骤:
首次登录并保存Cookie :专门写一个脚本,用上述手动或任何方式完成一次成功的登录。登录成功后,获取并保存所有的Cookie到文件(如JSON格式)。
# 登录成功后的操作
import json
import pickle # pickle也可以,但JSON更通用安全
cookies = driver.get_cookies()
with open(\’cookies.json\’, \’w\’) as f:
json.dump(cookies, f)
driver.quit()
新会话加载Cookie :在新的自动化脚本开始时,先访问目标网站的任意页面(通常是首页),然后加载之前保存的Cookie。
driver.get(\”https://www.target-site.com\”) # 先访问域名下的页面
time.sleep(2) # 稍等,确保页面加载
with open(\’cookies.json\’, \’r\’) as f:
cookies = json.load(f)
for cookie in cookies:
# 添加前可能需要删除‘expiry’字段,因为它可能是浮点数
if \’expiry\’ in cookie:
# 有时expiry字段会导致添加失败,可以尝试删除或转换
cookie.pop(\’expiry\’)
try:
driver.add_cookie(cookie)
except Exception as e:
print(f\”添加cookie失败: {cookie.get(\’name\’)}, 错误: {e}\”)
# 刷新页面或跳转到需要登录的页面,此时应该已是登录状态
driver.refresh()
实操心得与避坑指南:
- Cookie的有效性 :Cookie是有生命周期的( expiry )。会话Cookie在浏览器关闭后失效,持久化Cookie可以存活较长时间。保存前检查一下Cookie的 expiry 时间。如果过期了,就需要重新登录获取。
- 域名与路径匹配 : driver.add_cookie(cookie) 要求你必须在当前浏览器会话的域名和路径与Cookie的 domain 、 path 属性匹配或为其父级时才能添加成功。这就是为什么我们要先 driver.get 到目标网站根域下的一个页面。
- 安全Cookie :如果Cookie被标记为 secure (仅HTTPS)或 httpOnly (禁止JS访问),Selenium仍然可以添加,但你需要确保当前使用的是HTTPS协议。
- 适用场景 :这是做 数据采集 </




