由于公司最近需要对接某业务系统,涉及到部分数据需要提交至其它平台业务系统,只有其它平台账户,没有接口,因此做此开发。首先通过OpenCV计算出验证验证码滑块距离,根据距离,使用 Playwright 利用滑动距离模拟登录
下面展示Python 通过 Playwright 滑动及登录过程
- 首先下载 安装 Playwright
bash
pip install playwright
- 安装浏览器驱动(此步骤会在本地安装二进制浏览器:火狐、谷歌等)
bash
python -m playwright install
- Playwright 录制脚本(通过脚本录制,不需要写代码,通过鼠标事件将代码输出到文件当中)
bash
python -m playwright codegen -o "D:test.py"
- 主要代码展示
python
import re
from playwright.sync_api import Playwright, sync_playwright
import time
import random
from result import error_result, success_result
from position import get_gap_position
def perform_slide(page, max_retries=3):
"""执行滑块验证,支持自动重试"""
retry_count = 0
while retry_count < max_retries:
try:
page.wait_for_selector("#circle", state="visible", timeout=2000)
page.wait_for_selector("#bg_canvas", state="visible", timeout=2000)
# 计算缺口位置
try:
image_data = page.evaluate("document.getElementById('bg_canvas').toDataURL('image/png').split(',')[1]")
gap_x = get_gap_position(image_data)
except Exception as e:
print(f"缺口检测失败,使用默认偏移量: {e}")
gap_x = 50 # 备用值
# 模拟拖动
slider = page.query_selector("#circle")
slider_bbox = slider.bounding_box()
start_x = slider_bbox["x"] + slider_bbox["width"] / 2
start_y = slider_bbox["y"] + slider_bbox["height"] / 2
target_x = start_x + gap_x + 8
page.mouse.move(start_x, start_y)
page.mouse.down()
steps = random.randint(15, 30)
for i in range(steps):
x = start_x + (target_x - start_x) * (i / steps)
y = start_y + random.uniform(-2, 2)
page.mouse.move(x, y)
#time.sleep(random.uniform(0.01, 0.02))
page.mouse.up()
# 检查成功
if page.query_selector(".popup-success"):
print("验证成功!")
return True
else:
retry_count += 1
print(f"验证失败,第 {retry_count} 次重试...")
time.sleep(0.5)
except Exception as e:
print(f"滑动过程中出错: {e}")
retry_count += 1
return False
def login_with_slide(
username: str,
password: str,
login_url: str = "http://test.com/",
max_slide_retries: int = 3
) -> dict:
"""执行带滑块验证的登录,并返回登录接口的 JSON 数据"""
with sync_playwright() as playwright:
browser = playwright.webkit.launch(headless=True)
context = browser.new_context()
page = context.new_page()
page.set_default_timeout(5000)
login_response = None
def handle_response(response):
nonlocal login_response
if "login2" in response.url and response.status == 200:
try:
print("登录接口响应:", response.json())
login_response = login_result(response.json())
except ValueError:
return error_result("接口返回非json数据")
page.on("response", handle_response)
try:
page.goto(login_url)
page.get_by_role("textbox", name="请输入统一社会信用代码或身份证号").fill(username)
page.get_by_role("textbox", name="请输入密码").fill(password)
page.get_by_role("button", name="登录").click()
if not perform_slide(page, max_slide_retries):
return error_result("滑块验证失败")
# 等待登录接口响应
page.wait_for_timeout(500) # 简单延迟,确保响应已捕获
return login_response or error_result("未获取到登录异常")
except Exception as e:
return error_result("f登录异常: {}"+str(e))
finally:
page.close()
context.close()
browser.close()
def login_result(response: dict) -> dict:
if response.get("result")==0:
return success_result("成功",response.get("data",{}).get("userDetail"))
return error_result("登录失败,接口信息异常")
if __name__ == "__main__":
result = login_with_slide(
username="admin",
password="hpg123789"
)
print("最终结果:", result)