Playwright Python 教程:实战篇
处理验证码是自动化测试和爬虫开发中一个常见且颇具挑战性的任务。Playwright 本身并不直接提供验证码识别功能,但它提供了强大的工具来帮助我们应对各种验证码场景。我会为你梳理思路和方法。
🧠 基本思路和注意事项
处理验证码通常遵循以下流程:
- 检测出现:判断验证码是否在页面上出现。
- 类型判断(可选):识别是数字字母验证码、滑块验证码、点选验证码等。
- 获取数据:获取验证码图片、滑块位置等关键信息。
- 求解答案:通过技术手段(如OCR识别、图像处理、AI模型或第三方服务)计算出验证码的答案,如文本、滑动距离、点击坐标等。
- 模拟操作:利用 Playwright 模拟输入、滑动、点击等行为,完成验证。
- 结果验证:检查是否成功通过验证码挑战。
⚠️ 重要提醒:
- 法律与道德:确保你的自动化操作符合目标网站的
robots.txt
协议、服务条款及相关法律法规。绕过验证码可能触及网站方利益,请用于正当目的(如对自己账户的管理、 authorized 测试等)。 - 可行性:完全自动化处理复杂验证码(如行为验证、智能推理验证码)难度极高,需要持续投入技术研究。对于普通文本验证码和滑块验证码,自动化成功率相对较高。
下面是一个表格,汇总了常见验证码类型及其一般处理思路:
验证码类型 | 描述 | 常用处理思路 | 依赖工具/技术 |
---|---|---|---|
文本图形验证码 | 扭曲的数字、字母或汉字 | OCR识别 | ddddocr , pytesseract + OpenCV |
滑动验证码 | 拖动滑块拼接图片 | 计算缺口位置,模拟拖动 | OpenCV 模板匹配 |
点选验证码 | 点击图中指定的文字或物体 | 识别目标文字/物体并获取坐标,模拟点击 | ddddocr , OpenCV , 深度学习模型 |
计算验证码 | 简单的算术问题 | OCR识别或直接提取文本,计算表达式 | ddddocr , 字符串处理 |
旋转验证码 | 旋转图片至正确角度 | 识别或计算所需旋转角度,模拟旋转 | OpenCV , 深度学习模型 |
🔠 文本图形验证码处理(OCR)
对于包含数字、字母的传统图形验证码,OCR(光学字符识别)是常用方法。
import ddddocr # 一个识别效果较好的OCR库
from playwright.sync_api import sync_playwrightdef handle_text_captcha():with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.goto("https://example.com/login")# 1. 定位并截图验证码元素captcha_selector = "#captcha_image"page.wait_for_selector(captcha_selector)# 对验证码元素进行截图captcha_element = page.query_selector(captcha_selector)captcha_element.screenshot(path="captcha.png")# 2. 使用OCR识别截图ocr = ddddocr.DdddOcr()with open("captcha.png", 'rb') as f:image_bytes = f.read()captcha_text = ocr.classification(image_bytes)print(f"识别出的验证码为: {captcha_text}")# 3. 输入验证码并提交page.fill("#captcha_input", captcha_text)page.click("#submit_button")# 4. 验证处理结果(例如检查是否跳转)# page.wait_for_url("**/dashboard")# 或者检查错误信息是否消失# ... 其他验证逻辑browser.close()if __name__ == "__main__":handle_text_captcha()
提升OCR识别率的技巧:
- 图像预处理:在使用OCR前,可以先使用
OpenCV
等库对验证码图片进行灰度化、二值化、降噪等处理,能显著提高识别准确率。 - 尝试多种OCR库:
ddddocr
对中文和数字验证码效果较好,Tesseract
(配合pytesseract
)是另一个选择,但可能需要训练专属字库。
🧱 滑动验证码处理
滑动验证码需要计算滑块需要拖动的距离,并模拟人的拖动行为。
from playwright.sync_api import sync_playwright
import cv2
import numpy as npdef handle_slide_captcha():with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.goto("https://example.com/with_slide_captcha")# 1. 等待并获取滑块和背景图元素page.wait_for_selector(".slider-container")# 假设背景图是div的背景,可以通过evaluate获取urlbg_style = page.eval_on_selector(".bg-image", "el => getComputedStyle(el).backgroundImage")bg_url = bg_style.replace('url("', '').replace('")', '')# 也可以直接截图元素slider_element = page.query_selector(".slider-button")slider_box = slider_element.bounding_box()# 截图背景图bg_element = page.query_selector(".bg-container")bg_element.screenshot(path="background.png")# 2. 使用OpenCV计算滑动距离background = cv2.imread("background.png", 0)# 读取滑块图片(通常是小缺口图,可能需要事先准备好)template = cv2.imread("template.png", 0)result = cv2.matchTemplate(background, template, cv2.TM_CCOEFF_NORMED)_, max_val, _, max_loc = cv2.minMaxLoc(result)# 计算缺口中心点的x坐标gap_x = max_loc[0] + template.shape[1] // 2# 计算需要拖动的距离(可能需减去滑块初始位置)slide_distance = gap_x - slider_box['x'] - slider_box['width'] / 2print(f"计算得到的滑动距离为: {slide_distance}")# 3. 模拟拖动操作slider_handle = slider_element.bounding_box()start_x = slider_handle['x'] + slider_handle['width'] / 2start_y = slider_handle['y'] + slider_handle['height'] / 2page.mouse.move(start_x, start_y)page.mouse.down()# 模拟人的拖动轨迹(先快后慢,略带抖动)steps = []total_steps = 10for i in range(total_steps):# 轨迹生成算法可以更复杂step = slide_distance / total_stepssteps.append(step)current_x = start_xfor step in steps:current_x += step# 添加一些随机的Y轴偏移,模拟人手抖动random_y_offset = np.random.randint(-2, 2)page.mouse.move(current_x, start_y + random_y_offset)page.mouse.up()browser.close()
关键点:
- 获取图片:获取完整的背景图和滑块的缺口图是关键。有时图片藏在元素样式里或需要通过网络请求拦截。
- 计算距离:使用
OpenCV
的模板匹配功能计算滑块需要移动的距离。 - 模拟人类轨迹:直接设置终点坐标容易被识别。应模拟人类先快后慢、略带抖动的拖动轨迹。
🔍 高级技巧与替代方案
-
第三方打码平台与服务
对于非常复杂或自己难以处理的验证码,可以考虑使用专业的打码平台,如 2Captcha、Anti-Captcha 等。 你只需将验证码图片发送给他们的API,他们会返回识别结果(通常是文本或坐标)。 -
人工干预接管(半自动化)
在最复杂或自动化成本过高的情况下,可以设计程序在遇到验证码时暂停,并提示用户手动输入或完成验证,然后脚本再继续执行。 -
规避检测:让 Playwright 更像真人
网站会检测浏览器环境特征来判断是否是自动化脚本。Playwright 提供了一些方法来隐藏自动化痕迹:context = browser.new_context(viewport={"width": 1920, "height": 1080},user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...",# 绕过WebDriver检测bypass_csp=True,# 设置语言、时区等locale="zh-CN",timezone_id="Asia/Shanghai", ) # 在页面中执行JS,修改navigator属性 page.add_init_script("""delete Object.getPrototypeOf(navigator).webdriver;Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3], enumerable: true }); """)
💎 最佳实践与总结
- 优先考虑官方渠道:检查目标网站是否提供测试环境或无验证码的测试账号,或是否有供开发者使用的API。
- 合理设置等待与重试:验证码加载、识别和提交后都需要充分的等待时间。对于识别失败的验证码,要有重试机制。
- 代码封装与复用:将不同验证码的处理方法封装成函数或类,便于管理和调用。
- 监控与日志:记录验证码识别的成功率和失败原因,便于优化。
- 成本权衡:评估自建识别系统的维护成本(时间、技术)和使用第三方服务的金钱成本,做出合适选择。
处理验证码没有一劳永逸的万能药,往往需要具体问题具体分析。建议先从简单的方法(如OCR)尝试,结合Playwright强大的自动化能力,逐步解决遇到的问题。