一个基于 Node.js + Playwright 的通用脚本,用于抓取一个或多个 H5 游戏页面在运行时实际加载的图片资源,并按规则分类、下载、输出报告。
脚本入口:
- 支持抓取多个游戏入口 URL
- 支持运行时网络监听和 DOM 补扫
- 支持
strict、smart、review三种模式 - 自动推导每个游戏的
allowedOrigin和allowedBasePath - 自动过滤广告、统计、追踪、第三方营销资源
- 支持 CDN 候选打分、分类和报告输出
- 支持移动端模拟
mobile emulation - 支持自动点击
Start / Play / Tap to Start等常见入口 - 支持生成:
report.jsoncandidates.txt
.
├─ package.json
├─ README.md
└─ scripts/
└─ download-game-images.js
- Node.js 18 及以上
- npm
- Playwright 依赖可正常安装
- 首次运行前需要安装 Playwright 浏览器
推荐先确认版本:
node -v
npm -vnpm installnpx playwright install chromium如果你在 Linux 或 WSL 中运行,Playwright 浏览器可能缺少系统动态库。优先执行:
sudo npx playwright install-deps chromium如果仍有缺库问题,再补装常见依赖,例如:
sudo apt-get update
sudo apt-get install -y libnspr4 libnss3npm run download:game-images -- --url="https://example.com/game/index.html"npm run download:game-images -- --url="https://example.com/game1/index.html,https://example.com/game2/index.html"npm run download:game-images -- --out="./downloads"脚本支持以下命令行参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
--url="<url1>,<url2>" |
指定一个或多个入口页面 URL,逗号分隔 | 默认两个内置游戏 |
--out="./downloads" |
指定总输出目录 | ./downloads |
--wait=30000 |
页面加载后的额外等待时长,单位毫秒 | 15000 |
--headless |
启用无头模式 | false |
--mobile |
使用移动端模拟打开页面 | false |
--device="iPhone 13" |
指定 Playwright 设备配置名称 | iPhone 13 |
--no-auto-start |
禁用自动启动点击逻辑 | 自动开启 |
--auto-start-delay=3000 |
页面打开后延迟多久再尝试点击开始 | 3000 |
| `--mode=strict | smart | review` |
--include-cdn |
下载 cdnCandidate |
false |
--include-uncertain |
下载 uncertain |
false |
--allow-domain=a.com,b.com |
手动放行的域名列表 | 空 |
--block-domain=a.com,b.com |
手动屏蔽的域名列表 | 空 |
--force |
覆盖已存在文件 | false |
--help |
显示帮助 | - |
最安全模式。
只下载满足以下条件的图片:
- 是图片资源
- 与入口页面同源
same origin - 位于入口页面目录及其子目录
- 未命中广告、统计、追踪黑名单
适合先做一轮低风险抓取。
示例:
npm run download:game-images -- --mode=strict在 strict 基础上增加 CDN 候选分析。
行为:
- 总是下载
allowed - 只有传入
--include-cdn才下载cdnCandidate - 只有传入
--include-uncertain才下载uncertain blocked永远不下载- 所有候选都会写入报告
示例:
npm run download:game-images -- --mode=smart --include-cdn以审查报告为主。
行为:
- 默认下载
allowed - 不自动下载
cdnCandidate/uncertain - 重点生成
report.json和candidates.txt - 如果显式传入
--include-cdn或--include-uncertain,也可下载这些分类
示例:
npm run download:game-images -- --mode=review以下任一条件满足即视为图片资源:
request.resourceType() === "image"response content-type以image/开头- URL 扩展名为:
pngjpgjpegwebpgifsvgavif
脚本会正确处理带 query / hash 的 URL,但保存到本地时会去掉 query / hash。
脚本不会为每个游戏写死规则,而是根据入口 URL 自动推导:
allowedOrigin = new URL(pageUrl).originallowedBasePath = 入口页面所在目录
示例:
| 页面 URL | allowedOrigin | allowedBasePath |
|---|---|---|
https://jvliang.myfunmax.com/games/Soccer_Free_Kick/index.html |
https://jvliang.myfunmax.com |
/games/Soccer_Free_Kick/ |
https://threehey.myfunmax.com/2312/Shots/index.html |
https://threehey.myfunmax.com |
/2312/Shots/ |
https://example.com/a/b/c/index.html |
https://example.com |
/a/b/c/ |
https://example.com/a/b/c/ |
https://example.com |
/a/b/c/ |
如果 URL 或相关上下文命中以下关键字,会被标记为 blocked:
googleadsgooglesyndicationdoubleclickadserviceanalyticsgtaggstaticadsbygooglepageadadtraffictrackingtrackercollectbeaconpixelfacebookfbcdntiktokbytedanceadjustapplovinunityadsironsourcemintegralchartboostvungle
如果命中 --block-domain 指定域名,也会被标记为 blocked。
对于不满足 strict 规则、但也未直接命中黑名单的图片,脚本会进入评分流程。
典型加分因素:
content-type为图片resourceType为image- 路径包含
assets / images / sprite / texture / res / static等特征 - URL 或路径包含当前游戏目录名
- 域名像静态资源域
- 请求来自主 frame
- frame 同源或处于同游戏目录
- 命中
--allow-domain
典型扣分因素:
- 路径包含
ad / ads / banner / track / pixel / collect / beacon - 来源于跨 frame 非游戏上下文
- 域名或 frame 带明显广告 / 统计 / 社交追踪特征
分类规则:
allowed: 满足strictcdnCandidate:score >= 70uncertain:40 <= score <= 69blocked: 命中黑名单或score < 40
默认总输出目录:
./downloads
每个游戏会生成独立子目录,目录名默认取入口页面目录最后一级:
/games/Soccer_Free_Kick/index.html->Soccer_Free_Kick/2312/Shots/index.html->Shots/a/b/c/index.html->c
如果目录名无法安全推导,则降级为 hostname + timestamp。
保留游戏目录下的相对路径。
示例:
- 页面:
https://jvliang.myfunmax.com/games/Soccer_Free_Kick/index.html - 图片:
https://jvliang.myfunmax.com/games/Soccer_Free_Kick/images/a.png - 保存为:
./downloads/Soccer_Free_Kick/images/a.png
保存到 __cdn__ 目录下。
示例:
./downloads/Soccer_Free_Kick/__cdn__/cdn.example.com/assets/images/a.png
保存到 __uncertain__ 目录下。
示例:
./downloads/Soccer_Free_Kick/__uncertain__/static.example.com/media/thumb.png
每个游戏目录下会生成:
report.jsoncandidates.txt
每条资源包含至少以下字段:
urlnormalizedUrllocalPathoriginhostnamepathnamecontentTyperesourceTypeframeUrlcategoryscorereasonsblockedReasondownloadeddownloadError
按分类输出:
allowedcdnCandidateuncertainblocked
每条记录至少包含:
scoreurlreasons
某些 H5 游戏只在移动端布局下显示开始按钮、横屏提示或特定资源。
可以使用移动端模拟打开页面:
npm run download:game-images -- --mobile指定具体设备:
npm run download:game-images -- --device="iPhone 13"npm run download:game-images -- --device="Pixel 7"移动端模拟使用 Playwright 的设备描述配置,通常会同时设置:
viewportuserAgentisMobilehasTouchdeviceScaleFactor
很多 H5 游戏在首屏不会立即进入游戏,而是要求用户点击:
StartPlayTap to StartContinue
如果不点击,可能会漏掉后续懒加载的图片资源。
脚本默认会自动尝试启动游戏,策略如下:
- 等待一段时间,默认
3000ms - 点击包含常见开始文本的元素
- 点击按钮元素
- 点击
canvas中心 - 点击页面中心
npm run download:game-images -- --auto-start-delay=5000npm run download:game-images -- --no-auto-startnpm run download:game-imagesnpm run download:game-images -- --url="https://example.com/game/index.html" --out="./downloads"npm run download:game-images -- --mobile --wait=30000npm run download:game-images -- --mode=reviewnpm run download:game-images -- --mode=smart --include-cdnnpm run download:game-images -- --mode=smart --include-cdn --allow-domain="cdn.example.com,static.example.com"npm run download:game-images -- --block-domain="ads.example.com,tracker.example.com"npm run download:game-images -- --force优先执行:
sudo npx playwright install-deps chromium
npx playwright install chromium可以指定现成浏览器:
PLAYWRIGHT_EXECUTABLE_PATH=/usr/bin/google-chrome npm run download:game-images或:
PLAYWRIGHT_EXECUTABLE_PATH=/usr/bin/chromium-browser npm run download:game-images当前脚本已经内置纯函数和报告生成自测逻辑,但真实验证仍建议这样做:
- 先用
strict跑一遍,确认低风险资源抓取结果 - 再用
review查看report.json和candidates.txt - 最后按需开启:
--include-cdn--include-uncertain
- 如果页面需要启动交互,优先开启:
--mobile- 合适的
--auto-start-delay - 更长的
--wait
推荐验证命令:
npm run download:game-images -- --mobile --mode=review --wait=30000- 自动点击是通用启发式策略,不保证命中所有游戏的真实开始按钮
- 某些游戏可能需要多次点击、特定坐标或自定义 selector
- 某些资源可能依赖签名 URL、登录态、防盗链或 Service Worker,导致二次下载失败
- DOM 补扫不会深度解析所有外链 CSS 文件规则,网络监听仍是主数据源
- 优先保持
strict和review作为日常排查入口 - 遇到 CDN 误杀或漏抓时,先从
report.json判断是评分问题还是黑名单问题 - 新增特定游戏适配时,优先通过参数扩展而不是写死站点规则