update at 2025-10-24 22:27:54

This commit is contained in:
douboer
2025-10-24 22:27:54 +08:00
parent 9bfeee5a6d
commit 3eae607591
4 changed files with 82 additions and 391 deletions

144
block.md
View File

@@ -1,144 +0,0 @@
使用Python和Playwright破解滑动验证码
滑动验证码是一种常见的验证码形式通过拖动滑块将缺失的拼图块对准原图中的空缺位置来验证用户操作。本文将介绍如何使用Python中的OpenCV进行模板匹配并结合Playwright实现自动化破解滑动验证码的过程。
所需技术
OpenCV模板匹配用于识别滑块在背景图中的正确位置。
Python主要编程语言。
Playwright用于浏览器自动化模拟用户操作。
破解过程概述
获取验证码图像:
下载背景图和滑块图。
进行必要的图像预处理。
模板匹配:
使用OpenCV的模板匹配算法计算滑块在背景图中的最佳匹配位置。
模拟滑动:
生成模拟人类滑动的轨迹,避免被识别为机器人。
使用Playwright模拟滑动操作。
实现步骤
设置环境
首先我们需要设置Python环境并安装相关的依赖包。
sh
pip install playwright opencv-python-headless numpy
playwright install
2. 获取并预处理验证码图像
接下来编写Python代码下载验证码的背景图和滑块图并对图像进行预处理。
python
import cv2
import numpy as np
import requests
from PIL import Image
from io import BytesIO
def get_images(bg_url, slider_url):
bg_response = requests.get(bg_url)
slider_response = requests.get(slider_url)
bg_image = Image.open(BytesIO(bg_response.content))
slider_image = Image.open(BytesIO(slider_response.content))
bg_image.save("background.png")
slider_image.save("slider.png")
def preprocess_images():
bg_img = cv2.imread('background.png')
slider_img = cv2.imread('slider.png', cv2.IMREAD_GRAYSCALE)
return bg_img, slider_img
在上述代码中,我们下载并保存验证码图像,然后将滑块图转换为灰度图进行处理。
模板匹配
使用OpenCV的模板匹配算法来确定滑块在背景图中的正确位置。
python
def find_slider_position(bg_img, slider_img):
result = cv2.matchTemplate(bg_img, slider_img, cv2.TM_CCOEFF_NORMED)
_, _, _, max_loc = cv2.minMaxLoc(result)
top_left = max_loc
return top_left[0]
bg_url = 'background_image_url'
slider_url = 'slider_image_url'
get_images(bg_url, slider_url)
bg_img, slider_img = preprocess_images()
slider_position = find_slider_position(bg_img, slider_img)
print('Slider Position:', slider_position)
这里我们使用TM_CCOEFF_NORMED算法进行匹配并找到最佳匹配位置的坐标。
模拟滑动操作
通过生成一条模拟人类滑动的轨迹并使用Playwright模拟滑动操作。
python
更多内容联系1436423940
from playwright.sync_api import sync_playwright
import time
import random
def generate_track(distance):
track = []
current = 0
mid = distance * 4 / 5
t = 0.2
v = 0
while current < distance:
if current < mid:
a = 2
else:
a = -3
v0 = v
v = v0 + a * t
move = v0 * t + 0.5 * a * t * t
current += move
track.append(round(move))
return track
def simulate_slider_move(page, slider, track):
page.mouse.move(slider['x'], slider['y'])
page.mouse.down()
for x in track:
page.mouse.move(slider['x'] + x, slider['y'], steps=10)
time.sleep(random.uniform(0.02, 0.03))
page.mouse.up()
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto('your_target_website_with_captcha')更多内容访问ttocr.com或联系1436423940
slider = page.query_selector('your_slider_css_selector')
bounding_box = slider.bounding_box()
track = generate_track(slider_position)
simulate_slider_move(page, bounding_box, track)
browser.close()
## TypeScript 实现
项目中提供了等价的 TypeScript/Playwright 脚本 `src/slider.ts`按照以下方式运行
```bash
npm run slider -- <url> <滑块选择器> <拖动距离>
```
示例
```bash
npm run slider -- https://example.com '.slider-handle' 180
```
脚本核心逻辑
- `generateTrack(distance)`生成类似人类滑动加速/减速的位移序列
- `performSlide(page, selector, distance)`定位滑块元素模拟按下移动及释放
- 默认以非无头模式启动浏览器可直接观察效果完成滑动后自动关闭

