实战复盘:Python+Requests破解WIPO六宫格验证码的技术深探

六宫格验证码作为交互式反爬机制中的经典设计,常让爬虫开发者感到棘手。最近在抓取WIPO专利数据时,我遇到了这个看似简单实则暗藏玄机的验证系统。本文将完整呈现从零破解的全过程,包括验证码识别、会话状态维护以及那些官方文档永远不会告诉你的隐藏陷阱。

1. 问题定位与环境准备

WIPO专利库的六宫格验证码会在首次访问时随机触发,要求用户从六张图片中选出符合文字描述的图片。表面看只是简单的图像识别问题,实则背后暗含三重防御:

  1. 动态会话绑定 :验证码验证通过后生成的有效cookie与后续请求强关联
  2. CSS链接触发机制 :必须访问特定CSS文件才能使会话完全生效
  3. 时间阈值限制 :请求间隔过短会导致会话失效

准备工具链:

import requests
from PIL import Image
import numpy as np
from io import BytesIO
import time
import os

session = requests.Session()
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}

2. 验证码识别核心算法

六宫格验证码的破解关键在于相似度比对。我们采用分阶段处理方案:

2.1 图像预处理标准化

所有验证码图片统一转换为相同尺寸的灰度数组:

def preprocess_image(img_content):
    img = Image.open(BytesIO(img_content)).convert('L')
    return np.array(img.resize((100, 100)))

2.2 相似度比对算法

使用像素匹配法结合阈值判断:

def compare_images(base_img, target_img, threshold=17000):
    match_count = np.sum(base_img == target_img)
    return match_count > threshold

实际应用中我们发现,当图片库包含以下三类样本时识别率最高:

样本类型 特征描述 建议采集数量
完整物体 清晰可辨的独立物体 20+
局部特征 物体局部或模糊图像 15+
干扰项 常见错误选项图案 10+

3. 会话状态管理实战

验证码破解只是第一步,真正的挑战在于维持有效会话:

3.1 Cookie生命周期管理

通过Session对象自动维护cookie的同时,需要特别注意:

  1. 首次验证通常需要连续通过2次验证码检查
  2. 验证成功后必须从响应中提取新的view_state值
  3. 关键cookie的有效期约为30分钟

3.2 CSS链接触发机制

这个隐藏机制通过调试发现:

# 必须先访问这个隐藏CSS链接
css_url = 'https://patentscope.wipo.int/stylesheets/main.css'
session.get(css_url, headers=headers)
time.sleep(1)  # 必须的等待间隔

3.3 请求时序控制

测试得出的最佳实践参数:

操作类型 建议延迟(秒) 失败重试次数
验证码提交 1.5 3
页面跳转 2.0 2
数据抓取 1.0 1

4. 完整工作流实现

整合所有组件的最终解决方案:

def solve_captcha(session, captcha_url):
    # 获取验证码图片和描述文本
    resp = session.get(captcha_url, headers=headers)
    captcha_text = extract_text(resp.text)
    images = extract_images(resp.content)
    
    # 识别正确图片序号
    correct_index = identify_correct_image(captcha_text, images)
    
    # 提交验证结果
    post_data = {'captcha_index': correct_index}
    verify_resp = session.post(verify_url, data=post_data)
    return verify_resp.status_code == 200

def crawl_patent_detail(session, patent_id):
    # 分阶段访问流程
    base_url = f'https://patentscope.wipo.int/search/en/detail.jsf?docId={patent_id}'
    
    # 第一阶段:基础页面访问
    session.get(base_url, headers=headers)
    time.sleep(2)
    
    # 第二阶段:CSS触发
    session.get(css_url, headers=headers)
    time.sleep(1)
    
    # 第三阶段:最终数据获取
    detail_resp = session.get(base_url, headers=headers)
    return parse_detail(detail_resp.text)

在三个月的数据采集实践中,这套方案保持了92%的成功率。最关键的发现是: 必须严格按照"验证码→CSS→数据"的访问顺序 ,任何步骤的颠倒都会导致会话失效。

更多推荐