首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python 爬虫验证码处理:短信验证码、图形验证码、滑块、点选

Python 爬虫验证码处理:短信验证码、图形验证码、滑块、点选

原创
作者头像
用户12890632
发布于 2026-11-14 21:46:21
发布于 2026-11-14 21:46:21
90
举报

验证码是网站常见的反爬机制。爬虫中遇到验证码时,通常不建议强行破解,而应优先选择合规方案:例如使用已有登录态的 Cookie、对接官方 API、使用测试环境账号,或者在人工授权下完成验证。下面按四类常见验证码介绍思路和示例代码。

1. 短信验证码

短信验证码通常不能直接通过“爬取页面”获得,因为验证码会发送到真实手机号或短信接收服务中。常见处理方式有三种:

  • 人工输入:适合测试环境或自有账号。
  • Cookie 复用:如果已经登录成功,可以保存 Cookie,减少重复触发短信验证。
  • 第三方短信接收服务:适合合法测试场景,但需要注意服务条款和隐私合规。

下面是一个“人工输入验证码”的 Selenium 示例:

代码语言:javascript
复制
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def login_with_sms_code():
    driver = webdriver.Chrome()
    driver.get("https://example.com/login")

    wait = WebDriverWait(driver, 15)

    # 输入手机号
    phone_input = wait.until(
        EC.presence_of_element_located((By.ID, "phone"))
    )
    phone_input.send_keys("13800000000")

    # 点击发送验证码
    send_btn = wait.until(
        EC.element_to_be_clickable((By.ID, "send_code"))
    )
    send_btn.click()

    # 人工收到短信后输入验证码
    code = input("请输入收到的短信验证码:")

    code_input = wait.until(
        EC.presence_of_element_located((By.ID, "sms_code"))
    )
    code_input.send_keys(code)

    # 点击登录
    login_btn = wait.until(
        EC.element_to_be_clickable((By.ID, "login_btn"))
    )
    login_btn.click()

    return driver

if __name__ == "__main__":
    login_with_sms_code()

如果已有登录态,可以保存和加载 Cookie:

代码语言:javascript
复制
import pickle
from selenium import webdriver

def save_cookies(driver, path="cookies.pkl"):
    with open(path, "wb") as f:
        pickle.dump(driver.get_cookies(), f)

def load_cookies(driver, path="cookies.pkl"):
    driver.get("https://example.com")
    with open(path, "rb") as f:
        for cookie in pickle.load(f):
            driver.add_cookie(cookie)
    driver.refresh()

2. 图形验证码

图形验证码通常由字母、数字或简单汉字组成。处理思路是:

  1. 获取验证码图片;
  2. 对图片做灰度、二值化等预处理;
  3. 使用 OCR 识别文本;
  4. 将识别结果填入表单。

这里推荐使用 ddddocr,它比传统 Tesseract 在验证码场景下通常更容易上手。

代码语言:javascript
复制
import requests
import ddddocr

def recognize_captcha(image_url: str) -> str:
    resp = requests.get(image_url, timeout=10)
    resp.raise_for_status()

    ocr = ddddocr.DdddOcr(show_ad=False, det=True)
    text = ocr.classification(resp.content)
    return text.strip()

if __name__ == "__main__":
    code = recognize_captcha("https://example.com/captcha.png")
    print("识别结果:", code)

如果验证码图片在 Selenium 页面中,也可以先截图再识别:

代码语言:javascript
复制
import tempfile
import os
import ddddocr
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def recognize_element_captcha(driver, img_locator):
    wait = WebDriverWait(driver, 10)
    img = wait.until(EC.presence_of_element_located(img_locator))

    with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
        img.screenshot(tmp.name)
        tmp_path = tmp.name

    try:
        ocr = ddddocr.DdddOcr(show_ad=False, det=True)
        with open(tmp_path, "rb") as f:
            text = ocr.classification(f.read())
        return text.strip()
    finally:
        os.remove(tmp_path)

对于干扰线较多、扭曲严重的验证码,可以先用 Pillow 做灰度处理,再交给 OCR 识别:

代码语言:javascript
复制
from PIL import Image

img = Image.open("captcha.png").convert("L")
img.save("captcha_gray.png")

3. 滑块验证码

滑块验证码通常要求用户拖动滑块补齐缺口。常见处理思路有两种:

  • OpenCV 模板匹配:计算缺口位置;
  • Selenium 模拟拖动:按照轨迹把滑块拖到目标位置。

下面是一个基础示例,先通过 OpenCV 估算缺口距离,再用 Selenium 模拟拖动。

代码语言:javascript
复制
import cv2
import numpy as np
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import random

