# MediaCrawler 项目架构文档
## 1. 项目概述
### 1.1 项目简介
MediaCrawler 是一个多平台自媒体爬虫框架,采用 Python 异步编程实现,支持爬取主流社交媒体平台的内容、评论和创作者信息。
### 1.2 支持的平台
| 平台 | 代号 | 主要功能 |
|------|------|---------|
| 小红书 | `xhs` | 笔记搜索、详情、创作者 |
| 抖音 | `dy` | 视频搜索、详情、创作者 |
| 快手 | `ks` | 视频搜索、详情、创作者 |
| B站 | `bili` | 视频搜索、详情、UP主 |
| 微博 | `wb` | 微博搜索、详情、博主 |
| 百度贴吧 | `tieba` | 帖子搜索、详情 |
| 知乎 | `zhihu` | 问答搜索、详情、答主 |
### 1.3 核心功能特性
- **多平台支持**:统一的爬虫接口,支持 7 大主流平台
- **多种登录方式**:二维码、手机号、Cookie 三种登录方式
- **多种存储方式**:CSV、JSON、SQLite、MySQL、MongoDB、Excel
- **反爬虫对策**:CDP 模式、代理 IP 池、请求签名
- **异步高并发**:基于 asyncio 的异步架构,高效并发爬取
- **词云生成**:自动生成评论词云图
---
## 2. 系统架构总览
### 2.1 高层架构图
```mermaid
flowchart TB
subgraph Entry["入口层"]
main["main.py
程序入口"]
cmdarg["cmd_arg
命令行参数"]
config["config
配置管理"]
end
subgraph Core["核心爬虫层"]
factory["CrawlerFactory
爬虫工厂"]
base["AbstractCrawler
爬虫基类"]
subgraph Platforms["平台实现"]
xhs["XiaoHongShuCrawler"]
dy["DouYinCrawler"]
ks["KuaishouCrawler"]
bili["BilibiliCrawler"]
wb["WeiboCrawler"]
tieba["TieBaCrawler"]
zhihu["ZhihuCrawler"]
end
end
subgraph Client["API客户端层"]
absClient["AbstractApiClient
客户端基类"]
xhsClient["XiaoHongShuClient"]
dyClient["DouYinClient"]
ksClient["KuaiShouClient"]
biliClient["BilibiliClient"]
wbClient["WeiboClient"]
tiebaClient["BaiduTieBaClient"]
zhihuClient["ZhiHuClient"]
end
subgraph Storage["数据存储层"]
storeFactory["StoreFactory
存储工厂"]
csv["CSV存储"]
json["JSON存储"]
sqlite["SQLite存储"]
mysql["MySQL存储"]
mongodb["MongoDB存储"]
excel["Excel存储"]
end
subgraph Infra["基础设施层"]
browser["浏览器管理
Playwright/CDP"]
proxy["代理IP池"]
cache["缓存系统"]
login["登录管理"]
end
main --> factory
cmdarg --> main
config --> main
factory --> base
base --> Platforms
Platforms --> Client
Client --> Storage
Client --> Infra
Storage --> storeFactory
storeFactory --> csv & json & sqlite & mysql & mongodb & excel
```
### 2.2 数据流向图
```mermaid
flowchart LR
subgraph Input["输入"]
keywords["关键词/ID"]
config["配置参数"]
end
subgraph Process["处理流程"]
browser["启动浏览器"]
login["登录认证"]
search["搜索/爬取"]
parse["数据解析"]
comment["获取评论"]
end
subgraph Output["输出"]
content["内容数据"]
comments["评论数据"]
creator["创作者数据"]
media["媒体文件"]
end
subgraph Storage["存储"]
file["文件存储
CSV/JSON/Excel"]
db["数据库
SQLite/MySQL"]
nosql["NoSQL
MongoDB"]
end
keywords --> browser
config --> browser
browser --> login
login --> search
search --> parse
parse --> comment
parse --> content
comment --> comments
parse --> creator
parse --> media
content & comments & creator --> file & db & nosql
media --> file
```
---
## 3. 目录结构
```
MediaCrawler/
├── main.py # 程序入口
├── var.py # 全局上下文变量
├── pyproject.toml # 项目配置
│
├── base/ # 基础抽象类
│ └── base_crawler.py # 爬虫、登录、存储、客户端基类
│
├── config/ # 配置管理
│ ├── base_config.py # 核心配置
│ ├── db_config.py # 数据库配置
│ └── {platform}_config.py # 平台特定配置
│
├── media_platform/ # 平台爬虫实现
│ ├── xhs/ # 小红书
│ ├── douyin/ # 抖音
│ ├── kuaishou/ # 快手
│ ├── bilibili/ # B站
│ ├── weibo/ # 微博
│ ├── tieba/ # 百度贴吧
│ └── zhihu/ # 知乎
│
├── store/ # 数据存储
│ ├── excel_store_base.py # Excel存储基类
│ └── {platform}/ # 各平台存储实现
│
├── database/ # 数据库层
│ ├── models.py # ORM模型定义
│ ├── db_session.py # 数据库会话管理
│ └── mongodb_store_base.py # MongoDB基类
│
├── proxy/ # 代理管理
│ ├── proxy_ip_pool.py # IP池管理
│ ├── proxy_mixin.py # 代理刷新混入
│ └── providers/ # 代理提供商
│
├── cache/ # 缓存系统
│ ├── abs_cache.py # 缓存抽象类
│ ├── local_cache.py # 本地缓存
│ └── redis_cache.py # Redis缓存
│
├── tools/ # 工具模块
│ ├── app_runner.py # 应用运行管理
│ ├── browser_launcher.py # 浏览器启动
│ ├── cdp_browser.py # CDP浏览器管理
│ ├── crawler_util.py # 爬虫工具
│ └── async_file_writer.py # 异步文件写入
│
├── model/ # 数据模型
│ └── m_{platform}.py # Pydantic模型
│
├── libs/ # JS脚本库
│ └── stealth.min.js # 反检测脚本
│
└── cmd_arg/ # 命令行参数
└── arg.py # 参数定义
```
---
## 4. 核心模块详解
### 4.1 爬虫基类体系
```mermaid
classDiagram
class AbstractCrawler {
<>
+start()* 启动爬虫
+search()* 搜索功能
+launch_browser() 启动浏览器
+launch_browser_with_cdp() CDP模式启动
}
class AbstractLogin {
<>
+begin()* 开始登录
+login_by_qrcode()* 二维码登录
+login_by_mobile()* 手机号登录
+login_by_cookies()* Cookie登录
}
class AbstractStore {
<>
+store_content()* 存储内容
+store_comment()* 存储评论
+store_creator()* 存储创作者
+store_image()* 存储图片
+store_video()* 存储视频
}
class AbstractApiClient {
<>
+request()* HTTP请求
+update_cookies()* 更新Cookies
}
class ProxyRefreshMixin {
+init_proxy_pool() 初始化代理池
+_refresh_proxy_if_expired() 刷新过期代理
}
class XiaoHongShuCrawler {
+xhs_client: XiaoHongShuClient
+start()
+search()
+get_specified_notes()
+get_creators_and_notes()
}
class XiaoHongShuClient {
+playwright_page: Page
+cookie_dict: Dict
+request()
+pong() 检查登录状态
+get_note_by_keyword()
+get_note_by_id()
}
AbstractCrawler <|-- XiaoHongShuCrawler
AbstractApiClient <|-- XiaoHongShuClient
ProxyRefreshMixin <|-- XiaoHongShuClient
```
### 4.2 爬虫生命周期
```mermaid
sequenceDiagram
participant Main as main.py
participant Factory as CrawlerFactory
participant Crawler as XiaoHongShuCrawler
participant Browser as Playwright/CDP
participant Login as XiaoHongShuLogin
participant Client as XiaoHongShuClient
participant Store as StoreFactory
Main->>Factory: create_crawler("xhs")
Factory-->>Main: crawler实例
Main->>Crawler: start()
alt 启用IP代理
Crawler->>Crawler: create_ip_pool()
end
alt CDP模式
Crawler->>Browser: launch_browser_with_cdp()
else 标准模式
Crawler->>Browser: launch_browser()
end
Browser-->>Crawler: browser_context
Crawler->>Crawler: create_xhs_client()
Crawler->>Client: pong() 检查登录状态
alt 未登录
Crawler->>Login: begin()
Login->>Login: login_by_qrcode/mobile/cookie
Login-->>Crawler: 登录成功
end
alt search模式
Crawler->>Client: get_note_by_keyword()
Client-->>Crawler: 搜索结果
loop 获取详情
Crawler->>Client: get_note_by_id()
Client-->>Crawler: 笔记详情
end
else detail模式
Crawler->>Client: get_note_by_id()
else creator模式
Crawler->>Client: get_creator_info()
end
Crawler->>Store: store_content/comment/creator
Store-->>Crawler: 存储完成
Main->>Crawler: cleanup()
Crawler->>Browser: close()
```
### 4.3 平台爬虫实现结构
每个平台目录包含以下核心文件:
```
media_platform/{platform}/
├── __init__.py # 模块导出
├── core.py # 爬虫主实现类
├── client.py # API客户端
├── login.py # 登录实现
├── field.py # 字段/枚举定义
├── exception.py # 异常定义
├── help.py # 辅助函数
└── {特殊实现}.py # 平台特定逻辑
```
### 4.4 三种爬虫模式
| 模式 | 配置值 | 功能描述 | 适用场景 |
|------|--------|---------|---------|
| 搜索模式 | `search` | 根据关键词搜索内容 | 批量获取特定主题内容 |
| 详情模式 | `detail` | 获取指定ID的详情 | 精确获取已知内容 |
| 创作者模式 | `creator` | 获取创作者所有内容 | 追踪特定博主/UP主 |
---
## 5. 数据存储层
### 5.1 存储架构图
```mermaid
classDiagram
class AbstractStore {
<>
+store_content()*
+store_comment()*
+store_creator()*
}
class StoreFactory {
+STORES: Dict
+create_store() AbstractStore
}
class CsvStoreImplement {
+async_file_writer: AsyncFileWriter
+store_content()
+store_comment()
}
class JsonStoreImplement {
+async_file_writer: AsyncFileWriter
+store_content()
+store_comment()
}
class DbStoreImplement {
+session: AsyncSession
+store_content()
+store_comment()
}
class SqliteStoreImplement {
+session: AsyncSession
+store_content()
+store_comment()
}
class MongoStoreImplement {
+mongo_base: MongoDBStoreBase
+store_content()
+store_comment()
}
class ExcelStoreImplement {
+excel_base: ExcelStoreBase
+store_content()
+store_comment()
}
AbstractStore <|-- CsvStoreImplement
AbstractStore <|-- JsonStoreImplement
AbstractStore <|-- DbStoreImplement
AbstractStore <|-- SqliteStoreImplement
AbstractStore <|-- MongoStoreImplement
AbstractStore <|-- ExcelStoreImplement
StoreFactory --> AbstractStore
```
### 5.2 存储工厂模式
```python
# 以抖音为例
class DouyinStoreFactory:
STORES = {
"csv": DouyinCsvStoreImplement,
"db": DouyinDbStoreImplement,
"json": DouyinJsonStoreImplement,
"sqlite": DouyinSqliteStoreImplement,
"mongodb": DouyinMongoStoreImplement,
"excel": DouyinExcelStoreImplement,
}
@staticmethod
def create_store() -> AbstractStore:
store_class = DouyinStoreFactory.STORES.get(config.SAVE_DATA_OPTION)
return store_class()
```
### 5.3 存储方式对比
| 存储方式 | 配置值 | 优点 | 适用场景 |
|---------|--------|-----|---------|
| CSV | `csv` | 简单、通用 | 小规模数据、快速查看 |
| JSON | `json` | 结构完整、易解析 | API对接、数据交换 |
| SQLite | `sqlite` | 轻量、无需服务 | 本地开发、小型项目 |
| MySQL | `db` | 性能好、支持并发 | 生产环境、大规模数据 |
| MongoDB | `mongodb` | 灵活、易扩展 | 非结构化数据、快速迭代 |
| Excel | `excel` | 可视化、易分享 | 报告、数据分析 |
---
## 6. 基础设施层
### 6.1 代理系统架构
```mermaid
flowchart TB
subgraph Config["配置"]
enable["ENABLE_IP_PROXY"]
provider["IP_PROXY_PROVIDER"]
count["IP_PROXY_POOL_COUNT"]
end
subgraph Pool["代理池管理"]
pool["ProxyIpPool"]
load["load_proxies()"]
validate["_is_valid_proxy()"]
get["get_proxy()"]
refresh["get_or_refresh_proxy()"]
end
subgraph Providers["代理提供商"]
kuaidl["快代理
KuaiDaiLiProxy"]
wandou["万代理
WanDouHttpProxy"]
jishu["技术IP
JiShuHttpProxy"]
end
subgraph Client["API客户端"]
mixin["ProxyRefreshMixin"]
request["request()"]
end
enable --> pool
provider --> Providers
count --> load
pool --> load
load --> validate
validate --> Providers
pool --> get
pool --> refresh
mixin --> refresh
mixin --> Client
request --> mixin
```
### 6.2 登录流程
```mermaid
flowchart TB
Start([开始登录]) --> CheckType{登录类型?}
CheckType -->|qrcode| QR[显示二维码]
QR --> WaitScan[等待扫描]
WaitScan --> CheckQR{扫描成功?}
CheckQR -->|是| SaveCookie[保存Cookie]
CheckQR -->|否| WaitScan
CheckType -->|phone| Phone[输入手机号]
Phone --> SendCode[发送验证码]
SendCode --> Slider{需要滑块?}
Slider -->|是| DoSlider[滑动验证]
DoSlider --> InputCode[输入验证码]
Slider -->|否| InputCode
InputCode --> Verify[验证登录]
Verify --> SaveCookie
CheckType -->|cookie| LoadCookie[加载已保存Cookie]
LoadCookie --> VerifyCookie{Cookie有效?}
VerifyCookie -->|是| SaveCookie
VerifyCookie -->|否| Fail[登录失败]
SaveCookie --> UpdateContext[更新浏览器上下文]
UpdateContext --> End([登录完成])
```
### 6.3 浏览器管理
```mermaid
flowchart LR
subgraph Mode["启动模式"]
standard["标准模式
Playwright"]
cdp["CDP模式
Chrome DevTools"]
end
subgraph Standard["标准模式流程"]
launch["chromium.launch()"]
context["new_context()"]
stealth["注入stealth.js"]
end
subgraph CDP["CDP模式流程"]
detect["检测浏览器路径"]
start["启动浏览器进程"]
connect["connect_over_cdp()"]
cdpContext["获取已有上下文"]
end
subgraph Features["特性"]
f1["用户数据持久化"]
f2["扩展和设置继承"]
f3["反检测能力增强"]
end
standard --> Standard
cdp --> CDP
CDP --> Features
```
### 6.4 缓存系统
```mermaid
classDiagram
class AbstractCache {
<>
+get(key)* 获取缓存
+set(key, value, expire)* 设置缓存
+keys(pattern)* 获取所有键
}
class ExpiringLocalCache {
-_cache: Dict
-_expire_times: Dict
+get(key)
+set(key, value, expire_time)
+keys(pattern)
-_is_expired(key)
}
class RedisCache {
-_client: Redis
+get(key)
+set(key, value, expire_time)
+keys(pattern)
}
class CacheFactory {
+create_cache(type) AbstractCache
}
AbstractCache <|-- ExpiringLocalCache
AbstractCache <|-- RedisCache
CacheFactory --> AbstractCache
```
---
## 7. 数据模型
### 7.1 ORM模型关系
```mermaid
erDiagram
DouyinAweme {
int id PK
string aweme_id UK
string aweme_type
string title
string desc
int create_time
int liked_count
int collected_count
int comment_count
int share_count
string user_id FK
datetime add_ts
datetime last_modify_ts
}
DouyinAwemeComment {
int id PK
string comment_id UK
string aweme_id FK
string content
int create_time
int sub_comment_count
string user_id
datetime add_ts
datetime last_modify_ts
}
DyCreator {
int id PK
string user_id UK
string nickname
string avatar
string desc
int follower_count
int total_favorited
datetime add_ts
datetime last_modify_ts
}
DouyinAweme ||--o{ DouyinAwemeComment : "has"
DyCreator ||--o{ DouyinAweme : "creates"
```
### 7.2 各平台数据表
| 平台 | 内容表 | 评论表 | 创作者表 |
|------|--------|--------|---------|
| 抖音 | DouyinAweme | DouyinAwemeComment | DyCreator |
| 小红书 | XHSNote | XHSNoteComment | XHSCreator |
| 快手 | KuaishouVideo | KuaishouVideoComment | KsCreator |
| B站 | BilibiliVideo | BilibiliVideoComment | BilibiliUpInfo |
| 微博 | WeiboNote | WeiboNoteComment | WeiboCreator |
| 贴吧 | TiebaNote | TiebaNoteComment | - |
| 知乎 | ZhihuContent | ZhihuContentComment | ZhihuCreator |
---
## 8. 配置系统
### 8.1 核心配置项
```python
# config/base_config.py
# 平台选择
PLATFORM = "xhs" # xhs, dy, ks, bili, wb, tieba, zhihu
# 登录配置
LOGIN_TYPE = "qrcode" # qrcode, phone, cookie
SAVE_LOGIN_STATE = True
# 爬虫配置
CRAWLER_TYPE = "search" # search, detail, creator
KEYWORDS = "编程副业,编程兼职"
CRAWLER_MAX_NOTES_COUNT = 15
MAX_CONCURRENCY_NUM = 1
# 评论配置
ENABLE_GET_COMMENTS = True
ENABLE_GET_SUB_COMMENTS = False
CRAWLER_MAX_COMMENTS_COUNT_SINGLENOTES = 10
# 浏览器配置
HEADLESS = False
ENABLE_CDP_MODE = True
CDP_DEBUG_PORT = 9222
# 代理配置
ENABLE_IP_PROXY = False
IP_PROXY_PROVIDER = "kuaidaili"
IP_PROXY_POOL_COUNT = 2
# 存储配置
SAVE_DATA_OPTION = "json" # csv, db, json, sqlite, mongodb, excel
```
### 8.2 数据库配置
```python
# config/db_config.py
# MySQL
MYSQL_DB_HOST = "localhost"
MYSQL_DB_PORT = 3306
MYSQL_DB_NAME = "media_crawler"
# Redis
REDIS_DB_HOST = "127.0.0.1"
REDIS_DB_PORT = 6379
# MongoDB
MONGODB_HOST = "localhost"
MONGODB_PORT = 27017
# SQLite
SQLITE_DB_PATH = "database/sqlite_tables.db"
```
---
## 9. 工具模块
### 9.1 工具函数概览
| 模块 | 文件 | 主要功能 |
|------|------|---------|
| 应用运行器 | `app_runner.py` | 信号处理、优雅退出、清理管理 |
| 浏览器启动 | `browser_launcher.py` | 检测浏览器路径、启动浏览器进程 |
| CDP管理 | `cdp_browser.py` | CDP连接、浏览器上下文管理 |
| 爬虫工具 | `crawler_util.py` | 二维码识别、验证码处理、User-Agent |
| 文件写入 | `async_file_writer.py` | 异步CSV/JSON写入、词云生成 |
| 滑块验证 | `slider_util.py` | 滑动验证码破解 |
| 时间工具 | `time_util.py` | 时间戳转换、日期处理 |
### 9.2 应用运行管理
```mermaid
flowchart TB
Start([程序启动]) --> Run["run(app_main, app_cleanup)"]
Run --> Main["执行 app_main()"]
Main --> Running{运行中}
Running -->|正常完成| Cleanup1["执行 app_cleanup()"]
Running -->|SIGINT/SIGTERM| Signal["捕获信号"]
Signal --> First{第一次信号?}
First -->|是| Cleanup2["启动清理流程"]
First -->|否| Force["强制退出"]
Cleanup1 & Cleanup2 --> Cancel["取消其他任务"]
Cancel --> Wait["等待任务完成
(超时15秒)"]
Wait --> End([程序退出])
Force --> End
```
---
## 10. 模块依赖关系
```mermaid
flowchart TB
subgraph Entry["入口层"]
main["main.py"]
config["config/"]
cmdarg["cmd_arg/"]
end
subgraph Core["核心层"]
base["base/base_crawler.py"]
platforms["media_platform/*/"]
end
subgraph Client["客户端层"]
client["*/client.py"]
login["*/login.py"]
end
subgraph Storage["存储层"]
store["store/"]
database["database/"]
end
subgraph Infra["基础设施"]
proxy["proxy/"]
cache["cache/"]
tools["tools/"]
end
subgraph External["外部依赖"]
playwright["Playwright"]
httpx["httpx"]
sqlalchemy["SQLAlchemy"]
motor["Motor/MongoDB"]
end
main --> config
main --> cmdarg
main --> Core
Core --> base
platforms --> base
platforms --> Client
client --> proxy
client --> httpx
login --> tools
platforms --> Storage
Storage --> sqlalchemy
Storage --> motor
client --> playwright
tools --> playwright
proxy --> cache
```
---
## 11. 扩展指南
### 11.1 添加新平台
1. 在 `media_platform/` 下创建新目录
2. 实现以下核心文件:
- `core.py` - 继承 `AbstractCrawler`
- `client.py` - 继承 `AbstractApiClient` 和 `ProxyRefreshMixin`
- `login.py` - 继承 `AbstractLogin`
- `field.py` - 定义平台枚举
3. 在 `store/` 下创建对应存储目录
4. 在 `main.py` 的 `CrawlerFactory.CRAWLERS` 中注册
### 11.2 添加新存储方式
1. 在 `store/` 下创建新的存储实现类
2. 继承 `AbstractStore` 基类
3. 实现 `store_content`、`store_comment`、`store_creator` 方法
4. 在各平台的 `StoreFactory.STORES` 中注册
### 11.3 添加新代理提供商
1. 在 `proxy/providers/` 下创建新的代理类
2. 继承 `BaseProxy` 基类
3. 实现 `get_proxy()` 方法
4. 在配置中注册
---
## 12. 快速参考
### 12.1 常用命令
```bash
# 启动爬虫
python main.py
# 指定平台
python main.py --platform xhs
# 指定登录方式
python main.py --lt qrcode
# 指定爬虫类型
python main.py --type search
```
### 12.2 关键文件路径
| 用途 | 文件路径 |
|------|---------|
| 程序入口 | `main.py` |
| 核心配置 | `config/base_config.py` |
| 数据库配置 | `config/db_config.py` |
| 爬虫基类 | `base/base_crawler.py` |
| ORM模型 | `database/models.py` |
| 代理池 | `proxy/proxy_ip_pool.py` |
| CDP浏览器 | `tools/cdp_browser.py` |
---
*文档生成时间: 2025-12-18*