验证码是网站常见的反爬机制。爬虫中遇到验证码时,通常不建议强行破解,而应优先选择合规方案:例如使用已有登录态的 Cookie、对接官方 API、使用测试环境账号,或者在人工授权下完成验证。下面按四类常见验证码介绍思路和示例代码。
短信验证码通常不能直接通过“爬取页面”获得,因为验证码会发送到真实手机号或短信接收服务中。常见处理方式有三种:
下面是一个“人工输入验证码”的 Selenium 示例:
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:
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()图形验证码通常由字母、数字或简单汉字组成。处理思路是:
这里推荐使用 ddddocr,它比传统 Tesseract 在验证码场景下通常更容易上手。
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 页面中,也可以先截图再识别:
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 识别:
from PIL import Image
img = Image.open("captcha.png").convert("L")
img.save("captcha_gray.png")滑块验证码通常要求用户拖动滑块补齐缺口。常见处理思路有两种:
下面是一个基础示例,先通过 OpenCV 估算缺口距离,再用 Selenium 模拟拖动。
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()需要注意,很多网站的滑块验证码会检测拖动轨迹、浏览器指纹和自动化特征。简单匀速拖动很容易被识别,因此实际项目中往往需要更自然的轨迹,或者直接对接合规的验证码服务。
点选验证码通常要求用户按顺序点击指定文字或图标。处理流程一般是:
下面是一个简化示例,假设打码接口已经返回按顺序排列的坐标。
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 删除。