一、引言:验证码识别——爬虫工程的最后一公里
在当今数据驱动的时代,验证码已成为网站反爬体系中的最后一道防线。根据2025年爬虫安全报告显示,87.4%的商业网站已部署至少一种验证码机制,其中:
- 42.3% 使用文字/图形验证码
- 35.6% 使用滑块验证码
- 15.8% 使用点选验证码
- 6.3% 使用其他复杂验证码(旋转、语序等)
面对如此复杂的验证码体系,手动识别已无法满足工程化需求。超级鹰(Super Eagle)作为国内领先的验证码识别服务平台,凭借其高准确率、多类型支持和合理定价,已成为众多爬虫工程师的首选解决方案。
本文将系统性地讲解超级鹰平台的使用方法、各类验证码的识别技巧、与爬虫框架的深度集成,以及企业级应用的最佳实践。通过本文,你将掌握从基础使用到高级优化的完整技能体系,构建一套可复用、可扩展、高性价比的验证码识别解决方案。
二、超级鹰平台全面解析
2.1 平台概述
超级鹰(Super Eagle)是国内专业的验证码识别服务平台,提供包括文字验证码、滑块验证码、点选验证码等在内的15+种验证码类型的识别服务。其核心优势包括:
- 高准确率:文字验证码识别率>95%,滑块验证码识别率>90%
- 多类型支持:覆盖主流验证码类型,持续更新
- 快速响应:平均识别时间<1.5秒
- 合理定价:按次计费,无月租费用
- API友好:提供完善的Python SDK和详细文档
2.2 注册与认证流程
2.2.1 账号注册
- 访问超级鹰官网:https://www.chaojiying.com/
- 点击"注册",填写邮箱、手机号和密码
- 完成邮箱验证和手机验证
- 登录后进入"账户中心"
2.2.2 实名认证(必要步骤)
- 进入"账户中心" → "实名认证"
- 填写真实姓名、身份证号
- 上传身份证正反面照片
- 等待审核(通常24小时内)
重要提示:未完成实名认证的账号无法使用API服务
2.2.3 充值与套餐选择
超级鹰采用预付费模式,充值后按识别次数扣费:
| 验证码类型 | 单价(元) | 推荐场景 |
|---|---|---|
| 文字/图形验证码 | 0.01 | 常规登录、搜索 |
| 滑块验证码 | 0.03 | 极验、腾讯防水墙 |
| 点选验证码 | 0.02 | 12306、阿里云 |
| 旋转验证码 | 0.04 | 特殊场景 |
| 语序验证码 | 0.05 | 高难度场景 |
充值建议:
- 新用户:先充值50元体验服务
- 中小型项目:充值300-500元
- 企业级应用:联系客服获取定制套餐
三、超级鹰API基础使用
3.1 API认证机制
超级鹰API采用用户名+密码+软件ID三重认证:
- 用户名:注册时填写的账号
- 密码:账号登录密码
- 软件ID:在"开发者中心" → "我的软件ID"中获取
3.2 安装官方SDK
超级鹰提供官方Python SDK,安装方式:
pip install chaojiying
3.3 基础API调用
3.3.1 初始化客户端
from chaojiying import ChaojiyingClient
# 初始化客户端
chaojiying = ChaojiyingClient('your_username', 'your_password', 'your_soft_id')
3.3.2 识别文字验证码
def recognize_captcha(image_path):
"""
识别文字验证码
:param image_path: 验证码图片路径
:return: 识别结果
"""
# 1. 读取图片文件
with open(image_path, 'rb') as f:
image_data = f.read()
# 2. 调用API识别 (验证码类型: 1902)
result = chaojiying.PostPic(image_data, 1902)
# 3. 解析结果
if result['err_no'] == 0:
return result['pic_str']
else:
raise Exception(f"识别失败: {result['err_str']}")
# 使用示例
captcha_text = recognize_captcha('captcha.jpg')
print(f"识别结果: {captcha_text}")
3.3.3 识别滑块验证码
def recognize_slider(image_path, bg_path):
"""
识别滑块验证码
:param image_path: 滑块图片路径
:param bg_path: 背景图片路径
:return: 滑块位置
"""
# 读取图片文件
with open(image_path, 'rb') as f:
slider_data = f.read()
with open(bg_path, 'rb') as f:
bg_data = f.read()
# 调用API识别 (验证码类型: 9101)
result = chaojiying.PostPic3(image_data=slider_data, image_data2=bg_data, codetype=9101)
# 解析结果
if result['err_no'] == 0:
# 返回滑块的x坐标
return int(result['pic_str'])
else:
raise Exception(f"识别失败: {result['err_str']}")
# 使用示例
slider_x = recognize_slider('slider.jpg', 'background.jpg')
print(f"滑块位置: x={slider_x}")
3.4 API响应结构详解
超级鹰API返回标准JSON格式:
{
"err_no": 0,
"err_str": "OK",
"pic_id": "1234567890",
"pic_str": "abcd",
"md5": "d41d8cd98f00b204e9800998ecf8427e"
}
| 字段 | 类型 | 说明 |
|---|---|---|
| err_no | int | 错误代码(0=成功) |
| err_str | string | 错误信息 |
| pic_id | string | 图片ID(用于纠错) |
| pic_str | string | 识别结果 |
| md5 | string | 图片MD5(用于验证) |
常见错误代码:
-1001: 账号余额不足-1002: 软件ID错误-1003: 用户名或密码错误-1004: 验证码类型错误-1005: 上传图片失败-1006: 识别超时
四、文字验证码识别深度实践
4.1 文字验证码类型详解
超级鹰支持多种文字验证码类型:
| 类型ID | 说明 | 适用场景 |
|---|---|---|
| 1001 | 纯数字 | 4位数字验证码 |
| 1002 | 纯英文 | 大小写混合 |
| 1003 | 数字+英文 | 常规验证码 |
| 1004 | 仅汉字 | 中文验证码 |
| 1005 | 带干扰线 | 线条干扰 |
| 1006 | 带干扰点 | 点状干扰 |
| 1007 | 带波浪线 | 曲线干扰 |
| 1008 | 带扭曲 | 字符扭曲 |
| 1009 | 带旋转 | 字符旋转 |
| 1902 | 复杂类型 | 综合干扰 |
4.2 实战案例:政府网站登录
4.2.1 案例背景
某政府网站使用4位数字验证码,类型为1001,需要实现自动登录。
4.2.2 完整代码实现
import requests
from chaojiying import ChaojiyingClient
from PIL import Image
import io
import time
class GovernmentSiteLogin:
def __init__(self, username, password, cjy_username, cjy_password, cjy_soft_id):
self.session = requests.Session()
self.username = username
self.password = password
self.chaojiying = ChaojiyingClient(cjy_username, cjy_password, cjy_soft_id)
# 设置请求头
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Referer': 'https://www.gov-example.com/login',
'Origin': 'https://www.gov-example.com'
}
def get_captcha(self):
"""获取验证码图片"""
captcha_url = "https://www.gov-example.com/captcha"
params = {
't': str(int(time.time() * 1000))
}
response = self.session.get(captcha_url, params=params, headers=self.headers)
if response.status_code != 200:
raise Exception("获取验证码失败")
# 保存验证码图片(用于调试)
with open('captcha.jpg', 'wb') as f:
f.write(response.content)
return response.content
def recognize_captcha(self, image_data):
"""识别验证码"""
result = self.chaojiying.PostPic(image_data, 1001)
if result['err_no'] == 0:
return result['pic_str']
elif result['err_no'] == -1001:
raise Exception("超级鹰账号余额不足")
else:
raise Exception(f"验证码识别失败: {result['err_str']}")
def login(self):
"""执行登录流程"""
# 1. 获取验证码
captcha_image = self.get_captcha()
# 2. 识别验证码
captcha_text = self.recognize_captcha(captcha_image)
print(f"识别的验证码: {captcha_text}")
# 3. 构建登录数据
login_data = {
'username': self.username,
'password': self.password,
'captcha': captcha_text,
'remember': 'on'
}
# 4. 发送登录请求
login_url = "https://www.gov-example.com/login"
response = self.session.post(login_url, data=login_data, headers=self.headers)
# 5. 检查登录结果
if "欢迎登录" in response.text:
print("登录成功!")
return True
elif "验证码错误" in response.text:
print("验证码识别错误,尝试重新识别...")
# 提交错误反馈
self.chaojiying.ReportError(result['pic_id'])
return False
else:
print("登录失败,可能密码错误")
return False
def get_user_data(self):
"""获取用户数据"""
# 需要先登录
if not self.login():
# 尝试重新登录
if not self.login():
raise Exception("多次登录失败")
# 获取用户数据
user_url = "https://www.gov-example.com/user/profile"
response = self.session.get(user_url, headers=self.headers)
if response.status_code == 200:
return response.json()
else:
raise Exception("获取用户数据失败")
# 使用示例
if __name__ == "__main__":
login = GovernmentSiteLogin(
username="your_username",
password="your_password",
cjy_username="super_eagle_user",
cjy_password="super_eagle_pass",
cjy_soft_id="your_soft_id"
)
try:
user_data = login.get_user_data()
print(f"用户数据: {user_data}")
except Exception as e:
print(f"发生错误: {str(e)}")
4.2.3 验证码预处理技巧
对于质量较差的验证码,可进行预处理提高识别率:
def preprocess_captcha(image_path, output_path=None):
"""
验证码预处理(去噪、二值化等)
:param image_path: 原始图片路径
:param output_path: 处理后图片保存路径
:return: 处理后的图片字节数据
"""
from PIL import Image
import numpy as np
# 1. 打开图片
img = Image.open(image_path)
# 2. 转为灰度
img = img.convert('L')
# 3. 二值化处理
threshold = 128
img = img.point(lambda p: p > threshold and 255)
# 4. 去噪处理(8邻域去噪)
img_array = np.array(img)
rows, cols = img_array.shape
for i in range(1, rows-1):
for j in range(1, cols-1):
# 统计8邻域内白色像素数量
white_count = 0
for x in range(-1, 2):
for y in range(-1, 2):
if img_array[i+x, j+y] == 255:
white_count += 1
# 如果白色像素少于3个,认为是噪点,设为黑色
if white_count < 3:
img_array[i, j] = 0
# 5. 转回Image对象
img = Image.fromarray(img_array)
# 6. 保存处理后的图片
if output_path:
img.save(output_path)
# 7. 返回字节数据
img_byte_arr = io.BytesIO()
img.save(img_byte_arr, format='JPEG')
return img_byte_arr.getvalue()
# 使用示例
processed_image = preprocess_captcha('captcha.jpg', 'processed.jpg')
result = chaojiying.PostPic(processed_image, 1001)
五、滑块验证码识别深度实践
5.1 滑块验证码原理
滑块验证码通过要求用户将滑块拖动到正确位置来验证是否为人类。主要分为两类:
- 极验类型:滑块与背景有缺口,需要计算缺口位置
- 腾讯防水墙类型:滑块需要匹配背景图案
5.2 超级鹰API接口详解
超级鹰提供两种滑块识别接口:
5.2.1 PostPic3(推荐)
result = chaojiying.PostPic3(
image_data=slider_image, # 滑块图片
image_data2=bg_image, # 背景图片
codetype=9101 # 验证码类型
)
返回结果:
pic_str: 滑块应拖动的X坐标(单位:像素)- 例如:
"230"表示需要拖动到X=230的位置
5.2.2 PostPic (旧版)
# 旧版接口(不推荐)
result = chaojiying.PostPic(
image_data=combined_image, # 合并的滑块和背景图片
codetype=9004 # 验证码类型
)
推荐使用PostPic3:分离的滑块和背景图片识别更准确
5.3 实战案例:电商网站登录
5.3.1 案例背景
某电商网站使用极验滑块验证码,需要实现自动登录。
5.3.2 完整代码实现
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.common.action_chains import ActionChains
import time
import random
from chaojiying import ChaojiyingClient
class EcommerceSliderLogin:
def __init__(self, username, password, cjy_username, cjy_password, cjy_soft_id):
self.username = username
self.password = password
self.chaojiying = ChaojiyingClient(cjy_username, cjy_password, cjy_soft_id)
# 初始化浏览器
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
self.driver = webdriver.Chrome(options=options)
self.driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': '''
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
'''
})
def download_image(self, element, save_path):
"""下载图片元素"""
# 获取图片URL
img_url = element.get_attribute('src')
if not img_url:
# 可能是base64编码
img_url = element.get_attribute('src')
# 下载图片
if img_url.startswith('data:image'):
# 处理base64图片
img_data = img_url.split(',')[1]
img_bytes = base64.b64decode(img_data)
else:
# 下载网络图片
img_bytes = requests.get(img_url).content
# 保存图片
with open(save_path, 'wb') as f:
f.write(img_bytes)
return img_bytes
def get_slider_position(self):
"""获取滑块位置"""
# 1. 等待滑块元素出现
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'geetest_slider_button'))
)
# 2. 获取滑块和背景图片
slider_img = self.driver.find_element(By.CLASS_NAME, 'geetest_slider')
bg_img = self.driver.find_element(By.CLASS_NAME, 'geetest_bg')
# 3. 下载图片
slider_bytes = self.download_image(slider_img, 'slider.jpg')
bg_bytes = self.download_image(bg_img, 'background.jpg')
# 4. 识别滑块位置
result = self.chaojiying.PostPic3(slider_bytes, bg_bytes, 9101)
if result['err_no'] == 0:
return int(result['pic_str'])
else:
raise Exception(f"滑块识别失败: {result['err_str']}")
def human_like_drag(self, slider_element, target_x):
"""模拟人类拖动行为"""
# 初始位置
ActionChains(self.driver).click_and_hold(slider_element).perform()
time.sleep(0.5)
# 生成人类拖动轨迹
tracks = self.generate_drag_tracks(target_x)
# 模拟拖动
for x, y, t in tracks:
ActionChains(self.driver).move_by_offset(x, y).perform()
time.sleep(t)
# 释放鼠标
time.sleep(0.5)
ActionChains(self.driver).release().perform()
time.sleep(2)
def generate_drag_tracks(self, target_x, distance=None):
"""
生成模拟人类的拖动轨迹
:param target_x: 目标位置
:param distance: 拖动距离(可选)
"""
if distance is None:
distance = target_x
# 1. 加速阶段(占总距离40%)
acceleration_distance = int(distance * 0.4)
# 2. 匀速阶段(占总距离20%)
constant_speed_distance = int(distance * 0.2)
# 3. 减速阶段(占总距离40%)
deceleration_distance = distance - acceleration_distance - constant_speed_distance
tracks = []
current_x = 0
current_y = 0
start_time = time.time()
# 加速阶段
for i in range(1, acceleration_distance + 1):
# 模拟加速度
v = 0.2 * i**0.5
x = i - (i-1)
y = random.randint(-1, 1) # 小幅度上下波动
t = random.uniform(0.01, 0.03)
tracks.append((x, y, t))
current_x += x
# 匀速阶段
for i in range(constant_speed_distance):
x = 1
y = random.randint(-1, 1)
t = random.uniform(0.02, 0.05)
tracks.append((x, y, t))
current_x += x
# 减速阶段
for i in range(deceleration_distance, 0, -1):
# 模拟减速度
v = 0.5 * i**0.5
x = 1 if i > 1 else i
y = random.randint(-1, 1)
t = random.uniform(0.03, 0.08)
tracks.append((x, y, t))
current_x += x
# 微调(避免精确到位)
if current_x < target_x:
remaining = target_x - current_x
for i in range(remaining):
tracks.append((1, 0, random.uniform(0.05, 0.1)))
elif current_x > target_x:
overshoot = current_x - target_x
for i in range(overshoot):
tracks.append((-1, 0, random.uniform(0.05, 0.1)))
return tracks
def login(self):
"""执行登录流程"""
try:
# 1. 打开登录页面
self.driver.get("https://www.ecommerce-example.com/login")
# 2. 输入用户名和密码
self.driver.find_element(By.ID, "username").send_keys(self.username)
self.driver.find_element(By.ID, "password").send_keys(self.password)
# 3. 点击登录触发滑块验证
self.driver.find_element(By.CLASS_NAME, "login-btn").click()
# 4. 获取滑块位置
slider_position = self.get_slider_position()
print(f"识别的滑块位置: x={slider_position}")
# 5. 定位滑块元素
slider_element = self.driver.find_element(By.CLASS_NAME, "geetest_slider_button")
# 6. 模拟人类拖动
self.human_like_drag(slider_element, slider_position)
# 7. 检查验证结果
time.sleep(3)
if "验证成功" in self.driver.page_source:
print("滑块验证通过!")
return True
else:
print("滑块验证失败")
# 提交错误反馈
self.chaojiying.ReportError(result['pic_id'])
return False
except Exception as e:
print(f"登录过程中发生错误: {str(e)}")
return False
def close(self):
"""关闭浏览器"""
self.driver.quit()
# 使用示例
if __name__ == "__main__":
login = EcommerceSliderLogin(
username="your_username",
password="your_password",
cjy_username="super_eagle_user",
cjy_password="super_eagle_pass",
cjy_soft_id="your_soft_id"
)
try:
if login.login():
print("登录成功,可以继续操作")
# 这里可以添加后续操作,如爬取数据
else:
print("登录失败")
finally:
login.close()
5.3.3 滑块轨迹优化技巧
人类拖动滑块的行为具有以下特征,模拟这些特征可提高通过率:
- 加速度变化:开始慢,中间快,结束慢
- 小幅波动:X/Y方向有微小抖动
- 不精确到位:通常会略微超过或不足目标位置
- 速度变化:速度不均匀,有停顿
def generate_human_drag_tracks(target_x, total_time=2.5):
"""
生成高度模拟人类的拖动轨迹
:param target_x: 目标X坐标
:param total_time: 总拖动时间(秒)
"""
# 1. 基础参数
total_points = int(total_time * 30) # 每秒30个点
current_x = 0
current_y = 0
current_time = 0
# 2. 生成随机波动参数
wave_amplitude = random.uniform(0.5, 1.5) # 波动幅度
wave_frequency = random.uniform(0.8, 1.2) # 波动频率
# 3. 生成加速度曲线(S型曲线)
acceleration_curve = []
for i in range(total_points):
t = i / total_points
# S型曲线:开始慢,中间快,结束慢
speed = 0.5 - 0.5 * math.cos(math.pi * t)
acceleration_curve.append(speed)
# 4. 生成轨迹点
tracks = []
for i in range(total_points):
# 计算当前应到达的位置比例
progress = sum(acceleration_curve[:i+1]) / sum(acceleration_curve)
target_progress = progress * target_x
# 计算X增量(考虑波动)
x_increment = target_progress - current_x
# 添加随机波动
x_jitter = wave_amplitude * math.sin(wave_frequency * current_time * 2 * math.pi)
x = x_increment + x_jitter
# Y方向随机波动(小幅度)
y = random.uniform(-1.5, 1.5)
# 时间增量
time_increment = total_time / total_points
tracks.append((x, y, time_increment))
# 更新当前位置
current_x += x
current_y += y
current_time += time_increment
# 5. 微调确保到达目标位置
final_x = sum(point[0] for point in tracks)
if abs(final_x - target_x) > 0.5:
adjustment = target_x - final_x
tracks[-1] = (tracks[-1][0] + adjustment, tracks[-1][1], tracks[-1][2])
return tracks
六、点选验证码识别深度实践
6.1 点选验证码原理
点选验证码要求用户点击图片中指定的文字或图案,常见类型包括:
- 文字点选:点击"点击{文字}"中的对应文字
- 图案点选:点击指定的图案(如交通标志)
- 语序点选:按顺序点击多个文字
6.2 超级鹰API接口详解
result = chaojiying.PostPic(
image_data=image_bytes, # 验证码图片
codetype=9004 # 点选验证码类型
)
返回结果:
pic_str: 点击坐标,格式为"x1,y1|x2,y2|..."- 例如:
"100,200|300,400"表示需要点击(100,200)和(300,400)
6.3 实战案例:12306登录
6.3.1 案例背景
12306网站使用文字点选验证码,需要识别并点击指定文字。
6.3.2 完整代码实现
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.common.action_chains import ActionChains
import time
import requests
from chaojiying import ChaojiyingClient
import base64
import json
class Train12306Login:
def __init__(self, username, password, cjy_username, cjy_password, cjy_soft_id):
self.username = username
self.password = password
self.chaojiying = ChaojiyingClient(cjy_username, cjy_password, cjy_soft_id)
# 初始化浏览器
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
self.driver = webdriver.Chrome(options=options)
self.driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': '''
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
'''
})
def get_captcha_image(self):
"""获取12306验证码图片"""
# 1. 等待验证码图片加载
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.ID, "nc_1_n1z"))
)
# 2. 获取验证码图片元素
captcha_img = self.driver.find_element(By.ID, "nc_1_n1z")
# 3. 获取图片数据
img_url = captcha_img.get_attribute('src')
# 4. 处理base64图片
if img_url.startswith('data:image'):
img_data = img_url.split(',')[1]
img_bytes = base64.b64decode(img_data)
else:
# 下载网络图片
img_bytes = requests.get(img_url).content
return img_bytes
def recognize_captcha_points(self, image_bytes):
"""识别点选验证码坐标"""
# 调用超级鹰API (12306点选验证码类型: 9501)
result = self.chaojiying.PostPic(image_bytes, 9501)
if result['err_no'] == 0:
# 解析坐标
points = []
for point_str in result['pic_str'].split('|'):
x, y = map(int, point_str.split(','))
points.append((x, y))
return points, result['pic_id']
else:
raise Exception(f"点选验证码识别失败: {result['err_str']}")
def click_points(self, points):
"""点击指定坐标"""
# 获取验证码图片元素
captcha_img = self.driver.find_element(By.ID, "nc_1_n1z")
# 获取元素位置
location = captcha_img.location
size = captcha_img.size
for x, y in points:
# 计算实际点击位置(相对于整个页面)
click_x = location['x'] + x
click_y = location['y'] + y
# 模拟人类点击
ActionChains(self.driver).move_to_element_with_offset(
captcha_img, x, y
).click().perform()
time.sleep(random.uniform(0.3, 0.8))
def human_like_click(self, element, x, y):
"""模拟人类点击行为"""
# 随机移动到目标点附近
offset_x = random.randint(-5, 5)
offset_y = random.randint(-5, 5)
# 移动到目标点
ActionChains(self.driver).move_to_element_with_offset(
element, x + offset_x, y + offset_y
).perform()
time.sleep(random.uniform(0.1, 0.3))
# 微调到精确位置
ActionChains(self.driver).move_by_offset(-offset_x, -offset_y).perform()
time.sleep(random.uniform(0.05, 0.15))
# 点击
ActionChains(self.driver).click().perform()
time.sleep(random.uniform(0.1, 0.3))
def login(self):
"""执行登录流程"""
try:
# 1. 打开12306登录页面
self.driver.get("https://www.12306.cn/index/")
# 2. 点击登录按钮
WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.ID, "login"))
).click()
# 3. 等待点选验证码出现
time.sleep(2)
# 4. 获取验证码图片
captcha_image = self.get_captcha_image()
# 5. 识别点选坐标
points, pic_id = self.recognize_captcha_points(captcha_image)
print(f"识别的点选坐标: {points}")
# 6. 点击坐标
for x, y in points:
self.human_like_click(
self.driver.find_element(By.ID, "nc_1_n1z"),
x, y
)
# 7. 等待验证结果
time.sleep(2)
if "验证通过" in self.driver.page_source:
print("点选验证通过!")
# 8. 输入用户名和密码
self.driver.find_element(By.ID, "username").send_keys(self.username)
self.driver.find_element(By.ID, "password").send_keys(self.password)
# 9. 点击登录
self.driver.find_element(By.ID, "loginBtn").click()
# 10. 检查登录结果
time.sleep(3)
if "我的12306" in self.driver.title:
print("登录成功!")
return True
else:
print("登录失败,可能密码错误")
return False
else:
print("点选验证失败")
# 提交错误反馈
self.chaojiying.ReportError(pic_id)
return False
except Exception as e:
print(f"登录过程中发生错误: {str(e)}")
return False
def close(self):
"""关闭浏览器"""
self.driver.quit()
# 使用示例
if __name__ == "__main__":
login = Train12306Login(
username="your_username",
password="your_password",
cjy_username="super_eagle_user",
cjy_password="super_eagle_pass",
cjy_soft_id="your_soft_id"
)
try:
if login.login():
print("成功登录12306,可以继续操作")
# 这里可以添加后续操作,如查询车票
else:
print("登录失败")
finally:
login.close()
6.3.3 坐标校正技巧
由于屏幕分辨率、缩放比例等因素,识别出的坐标可能需要校正:
def calibrate_coordinates(points, element, scale_factor=1.0, offset_x=0, offset_y=0):
"""
校正点击坐标
:param points: 原始坐标列表[(x1,y1), (x2,y2), ...]
:param element: 验证码图片元素
:param scale_factor: 缩放比例(如页面缩放)
:param offset_x: X方向偏移
:param offset_y: Y方向偏移
:return: 校正后的坐标列表
"""
# 获取元素位置和尺寸
location = element
8780

被折叠的 条评论
为什么被折叠?



