Files
spider/README.md
toom1996 3fe0b86e11 feat: 媒体机直传 + 向量回填
- media: spider 下载图片后按内容 sha1 生成 key,经后端预签名直传 S4,上报只带 key
  (spider 不持有 AK/SK;单张失败自动回退为上报 URL)
- embed: 新增 embed 子命令,从后端领取缺向量的图片→下载→本地 CLIP 编码→回传
  (媒体拆分后后端拿不到图片字节,向量只能靠回填补齐)
- serve: 服务化常驻模式(领取 crawl 任务 → 抓取 → 回报)
- config: 新增 media.upload/concurrency、vision.endpoint/concurrency
2026-10-25 00:27:46 +08:00

133 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# spider
Vogue 走秀 / The Impression 街拍采集器。抓到的元数据经 HMAC 签名上报后端 `ingest` 接口,由后端异步下载图片、写库、编码向量——**spider 不直连数据库**。
## 两种运行模式
| 模式 | 命令 | 适用 |
|---|---|---|
| 单次抓取 | `spider vogue -b <品牌id> [-s 场次上限]` | 临时补某个品牌、调试 |
| **常驻服务** | `spider serve -w 4 -i 5 -m 5` | **生产用法**:从后台领取任务 |
服务模式不再由人指定品牌:**后台决定爬谁**(`/admin/crawl`),spider 领取并执行,执行结果回报后台。
## 配置(config.yml)
```yaml
ingest:
enabled: true # serve 模式必须为 true
endpoint: "http://<后端IP>:8092/admin/internal/ingest"
secret: "<与后端 INGEST_SECRET 完全一致>"
hashid_secret: "" # 服务模式不需要(brand_uid 由后端下发)
```
> `endpoint` 末尾是 `/ingest`,客户端会自己推导出 `/crawl/tasks`(领取任务)和 `/crawl/tasks/:id/result`(回报结果)。
## 媒体机直传(把下载/上传从前端搬出来)
```yaml
media:
upload: true # 打开:spider 自己下载图并直传对象存储,后端只写库
concurrency: 6 # 下载/上传并发
```
打开后 spider 会:下载图片 → 按内容 sha1 生成 key(`runway/<sha1>.jpg`)→ 向后端
`/admin/internal/upload-url` 申请一次性 PUT 地址 → 直接上传 → 上报时只带 key。
**关键点**:
- 密钥只在后端:spider 拿的是 15 分钟有效的预签名 URL,不持有存储 AK/SK
- key 是内容寻址,重复上传幂等,重爬不产生孤儿文件
- 单张失败不影响整场:失败的图仍带原始 URL,后端会兜底下载
- 关掉 `upload` 就完全回到旧行为(后端下载),可随时回滚
**什么时候值得打开**:spider 部署在**带宽比后端机器好**的地方时收益明显;
如果两者在同一台机器上,下载带宽是同一份,拆开不会更快(只是把活儿换个进程干)。
## 服务模式怎么跑
```bash
# 编译
go build -o spider .
# 启动:4 路并发、空队列每 5 秒轮询、单品牌内部并发 5
./spider serve -w 4 -i 5 -m 5
```
| 参数 | 含义 | 建议 |
|---|---|---|
| `-w/--workers` | 同时跑几个品牌 | 带宽/CPU 够就 2~4;每个品牌内部还有 `-m` 并发 |
| `-i/--interval` | 队列空时的轮询间隔(秒) | 5~10,别设 1(会把后台接口打满) |
| `-m/--max-co` | 单品牌内部的抓取并发 | 3~8;太大会被 Vogue 限流 |
优雅退出:`Ctrl+C` 会停止领新任务,等手上的品牌跑完再退。
日志里每个任务有两行关键输出:
```
[serve] host-1234-0 领取任务 task=7 品牌=Acne Studios(uid=001AJGov) 场次上限=3
[serve] host-1234-0 任务 7 完成:status=done 提交 3 场,耗时 42s
```
## 单次模式(调试用)
```bash
./spider vogue -b 7 # 只抓 Gucci,不限场次
./spider vogue -b 7 -s 2 # 只抓最近 2 场
./spider vogue -d # debug:只打印,不上报
./spider theimpression -n 10 # 街拍,最多 10 条任务
```
`-b` 是**数据库里的数字 id**(`brands.id`),不是 hashid。
## 后台怎么操作
访问 `http://<后端>:8092/admin/crawl`(需先登录后台)。
### 1. 加任务
| 场景 | 操作 |
|---|---|
| 抓单个品牌 | 去 `/admin/brands` 找到品牌 → 点「加入抓取队列」(默认每品牌 3 场) |
| 批量抓一批 | 在 `/admin/crawl` 顶部「批量加入」:前缀 `A` + 场次上限 `3` + 数量 `50` → 就是把 A 开头的 50 个品牌各抓最近 3 场 |
| 重爬某个品牌 | 在任务列表该行点「重试」(会把状态重置为待领取) |
「场次上限」填 `0` 表示不限场次——**批量时不要填 0**,否则一个老品牌可能有上百场,一次灌进来几万张图。
### 2. 看状态
| 状态 | 含义 |
|---|---|
| 待领取 | 已入队,等 spider 来拿 |
| 执行中 | 某个 spider 已领取(列表里会显示 worker 标识) |
| 已完成 | 跑完了。`已提交` 列是本次提交了几场走秀 |
| 失败 | spider 侧进程级失败,会自动重试最多 3 次;耗尽后需手动「重试」 |
**`已提交 = 0` 不一定是错误**:Vogue 上很多品牌没有走秀页面(实测 A 开头品牌里约 75% 没有),这种情况任务是「已完成、提交 0 场」。
### 3. 取消 / 删除
- **取消**:只是不再被领取,**无法中断正在执行的品牌**(spider 手里还在跑)
- **删除**:只删任务记录,已入库的图集不受影响
### 4. 任务卡在「执行中」怎么办
正常情况会被自动回收:后台对 `执行中` 的任务有 **15 分钟租约**,超过仍未回报就自动放回「待领取」。所以 spider 断电/被杀不会导致任务永久丢失,重启后会被重新领走。
## 抓完之后
任务完成只代表**元数据已提交**。图片下载、写库、编码向量由后端 worker 异步完成,看进度去:
- `/admin/ingest-jobs` — 入库任务(pending / processing / done / failed)
- `/admin/articles` — 已入库的图集(默认 `pending` 状态,前台不可见,需在列表里通过)
## 常见问题
| 现象 | 原因 / 处理 |
|---|---|
| 启动即报「ingest 未启用」 | `config.yml` 的 `ingest.enabled` 不是 true |
| 一直「无任务」 | 后台还没加任务,或全部被其他 spider 领走了 |
| 领取报 401 | `ingest.secret` 与后端 `INGEST_SECRET` 不一致 |
| 任务反复失败 | 看后台列表的「错误」列;常见是网络不通/被 Vogue 限流 |
| 抓到了但前台看不到 | 图集是 `pending`,去 `/admin/articles` 通过审核 |