一个面向 AI SaaS 应用基础信息收集 的 Windows 端通用爬虫,带 Tkinter 桌面应用 + CLI 两种入口。
- 底层:Python + Playwright,通过 CDP(Chrome DevTools Protocol)接管你自己启动的 Chrome,天然复用浏览器里已有的登录态、Cookie、扩展。
- 探索方式:通用启发式,不针对任何特定站点。从起始 URL 出发,按"价格 > 功能 > 关于 > 文档"等优先级访问站内页面,并尝试点击主 CTA 进入产品功能区(永远不点付费/订阅类按钮)。
- 登录拦截:检测到登录墙会自动暂停。GUI 模式下会弹出醒目的提示横幅,点"我已完成登录"按钮即可继续;CLI 模式下按回车继续。
- 结果整合:可选接入大模型(OpenAI / 通义千问 / DeepSeek / 任意 OpenAI 兼容接口),由 LLM 输出结构化字段并打主观评分。没有 LLM 时退回纯启发式抽取,字段会随爬取实时刷新。
最简方式:双击 install.bat,它会自动:
- 在项目目录创建
.venv虚拟环境(需要系统装有 Python 3.8+) - 安装
requirements.txt里的全部依赖 - 安装 Playwright 自带的 chromium(备用)
或手动:
cd e:\Source\StructAIWeb_cursor
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python -m playwright install chromium不需要重新装 Chrome——爬虫接管的是你系统里已经装好的 Google Chrome 或 Edge。
run_gui.bat和python -m scraper.gui都会自动搜索可用的 Python:先.venv,再 PATH 上的 python,最后扫 Anaconda 的 envs。所以如果你已经在某个 conda env 里装过依赖,可以直接双击run_gui.bat,不用再创建.venv。
直接双击 run_gui.bat,或:
python -m scraper.guiGUI 操作流程(主流程已合并为一个按钮):
- 顶部填入 目标 URL、CDP endpoint(默认
http://127.0.0.1:9222)、最多页数 - 可选填 LLM Provider(none / dashscope / openai / deepseek)和 API Key
- 「尝试使用主功能(评估效果与易用性,仅消耗一次积分)」 默认已勾选,可在"试用输入"修改提示词;若只看公开文案、不消耗任何积分,取消勾选即可
- 点 「🚀 一键结构化分析」 —— 这一步会自动完成:
- 找不到调试浏览器就自动启动一个(不再弹"是否启动"的询问对话框)
- 启动爬取流程,左侧 执行日志 实时显示访问的每个页面、CTA 点击、登录拦截、试用过程等
- 右侧 已抓字段表格 随爬取实时刷新(双击任一行弹窗查看完整值)
- 跑完后自动把结果落盘到
output/<host>_<时间戳>.json,状态栏直接显示文件路径
- 如果触发登录拦截,底部会弹出醒目横幅,回到那个浏览器窗口登录完,再点 GUI 上"我已完成登录" 即可继续
- 想另存到其它路径?点 「另存为...」 弹文件对话框选位置(这是辅助按钮,平时不需要)
浏览器不用提前自己起。如果偏好手动控制,双击老的
start_chrome.bat提前拉一个调试浏览器也行——「一键结构化分析」检测到端口已通就跳过启动这一步。想专门为某站点提前训练高准确率视觉指纹?点 「训练视觉指纹(高精度)」(详见 2.2.1)。
要批量处理一堆站点?点 「批量操作...」(详见 2.1.1)。
GUI 顶部按钮栏的 「批量操作...」 用于"对一份 URL 清单跑同一种任务",支持两种模式:
- 🚀 一键结构化分析:对每个 URL 走完整爬取流程,结果自动写到
output/<host>_<ts>.json - 🎯 视觉指纹训练(高精度):对每个 URL 跑多采样投票训练,结果写到
~/.structaiweb/vision_cache.json
清单文件默认是项目根目录下的 url_list.txt,格式:
# 注释行以 # 开头,会被忽略;空行也忽略
# 每行两个字段:<flag> <url>
# flag = 0 → 本次会处理它;flag = 1 → 本次跳过(占位,用于暂时排除某些站点)
# 分隔符可用空格 / 制表符 / 逗号 / 竖线
0 https://codewisp.ai/create
0 https://laughchat.cn/home
1 https://www.example.com/skip-this-one
执行逻辑:
- 只处理首字段为
0的行(首字段为1或其它值的行整行跳过) - 串行处理:当前一个站点跑完才会开始下一个(不并发,避免对同站点频繁请求触发风控)
- 每开始一个 URL 之前,先做一次登录检测——如果命中登录墙就停下来弹横幅,等你在浏览器里登录完点「我已完成登录」再继续;想直接放弃这条 URL 可以点「跳过登录」(它会被记成
reason=login_required,跑下一条)。视觉指纹训练尤其依赖这一步——没登录的训练会把指纹训歪 - 本工具不会修改
url_list.txt。它是你的输入清单,工具只读不写 - 批量结束后写一份独立的运行报告到
output/batch_report_<时间戳>.json,含每个 URL 的成功/失败、保存路径、错误原因、耗时等。结果对话框也会显示这份报告的路径
报告 JSON 结构示意:
{
"task": "analyze",
"url_list_file": ".../url_list.txt",
"started_at": "2026-05-25T22:30:21",
"finished_at": "2026-05-25T22:30:58",
"elapsed_seconds": 36.92,
"summary": {"total": 1, "ok": 1, "failed": 0},
"items": [
{
"index": 1,
"url": "https://codewisp.ai/create",
"ok": true,
"saved_path": ".../output/codewisp.ai_20260525_223058.json",
"source_line": 2,
"elapsed_seconds": 36.92
}
]
}想"跳过某些已经处理过的站点"?直接手动把对应行的首字段从
0改成1即可,工具本身不再帮你改这个文件。
部分 SaaS 的"开始生成"按钮纯靠文本/class 匹配选不准(比如 laughchat 是"两段提交":先点 ↑ 提交,再点弹出面板里的"开始异步全流程生成")。此时启用视觉模型识别:
- GUI:勾选「用视觉模型识别提交按钮」,输入"视觉模型"名(默认
qwen-vl-max-latest,跑在阿里百炼)即可;base_url / api_key 自动复用上面的 LLM 配置(DashScope、OpenAI、智谱等 OpenAI 兼容多模态服务都支持) - CLI:加
--vision-locator [--vision-model qwen-vl-max-latest]
工作机制:
- 试用前先给页面上所有可点击元素叠加红色编号、所有输入框叠加蓝色编号
- 把整页截图 + 元素清单一起发给多模态模型,让它直接回答:"应该输入到 I1,再依次点 12、25 号按钮"
- 把它返回的编号转成稳定指纹(tag + text + class 关键 token),存到
~/.structaiweb/vision_cache.json,按"域名 + 路径首段"作 key - 同一站点下次直接命中缓存,跳过模型调用;缓存指纹在新 DOM 上失效时会自动清除并重新识别
- 安全护栏:如果模型把"购买 / 充值 / 订阅"等付费按钮当成提交按钮,整个计划会被本地策略拒绝,回退到 score 启发式(不会误扣费)
启用视觉识别后,整个试用按钮选择路径变成"缓存 → 视觉模型 → score 启发式"三级回退,第一级和第二级失败都会自动 fallback。
支持的视觉模型示例(按推荐顺序排列):
| Provider | 视觉模型名 | 备注 |
|---|---|---|
| 阿里百炼 (DashScope OpenAI 兼容模式) | qwen-vl-max-latest ⭐默认, qwen-vl-max, qwen-vl-plus-latest, qwen2.5-vl-72b-instruct |
中文场景识别率最高,账号最容易拿 |
| OpenAI | gpt-4o, gpt-4o-mini, gpt-4-turbo |
需要 OpenAI 账号或镜像服务 |
| 智谱 | glm-4v, glm-4v-plus |
国内备选 |
| 月之暗面 | moonshot-v1-128k-vision-preview |
用百炼做视觉的最简配置:LLM Provider 选
dashscope、API Key 填百炼 sk-、勾选「用视觉模型识别提交按钮」、保持视觉模型名为默认qwen-vl-max-latest。文本和视觉同走百炼一个 Key 搞定。
GUI 上有个 「训练视觉指纹(高精度)」 按钮,专门解决"我希望对某个站点的关键页面(比如 https://codewisp.ai/create)一次性把指纹训准,以后每次爬取都直接命中缓存、不再调视觉模型"的需求。
跟普通流程的区别:
| 维度 | 普通 --vision-locator |
高精度训练 |
|---|---|---|
| 入口 | 自动在试用流程中懒触发,首次失败才调模型 | GUI 上手动点按钮显式触发 |
| 采样次数 | 1 次(截图 → 调一次模型) | N 次(默认 3 次:分别滚动到首屏 / 中部 / 底部各采一次) |
| 决策方式 | 单次结果直接保存 | 多数投票:按"按钮 dom_idx 序列"作 key,赢家才入库 |
| 识别范围 | 只识别 submit_chain + input_box | 还顺便识别 11 类关键元素(详见下表),按角色独立投票 |
| 缓存标记 | trained=false |
trained=true, samples=N, confidence=N/M |
| Token 消耗 | 省 token 优先 | 准确率优先,可以多花 token |
| 适用场景 | 一般站点 | 重要站点、UI 复杂的站点、要批量重复爬取的站点 |
训练时一次性收集的"关键元素角色"(写入 vision_cache.json 的 key_elements 字段):
| 角色 | 含义 | 典型识别结果 |
|---|---|---|
login |
登录入口 | 登录 / Log in / Sign in |
signup |
注册入口 | 注册 / Sign up / Register |
pricing |
定价 / 收费 / 积分中心入口 | Pricing / Plans / 充值 / 积分中心 / Wallet / About credits |
faq |
FAQ / 帮助 / 常见问题 | FAQ / Help / 常见问题 |
docs |
文档 / API 参考 | Documentation / API / Block Editor |
profile |
个人中心 / 头像 | Profile / My account / 头像菜单 |
logout |
退出登录 | Sign out / 退出 |
settings |
设置 / 偏好 | Settings / 偏好 |
history |
历史记录 / 我的作品 | My works / History / My games |
home |
主页 / Logo | Home / 站点 Logo |
contact |
联系 / 反馈 / 支持 | Contact / Feedback / Support |
每个角色独立投票:在 N 次采样中"多数"识别为同一 dom_idx 的角色才被采纳。模型在某次采样里没识别到的角色直接跳过(不会硬塞)。训练完后可以通过 GUI 弹出的结果对话框看到每个角色的 winner_dom_idx / votes / confidence / from_sample_index。
pricing角色允许包含"定价 / Pricing / 充值"字样的链接(视为指向定价页面的入口);其它所有角色严格过滤掉付费按钮(避免误识别"立即支付"这种)。
操作流程:
- GUI 上「目标 URL」填主功能页(推荐直接填
https://codewisp.ai/create这种,不要填入口https://codewisp.ai/);如果你只能填入口,请在训练对话框里勾选「训练前先尝试点击主 CTA」让程序自己跳进去 - 配好 LLM Provider + API Key(训练会复用同一个 Key 调多模态模型)
- 点击 「训练视觉指纹(高精度)」
- 在弹出的对话框里:
- 「采样次数」默认 3(每次都会调一次多模态 LLM),可以调到 1~6
- 「试用文本」会作为给模型的提示语("该用户想干什么"),帮助它挑选语义最匹配的按钮
- 点「开始训练」后,日志窗口会实时显示每次采样的结果(按钮链 dom_idx、模型给出的理由);训练结束弹出完整结果窗口
- 之后回到主界面正常爬取,视觉路径会直接命中
~/.structaiweb/vision_cache.json里的训练成果——日志里会出现视觉缓存命中: 按钮链 N 步,且不会再出现调用视觉模型识别提交按钮
训练只预热缓存,不会抓取字段、不会调 LLM 整合、不会跑试用——它是个独立的"准备"步骤。
先双击 start_chrome.bat 启动调试浏览器后:
# 最简单:用内置默认配置 + 启发式抽取(不调用 LLM)
python -m scraper.main https://laughchat.cn/home
# 限制最多访问 8 个页面
python -m scraper.main https://laughchat.cn/home --max-pages 8
# 启用通义千问做结构化整合 + 评分(需要 DashScope API Key)
python -m scraper.main https://laughchat.cn/home `
--llm-provider dashscope `
--llm-api-key sk-xxxxxxxx
# CLI 也默认会自动试用主功能;如不想消耗积分可关掉
python -m scraper.main https://laughchat.cn/home --no-try-features
# 自定义试用提示词
python -m scraper.main https://laughchat.cn/home `
--demo-text "请帮我写一段产品 slogan。"
# 启用视觉模型识别提交按钮(结果按站点缓存,下次免费)
# 推荐:用阿里百炼一套 Key 同时跑文本 LLM 和视觉 LLM
python -m scraper.main https://laughchat.cn/home `
--llm-provider dashscope --llm-api-key sk-xxx `
--vision-locator # 不带 --vision-model 默认就是 qwen-vl-max-latest
# 如果偏好 OpenAI
python -m scraper.main https://laughchat.cn/home `
--llm-provider openai --llm-api-key sk-xxx `
--vision-locator --vision-model gpt-4o结果会写到 ./output/<host>_<timestamp>.json,控制台也会打印一份。
默认开启的"试用主功能"逻辑:找最大的 textarea / contenteditable,输入设定文本, 点"生成 / 提交 / 发送"类按钮(会主动避开"购买 / 充值 / 订阅"按钮),最长等 30 秒并采用 "出现 + 稳定 4 秒"两阶段判定抓取新增输出,然后把输入和输出一起喂给 LLM 作为
effect_score的依据。 整轮探索只触发一次试用,最多消耗一次积分;如要彻底关闭加--no-try-features即可。
Windows PowerShell 默认编码可能导致中文日志乱码。用 cmd 跑 + 先
chcp 65001即可正常显示;或直接用 GUI 模式不会有这个问题。
复制 config.example.yaml 为 config.yaml,按需修改。常用项:
| 字段 | 说明 |
|---|---|
browser.cdp_endpoint |
Chrome 调试端口。默认 http://127.0.0.1:9222,要和 start_chrome.bat 里的 DEBUG_PORT 一致。 |
crawl.max_pages |
单次最多探索多少个页面(默认 12) |
crawl.same_site_only |
是否只在同根域名下探索(默认 true) |
llm.provider |
none / openai / dashscope / deepseek / custom |
llm.api_key |
LLM API Key。也可以用 --llm-api-key 或环境变量 LLM_API_KEY 传入。 |
output/*.json 的 data 子对象包含:
| 字段 | 说明 |
|---|---|
name |
工具的展示名称(保留品牌大小写) |
logo_url |
工具 logo 图片地址 |
tagline |
一句话简介 / Slogan |
description |
工具详细介绍(纯文本) |
developer |
开发商 / 组织名称 |
is_free |
是否存在免费可用部分(true/false/null)。积分制 / 必须充值 / Free trial 都算 false |
pricing_info |
定价说明文字。若识别到"剩余 N 积分"/"充值"/"会员"等线索,会自动追加"积分制/付费墙线索"段 |
sub_capbility_list |
子功能列表 [{"capbility": "...", "descript": "..."}] |
usability_score / usability_describe |
易用性评分 1~10 及理由 |
effect_score / effect_describe |
效果评分 1~10 及理由(启用 --try-features 时,会基于真实试用输出打分) |
price_score / price_describe |
性价比评分 1~10 及理由 |
顶层另外几个字段:
| 字段 | 说明 |
|---|---|
visited_pages |
本次实际抓到快照的 URL 列表(含 anchor section) |
login_encounters |
命中登录拦截的全部记录(页面 URL + 触发原因) |
demo_runs |
启用 --try-features 时记录的试用结果 [{input, output, url, submit_button}, ...] |
评分字段只有在启用了 LLM 时才会被填充;否则保持为
null并在 describe 中说明原因。
GUI 会把上次填的 目标 URL / CDP / 最多页数 / LLM Provider / API Key / 试用开关 / 试用提示词 / 视觉模型开关 / 视觉模型名 保存到:
%USERPROFILE%\.structaiweb\settings.json
视觉模型识别出的"该点哪些按钮"会按 host + path 缓存到另一个独立文件:
%USERPROFILE%\.structaiweb\vision_cache.json
想强制让某个站点重新识别?直接删掉
vision_cache.json(或编辑掉对应条目)即可;下次访问会重新调一次视觉模型并把新指纹存回。
下次启动 GUI 直接回填,不用每次重新填一遍 API Key。
特点:
- 按 Provider 分桶保存 API Key:切到 OpenAI 输入了一个 key 再切回 DashScope,DashScope 的旧 key 还在。Provider 下拉一变,输入框立刻显示对应的 key。
- 何时落盘:点 「🚀 一键结构化分析」 或 「训练视觉指纹(高精度)」 时保存一次;退出 GUI 时再保存一次;切换 Provider 时也会把当前输入框的 key 写回 旧 Provider 的桶。
- 文件权限:保存后会尝试
chmod 0o600(仅当前用户可读写,Windows 下尽力而为)。 - 配置不会进 git:放在用户主目录,跟项目目录隔离。
- 需要重置 / 想清空保存的 API Key? 在 GUI 顶部按钮区点 「重置配置...」,确认后即删除
settings.json并回到默认值;或者直接手动删除上面那个文件。 - CLI 默认 不读 这个文件(保持脚本可重复性);CLI 用户依旧通过
--llm-api-key/config.yaml/LLM_API_KEY环境变量传 key。
GUI 每次启动都会把详细日志写到 logs/gui.log(追加模式,单文件自动滚动到最大 2 MB × 5 份)。
- 记录的内容包括:
- 每次启动的
=== START ===横幅 + 进程 PID - 用户每次点击「🚀 一键结构化分析」/「训练视觉指纹(高精度)」时的完整参数
- 后台线程开始 / 结束 / 异常
- 探索过程中每个关键节点(连接 Chrome、访问页面、点击 CTA、登录拦截、调用 LLM…)
- 主线程 / 子线程 / asyncio / tkinter callback 的全部未处理异常(带完整 traceback)
- 每次启动的
- 如果 GUI 突然闪退、看不到任何弹窗,打开
logs/gui.log看最后几条就能定位卡在哪一步、是否抛了异常。 - GUI 顶部有 「打开日志文件」 按钮,点它会用资源管理器高亮
gui.log。
StructAIWeb_cursor/
├── README.md # 本文件
├── requirements.txt # Python 依赖
├── config.example.yaml # 配置文件模板
├── install.bat # 一键创建 .venv + 安装依赖
├── run_gui.bat # 启动 Tkinter 桌面应用(自动找有依赖的 Python)
├── start_chrome.bat # (可选)老的手动启动调试 Chrome 脚本
├── output/ # 爬取结果 JSON(自动创建)
├── logs/ # GUI 运行日志(自动创建)
└── scraper/
├── __init__.py
├── main.py # CLI 入口
├── gui.py # Tkinter 桌面应用入口
├── runner.py # 核心流程封装(CLI & GUI 共用)
├── settings.py # GUI 用户偏好持久化(~/.structaiweb/settings.json)
├── logger.py # 统一日志 + 全局异常拦截
├── browser.py # CDP 接管 Chrome / 自动启动浏览器
├── explorer.py # 站内页面发现与调度 + 主 CTA 点击 + 主功能试用
├── extractor.py # 单页 HTML -> 结构化快照
├── login_guard.py # 登录拦截检测 / 暂停等待
└── llm_analyzer.py # LLM 整合 + 评分(可选)
┌──────────────────────┐
│ 你: 双击 start_chrome│
│ 并在 Chrome 里登录 │
└────────┬─────────────┘
│ CDP :9222
▼
┌──────────────────────┐
│ Playwright 接管 Tab │
│ → 访问起始 URL │
│ → 提取 meta/og/正文 │
│ → 发现并排序子链接 │
│ → 遇到登录墙: 暂停 │
└────────┬─────────────┘
│
▼
┌──────────────────────┐
│ 把所有页面快照交给 │
│ LLM 输出 JSON+评分 │
│ (没配 LLM 走启发式) │
└────────┬─────────────┘
│
▼
output/*.json
Q: 程序提示"无法连接到 Chrome 调试端口"?
A: 没先双击 start_chrome.bat,或者已经有别的进程占用了 9222 端口。改 DEBUG_PORT 后记得同步改 config.yaml。
Q: 我的 Chrome 安装在非常规位置,bat 找不到?
A: 用记事本打开 start_chrome.bat,手动改 CHROME_EXE 一行。
Q: 想爬的 SaaS 强制登录才能用,怎么办?
A: 程序检测到登录墙后会暂停,你在浏览器里登录完回到终端按回车即可继续。下次再跑同一个站时(只要 StructAIWeb_chrome_profile 没删),登录态自动复用。
Q: 爬到的字段不全?
A: 这类站点没有把信息暴露在公开页面上是常见现象。脚本会原样返回 "" / null / [],符合需求里"找不到就说找不到"的要求。