High priority: - Fix concurrent race condition for view_count/like_count (atomic update) - Add route request ID tracking to prevent race conditions - Filter get_joke by status=approved (no pending content leak) - Add error feedback for like button Performance: - Optimize random joke query (avoid full table sort) - Limit page_size max to 100 (DoS prevention) Medium: - Add localStorage quota error handling - Handle empty AI response gracefully - Fix generate content title extraction Low: - Add rejected_jokes to stats API - Update dashboard to show rejected count
149 lines
4.0 KiB
Markdown
149 lines
4.0 KiB
Markdown
# 采集工具操作文档
|
||
|
||
## 概述
|
||
|
||
采集工具分为两个独立程序:
|
||
|
||
| 程序 | 功能 | 输出 |
|
||
|------|------|------|
|
||
| `site_finder.py` | 搜索 Bing,发现笑话聚合网站 | `joke_sites.json`(站点编号列表) |
|
||
| `site_crawler.py` | 按编号或 URL,深度翻页采集笑话 | 直接提交到 API(数据库) |
|
||
|
||
---
|
||
|
||
## 一、程序 1:发现笑话站点
|
||
|
||
搜索 Bing 获取笑话聚合网站,保存到 JSON 文件。
|
||
|
||
```bash
|
||
# 搜索并保存站点列表(默认输出到 joke_sites.json)
|
||
python crawler/site_finder.py
|
||
|
||
# 指定关键词
|
||
python crawler/site_finder.py --keywords "笑话大全,冷笑话,段子"
|
||
|
||
# 指定输出文件
|
||
python crawler/site_finder.py --output my_sites.json
|
||
|
||
# 限制最多 10 个站点
|
||
python crawler/site_finder.py --max-sites 10
|
||
|
||
# 显示浏览器窗口
|
||
python crawler/site_finder.py --no-headless
|
||
```
|
||
|
||
**参数说明:**
|
||
|
||
| 参数 | 默认值 | 说明 |
|
||
|------|--------|------|
|
||
| `--keywords` | 笑话大全,搞笑段子,冷笑话,... | 搜索关键词,逗号分隔 |
|
||
| `--output` | `joke_sites.json` | 输出 JSON 文件路径 |
|
||
| `--max-sites` | 15 | 最多保留几个站点 |
|
||
| `--no-headless` | — | 显示浏览器窗口(不加则无头模式) |
|
||
|
||
**输出格式(joke_sites.json):**
|
||
|
||
```json
|
||
[
|
||
{
|
||
"id": 1,
|
||
"url": "https://xiaohua.example.com",
|
||
"domain": "xiaohua.example.com",
|
||
"title": "笑话大全 - 爆笑来袭",
|
||
"found_at": "2026-05-31T10:30:00"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"url": "https://joke.example.net",
|
||
"domain": "joke.example.net",
|
||
"title": "每日一笑",
|
||
"found_at": "2026-05-31T10:30:05"
|
||
}
|
||
]
|
||
```
|
||
|
||
已有站点会自动保留编号,新站点追加,按域名去重。
|
||
|
||
---
|
||
|
||
## 二、程序 2:深度采集指定站点
|
||
|
||
从 JSON 文件按编号加载站点,或直接指定 URL,深度采集该站点所有笑话并提交到 API。
|
||
|
||
### 按编号采集(推荐)
|
||
|
||
```bash
|
||
# 采集 #1 站点
|
||
python crawler/site_crawler.py --id 1
|
||
|
||
# 批量采集多个站点
|
||
python crawler/site_crawler.py --id 1,2,3
|
||
|
||
# 指定站点文件
|
||
python crawler/site_crawler.py --id 1 --sites-file my_sites.json
|
||
```
|
||
|
||
### 直接指定 URL
|
||
|
||
```bash
|
||
# 直接采集任意 URL
|
||
python crawler/site_crawler.py --url https://xiaohua.example.com
|
||
```
|
||
|
||
python crawler/site_crawler.py --url https://www.52xiaohua.com --no-headless
|
||
|
||
### 其他选项
|
||
|
||
```bash
|
||
# 显示浏览器窗口
|
||
python crawler/site_crawler.py --id 1 --no-headless
|
||
|
||
# 指定 API 地址
|
||
python crawler/site_crawler.py --id 1 --api-base http://192.168.1.10:8001
|
||
|
||
# 指定管理员账号
|
||
python crawler/site_crawler.py --id 1 --username admin --password admin123
|
||
```
|
||
|
||
**参数说明:**
|
||
|
||
| 参数 | 默认值 | 说明 |
|
||
|------|--------|------|
|
||
| `--id` | — | 站点编号,多个用逗号分隔 |
|
||
| `--url` | — | 直接指定 URL(与 --id 二选一) |
|
||
| `--sites-file` | `joke_sites.json` | 站点列表文件路径 |
|
||
| `--api-base` | `http://localhost:8001` | API 服务地址 |
|
||
| `--username` | `admin` | 管理员用户名 |
|
||
| `--password` | `admin123` | 管理员密码 |
|
||
| `--no-headless` | — | 显示浏览器窗口 |
|
||
|
||
---
|
||
|
||
## 三、配合使用流程
|
||
|
||
```bash
|
||
# 1. 先启动 API
|
||
cd api && uvicorn main:app --reload --port 8001
|
||
|
||
# 2. 发现笑话站点(建议第一次用 --no-headless 观察效果)
|
||
cd crawler && python site_finder.py --no-headless
|
||
|
||
# 3. 查看生成的站点列表
|
||
cat joke_sites.json
|
||
|
||
# 4. 选择站点编号,开始深度采集
|
||
python site_crawler.py --id 1 --no-headless
|
||
|
||
# 5. 继续采集其他站点
|
||
python site_crawler.py --id 2,3 --no-headless
|
||
```
|
||
|
||
---
|
||
|
||
## 四、采集说明
|
||
|
||
- **翻页采集**:自动发现首页的翻页链接(`?page=N`、`/page/N/`、`index_N.html`、`下一页` 等),逐页抓取所有笑话
|
||
- **去重**:基于内容 MD5 哈希去重,同一笑话不会重复入库
|
||
- **容错**:单个页面失败自动重试 2 次;同一站点连续失败 3 次自动跳过
|
||
- **翻页限制**:每个站点最多采 30 页,避免无限抓取
|
||
- **状态**:采集的笑话默认 `pending`(待审核),需在后台管理页面审核通过后才会在前台展示 |