View File

@@ -1,3 +0,0 @@
滑块html如下:
<div class="tc-bg-img unselectable" id="slideBg" style="position: absolute; background-image: url(&quot;https://turing.captcha.qcloud.com/cap_union_new_getcapbysig?img_index=1&amp;image=026109000032302f000000098d06132144b3&amp;sess=s0r5Kya8qgZ8xedtGpqN6EVg9lTGryacXzBhGD8e8ZeKRfus6bp2k9zTRtz0dJO5suozw7lQQ3XENjgan1csllKQxRPeyOQ6HAOKZ5mv8u_sfVgr6N5_dlpFAqdCTGQvxONTYpYsLfBqYp26FZQjqqRpQfelL82H46G3KOyvzZ3o33xtyknXJ3tZPL-ui4EOFWDWijAS2k2p3UoDtrFfCoGngs0B76bJ8mrsdkSCSsK1YLnqtb61RarOEW7xUDW_MeyhHs1zpt8ikwM9Tk1wlajUvSR2gl4VVFyPdSPt_12MwwEv1UpHCLbflFFpkFKLxp0cz9DNZhD5-mSwnq-Jc5Ob9TPDTes-cH-_1lmczZ43q1bmdRZBZ_9u-YNDP0q4fb&quot;); background-position: 0px 0px; background-size: 100%; width: 340px; height: 242.857px; left: 0px; top: 0px; background-repeat: no-repeat; overflow: hidden; z-index: 1; opacity: 1;"></div>

82
release.md Normal file
View File

@@ -0,0 +1,82 @@
## v1.0.0
Playwright + TypeScript 脚本,用于完成豆瓣短信验证码登录,并将登录态持久化到本地 Cookie 文件。
滑块验证码需人工处理,本项目不再尝试自动识别。
## 功能概览
- 启动 Chromium 浏览器并访问豆瓣登录页;
- 自动填写手机号,触发短信验证码;
- 控制台提示用户完成页面内的额外验证(如滑块)并输入短信验证码;
- 登录成功后将 Cookie 状态保存到 `~/douban-cookie.json`,后续运行可直接复用。
## 环境准备
```bash
npm install
npx playwright install chromium
```
需要 Node.js ≥ 18。Playwright 会自动下载 Chromium首次运行请确保网络可访问 Playwright CDN。
## 使用方式
1. 设置手机号环境变量并运行登录脚本:
```bash
DOUBAN_PHONE=13800000000 npm run login
```
2. 浏览器会自动打开豆瓣登录页,脚本完成以下操作:
- 填入手机号并点击「获取验证码」;
- 控制台提示等待页面验证(若出现滑块,请手动完成);
- 控制台等待用户输入短信验证码;
- 验证码提交成功后,脚本将登录态写入 `~/douban-cookie.json` 并退出。
3. 下次运行会优先尝试加载该 Cookie 文件,若仍在有效期内可直接登录。
## 命令列表
| 命令 | 说明 |
| --------------- | ---------------------------- |
| `npm run login` | 启动豆瓣登录流程并保存 Cookie |
## 可配置项
当前脚本仅使用一个环境变量:
| 变量名 | 说明 | 是否必填 | 默认值 |
| -------------- | ---------------- | -------- | ------ |
| `DOUBAN_PHONE` | 登录手机号(大陆) | 必填 | - |
若需要更改 Cookie 保存位置,可在 `src/login.ts` 中调整 `COOKIES_PATH` 定义。
## 工作流程说明
1. 读取 `DOUBAN_PHONE`,未提供则直接退出;
2. 若存在 `~/douban-cookie.json`,加载后访问登录页并校验登录态;
3. 如未登录,执行短信验证码流程,期间需手动处理页面可能出现的滑块或图形验证码;
4. 用户在终端输入收到的短信验证码;
5. 验证通过后,将当前浏览器上下文的 `storageState` 写入 `~/douban-cookie.json`。
## 常见问题
- **登录后仍提示手机号未填写?** 确认 Playwright 浏览器窗口焦点在页面内,避免浏览器阻止自动填充。
- **提示滑块验证但脚本无动作?** 脚本已停止自动滑块功能,请在浏览器中手动拖动滑块完成验证。
- **Cookie 未生成?** 只有当脚本确认登录成功时才会写入 Cookie。若终端未看到 “登录成功Cookies 已保存…” 的日志,请检查短信验证码是否正确。
```bash
# 启用自动滑块验证
DOUBAN_AUTO_SLIDER=1 DOUBAN_PHONE=13800138000 npm run login
# 独立测试滑块功能
npm run slider
```
## 开发脚本
- `src/login.ts`:主登录流程,负责 Cookie 复用、短信登录以及滑块自动化;
- `login.md`:原始业务需求与操作步骤;
- `block.md`滑块破解思路Python 版)与 TypeScript 脚本参考;
- `typescript-spec.md`:团队 TypeScript 编码规范与示例。
## 许可
本项目仅用于功能验证和学习,使用时请遵守目标网站的服务条款。