def find_gap_distance(bg_path: str, slider_path: str) -> int:
    bg = cv2.imread(bg_path, cv2.IMREAD_COLOR)
    slider = cv2.imread(slider_path, cv2.IMREAD_COLOR)

    bg_gray = cv2.cvtColor(bg, cv2.COLOR_BGR2GRAY)
    slider_gray = cv2.cvtColor(slider, cv2.COLOR_BGR2GRAY)

    result = cv2.matchTemplate(bg_gray, slider_gray, cv2.TM_CCOEFF_NORMED)
    _, _, _, max_loc = cv2.minMaxLoc(result)
    return max_loc[0]

def human_like_drag(driver, slider, distance: int):
    action = ActionChains(driver)
    action.click_and_hold(slider).perform()

    remaining = distance
    while remaining > 0:
        step = random.randint(5, 15)
        if step > remaining:
            step = remaining

        y_offset = random.randint(-2, 2)
        action.move_by_offset(step, y_offset).perform()
        remaining -= step
        time.sleep(random.uniform(0.05, 0.2))

    action.release().perform()

def solve_slider_captcha():
    driver = webdriver.Chrome()
    driver.get("https://wlt.szshysh.com/slider-captcha")

    wait = WebDriverWait(driver, 15)

    # 点击触发滑块验证码
    trigger = wait.until(
        EC.element_to_be_clickable((By.ID, "slider_trigger"))
    )
    trigger.click()
    time.sleep(2)

    # 保存背景图和滑块图,实际路径需要根据网站调整
    bg_elem = wait.until(EC.presence_of_element_located((By.ID, "bg_image")))
    slider_elem = wait.until(EC.presence_of_element_located((By.ID, "slider_image")))

    bg_elem.screenshot("bg.png")
    slider_elem.screenshot("slider.png")

    distance = find_gap_distance("bg.png", "slider.png")

    slider_btn = wait.until(
        EC.presence_of_element_located((By.ID, "slider_button"))
    )
    human_like_drag(driver, slider_btn, distance)

    return driver

if __name__ == "__main__":
    solve_slider_captcha()

需要注意,很多网站的滑块验证码会检测拖动轨迹、浏览器指纹和自动化特征。简单匀速拖动很容易被识别,因此实际项目中往往需要更自然的轨迹,或者直接对接合规的验证码服务。

4. 点选验证码

点选验证码通常要求用户按顺序点击指定文字或图标。处理流程一般是:

  1. 获取验证码图片;
  2. 识别需要点击的文字;
  3. 识别每个文字在图片中的坐标;
  4. 使用 Selenium 按顺序点击。

下面是一个简化示例,假设打码接口已经返回按顺序排列的坐标。

代码语言:javascript
复制
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver import ActionChains
import time

def click_captcha_points(driver, img_element, points):
    """
    points 示例:[(x1, y1), (x2, y2), (x3, y3)]
    坐标需要相对于验证码图片左上角计算。
    """
    actions = ActionChains(driver)
    for x, y in points:
        actions.move_to_element_with_offset(img_element, x, y).click()
    actions.perform()

def solve_click_captcha():
    driver = webdriver.Chrome()
    driver.get("https://wlt.szshysh.com/click-captcha")

    wait = WebDriverWait(driver, 15)

    # 触发点选验证码
    trigger = wait.until(
        EC.element_to_be_clickable((By.ID, "click_trigger"))
    )
    trigger.click()
    time.sleep(2)

    # 获取验证码图片元素
    img = wait.until(
        EC.presence_of_element_located((By.ID, "captcha_image"))
    )

    # 截图并发送给识别服务
    img.screenshot("click_captcha.png")

    # 这里仅为示例,实际应调用合规识别接口
    # 返回格式示例:[(120, 80), (200, 150), (60, 190)]
    points = get_click_points("click_captcha.png")

    click_captcha_points(driver, img, points)

    # 点击确认按钮
    confirm = wait.until(
        EC.element_to_be_clickable((By.ID, "captcha_confirm"))
    )
    confirm.click()

    return driver

def get_click_points(image_path: str):
    """
    实际项目中可替换为打码平台或自有识别模型。
    此处仅演示返回格式。
    """
    return [(120, 80), (200, 150), (60, 190)]

if __name__ == "__main__":
    solve_click_captcha()

点选验证码的难点通常不在点击本身,而在于准确识别文字位置和点击顺序。简单文字可以使用 OCR 识别,但复杂中文点选、图标点选或乱序点选通常需要更强的识别模型或第三方服务。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 1. 短信验证码
  • 2. 图形验证码
  • 3. 滑块验证码
  • 4. 点选验证码
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档