>这是我课程的一个实践作业,目标是自动登录几个网站并通过验证码验证。原本以为只要获取页面元素,只要做好定位就行,但是被不同类型验证码给卡了

---

为什么会有这个项目

做数据作业时,我需要自动登录豆瓣、当当、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_ratio=0.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, axis=0)
  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, codetype=1902):
    data = {'user': self.username, 'pass2': self.password, 'codetype': codetype}
    files = {'userfile': ('captcha.jpg', img_bytes)}
    r = requests.post(self.api_url, data=data, files=files, timeout=15)
    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 或者在评论区留言。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