244
slider.md
View File

@@ -1,244 +0,0 @@
# 滑块验证自动化说明
## 功能概述
本项目实现了滑块验证码的自动识别和破解功能,参考了 [crack-slide-captcha](https://github.com/omigo/crack-slide-captcha) 项目的思路。
## 核心原理
### 1. 计算滑动距离
- 使用 `sharp` 库进行图像处理
- 将背景图转换为灰度图
- 通过边缘检测找到缺口位置
- 计算滑块需要移动的距离
### 2. 模拟人类滑动行为
为了避免被识别为机器人,实现了以下特性:
#### 真实的速度曲线
- **加速阶段** (30%距离, 25%时间):开始较慢,逐渐加快
- **匀速阶段** (50%距离, 50%时间):保持中等速度
- **减速阶段** (20%距离, 25%时间):接近目标时减速
#### 轨迹随机化
- 垂直方向有微小抖动±1-3px
- 非完全直线移动
- 总耗时随机在 1-2 秒之间
#### 随机反应时间
- 鼠标移动到滑块前有 100-300ms 的反应延迟
- 按下和松开鼠标时有 50-100ms 的随机延迟
### 3. 多次尝试机制
由于图像识别不能保证 100% 准确,实现了偏移重试机制:
- 默认尝试偏移: `[0, -2, 2, -5, 5, -10, 10]`
- 每次失败后使用不同偏移值重试
- 直到验证成功或尝试完所有偏移
## 使用方法
### 在登录流程中使用
启用自动滑块验证:
```bash
DOUBAN_AUTO_SLIDER=1 DOUBAN_PHONE=13800138000 npm run login
```
### 高级配置
通过环境变量自定义行为:
```bash
# 启用自动滑块
DOUBAN_AUTO_SLIDER=1 \
# 手动指定滑动距离(像素)
DOUBAN_SLIDER_DISTANCE=250 \
# 自定义偏移尝试序列
DOUBAN_SLIDER_OFFSETS=0,-3,3,-8,8 \
# 超时时间(毫秒)
DOUBAN_SLIDER_TIMEOUT=30000 \
npm run login
```
### 独立测试滑块功能
```bash
npm run slider
```
这会启动一个测试模式,给你 30 秒时间手动导航到包含滑块的页面,然后自动尝试完成滑块验证。
### 在代码中调用
```typescript
import { autoSlide, waitAndHandleSlider, hasSlider } from './slider';
// 检查是否存在滑块
if (await hasSlider(page)) {
console.log('发现滑块验证码');
}
// 自动完成滑块验证
const success = await autoSlide(page, {
distance: 250, // 可选:手动指定距离
offsets: [0, -5, 5], // 可选:自定义偏移序列
timeout: 20000, // 可选:超时时间
});
// 或者等待并处理滑块(如果出现)
await waitAndHandleSlider(page);
```
## 配置选项
### SliderConfig 接口
```typescript
interface SliderConfig {
// 滑块按钮选择器
handleSelector?: string;
// 滑块轨道选择器
trackSelector?: string;
// 背景图选择器
bgSelector?: string;
// 缺口小图选择器
pieceSelector?: string;
// 等待超时(毫秒)
timeout?: number;
// 手动指定距离(像素)
distance?: number;
// 偏移尝试序列
offsets?: number[];
}
```
### 默认选择器
```typescript
{
handleSelector: '.tc-drag-thumb, .slide-verify-slider-mask-item, .slider-button',
trackSelector: '.tc-drag-track, .slide-verify-slider, .slider-track',
bgSelector: '.tc-bg-img, .slide-verify-block-bg, .captcha-bg',
pieceSelector: '.tc-jig-img, .slide-verify-block, .captcha-piece',
timeout: 20000,
offsets: [0, -2, 2, -5, 5, -10, 10]
}
```
## 针对不同验证码调整
### 腾讯防水墙
```typescript
await autoSlide(page, {
handleSelector: '.tc-drag-thumb',
trackSelector: '.tc-drag-track',
bgSelector: '.tc-bg-img',
pieceSelector: '.tc-jig-img',
});
```
### 极验验证
```typescript
await autoSlide(page, {
handleSelector: '.geetest_slider_button',
trackSelector: '.geetest_slider',
bgSelector: '.geetest_canvas_bg',
pieceSelector: '.geetest_canvas_slice',
});
```
### 网易易盾
```typescript
await autoSlide(page, {
handleSelector: '.yidun_slider',
trackSelector: '.yidun_slider_track',
bgSelector: '.yidun_bg-img',
pieceSelector: '.yidun_jigsaw',
});
```
## 提高成功率的技巧
### 1. 调整偏移序列
根据实际测试结果调整偏移值:
```bash
# 如果发现总是差 5-10 像素,可以重点尝试这个范围
DOUBAN_SLIDER_OFFSETS=0,5,10,15,-5,-10 npm run login
```
### 2. 手动指定距离
如果能通过人工观察确定距离:
```bash
DOUBAN_SLIDER_DISTANCE=280 npm run login
```
### 3. 自定义选择器
查看页面 HTML 结构,使用更精确的选择器:
```bash
DOUBAN_SLIDER_HANDLE_SELECTOR='.custom-slider-btn' npm run login
```
### 4. 增加超时时间
网络较慢时:
```bash
DOUBAN_SLIDER_TIMEOUT=60000 npm run login
```
## 注意事项
1. **识别准确率**:图像识别方法的准确率约 70-80%,需要配合偏移重试
2. **反爬策略**:频繁使用可能触发更严格的验证,建议:
- 控制使用频率
- 随机化行为参数
- 使用代理 IP
3. **维护成本**:验证码提供商可能更新策略,需要相应调整选择器和算法
4. **合规使用**:仅用于学习研究,实际使用请遵守目标网站的服务条款
## 故障排查
### 问题:找不到滑块元素
**解决方案**
1. 打开浏览器开发者工具,检查实际的 HTML 结构
2. 使用 `DOUBAN_SLIDER_HANDLE_SELECTOR` 等环境变量指定正确的选择器
### 问题:滑动后验证失败
**可能原因**
1. 距离计算不准确 → 调整 `DOUBAN_SLIDER_OFFSETS`
2. 滑动速度过快 → 修改 `generateTrack` 函数增加总时长
3. 轨迹不够真实 → 增加抖动幅度
### 问题:图像处理失败
**可能原因**
1. 图片格式不支持 → 检查 `getImageBuffer` 函数
2. 选择器不正确 → 调整 `bgSelector``pieceSelector`
3. 使用默认距离 → 手动指定 `DOUBAN_SLIDER_DISTANCE`
## 参考资料
- [crack-slide-captcha](https://github.com/omigo/crack-slide-captcha) - 原始参考项目
- [Sharp 文档](https://sharp.pixelplumbing.com/) - 图像处理库
- [Playwright 文档](https://playwright.dev/) - 浏览器自动化