一、项目背景
1.1 需求来源
用户需要将 Milky Way Idle 游戏维基 的内容批量爬取并转换为 Markdown 格式,便于离线存档、本地阅读或二次加工。同时需支持 自动抓取站内链接,实现全站内容递归爬取,避免手动逐个页面处理的低效问题。
1.2 目标场景
- 离线文档库:将维基内容存档为 Markdown,用于本地知识库或团队协作。
- 内容迁移:为后续可能的内容迁移(如自建 Wiki、博客)提供标准化数据。
- 数据分析:通过爬取全站内容,分析游戏玩法、用户贡献等信息(扩展场景)。
二、功能需求
2.1 核心功能:页面爬取与格式转换
功能点 | 详细描述 |
---|---|
HTML 转 Markdown | - 支持标题(H1-H6)、段落、无序列表(UL/LI)、有序列表(OL/LI)的格式转换。 - 链接处理:将站内链接转为 Markdown 格式( [文本](链接) ),保留站外链接。- 过滤无关标签(如广告、导航栏、页脚),仅提取正文内容(典型容器为 <div class="mw-parser-output"> )。 |
站内链接解析 | - 提取页面中所有 站内链接(绝对路径或相对路径,如以/ 或https://milkywayidle.wiki.gg/ 开头的链接)。- 排除特殊链接:包含 Special: 、File: 、Category: 、Template: 等前缀的链接(此类多为维基元数据页面,非正文内容)。 |
递归爬取 | - 采用 广度优先搜索(BFS) 策略,从起始页面(如首页)开始,自动爬取所有站内链接指向的页面,避免重复抓取(使用链接去重集合)。 - 支持自定义爬取深度(默认无限制,可扩展为按层级限制,如仅爬取2层内链接)。 |
2.2 辅助功能:文件与链接管理
功能点 | 详细描述 |
---|---|
文件保存 | - 按页面标题或 URL 生成 Markdown 文件名(如Game_Overview.md ),保存至指定目录(支持自定义路径)。- 自动创建多级目录,避免文件覆盖(通过链接去重和文件名唯一化处理)。 |
链接去重 | - 使用全局集合记录已爬取的链接,避免重复请求和重复生成文件。 - 去重规则:精确匹配 URL(包括查询参数和锚点,如 /page?param=1 与/page 视为不同链接)。 |
异常处理 | - 处理网络请求超时、页面不存在(404)、服务器错误(500+)等异常,记录错误日志并跳过当前链接。 - 支持断点续爬:中断后可从上次未完成的链接继续爬取(需扩展数据库或文件记录爬取状态)。 |
2.3 输入输出要求
输入项 | 格式/示例 |
---|---|
起始 URL | 字符串,如https://milkywayidle.wiki.gg/ (支持单个页面或全站爬取)。 |
输出目录 | 本地文件路径,如./docs/ (自动创建不存在的目录)。 |
Markdown 格式 | 符合 CommonMark 规范,保留原页面结构(标题层级、列表嵌套),链接可直接访问(绝对路径)。 |
三、技术要求
3.1 技术选型
模块 | 技术/工具 |
---|---|
编程语言 | Python 3.8+(支持异步扩展,当前使用同步请求)。 |
HTTP 库 | requests (处理网络请求,支持自定义 User-Agent 和超时设置)。 |
HTML 解析 | BeautifulSoup4 (解析页面结构,提取标签和链接)。 |
链接队列 | collections.deque (实现 BFS 队列,高效处理待爬取链接)。 |
3.2 关键技术实现
3.2.1 链接处理逻辑
- 相对路径转绝对路径:
- 输入:
/Game_Overview
→ 输出:https://milkywayidle.wiki.gg/Game_Overview
。
- 输入:
- 去重规则:
- 使用全局集合
crawled_links
存储已处理的 URL,每次请求前检查是否已存在。
- 使用全局集合
- 过滤策略:
- 排除非正文链接(如编辑页面、文件页面),仅保留用户可阅读的内容页面。
3.2.2 Markdown 转换规则
HTML 标签 | Markdown 转换规则 |
---|---|
<h1>标题</h1> | # 标题 (H1 对应 1 个# ,H6 对应 6 个# )。 |
<p>段落</p> | 段落内容,前后空一行(\n\n )。 |
<ul><li>列表项</li></ul> | 无序列表,每行以- 开头。 |
<ol><li>列表项</li></ol> | 有序列表,每行以1. 、2. 等序号开头(根据层级自动编号)。 |
<a href="链接">文本</a> | [文本](链接) (站内链接转为绝对路径,站外链接保留原地址)。 |
3.3 项目代码结构
核心模块说明
模块文件 | 功能定位 | 依赖关系 |
---|---|---|
main.py | 程序入口,协调爬取流程,包含BFS队列管理和爬取任务调度 | 调用link_processor/file_manager/config |
link_processor.py | 链接处理核心,实现链接提取、绝对路径转换和有效性验证 | 依赖config的排除规则配置 |
file_manager.py | 文件存储管理,处理Markdown文件命名规则、目录创建和异常写入 | 独立模块,被main调用 |
config.py | 集中配置请求参数、日志格式、路径排除规则等运行时参数 | 被所有功能模块引用 |
md_converter.py | HTML到Markdown的转换引擎,实现标签转换和格式优化(当前版本1.0) | 依赖BeautifulSoup解析结果 |
模块调用关系
main.py
├── 初始化 → config.py(加载配置)
├── 爬取循环 → link_processor.py(提取新链接)
│ └── 有效链接 → file_manager.py(保存内容)
└── 异常处理 → config.py(记录日志)
3.3 Python 虚拟环境配置
- 安装
virtualenv
:
pip install virtualenv
- 创建虚拟环境:
virtualenv venv
- 激活虚拟环境:
source venv/bin/activate
- 安装依赖:
pip install requests beautifulsoup4
3.4 运行参数示例
python crawler.py --start_url https://milkywayidle.wiki.gg/ --output_dir ./docs/
3.5 调试技巧
在调试过程中,可以通过查看日志文件crawler.log
来排查问题。日志文件记录了爬取成功、失败、重复链接等信息,格式为:时间+URL+状态。
3.6 Docker 使用示例
- 构建 Docker 镜像:
docker build -t milkywayidle-wiki-crawler .
- 运行 Docker 容器:
docker run -v $(pwd)/docs:/app/docs milkywayidle-wiki-crawler
四、非功能需求
4.1 性能要求
- 爬取速度:单线程模式下,建议每页面间隔 1-2 秒(避免触发网站反爬机制)。
- 并发扩展:未来可支持多线程或异步爬取(需添加代理池和速率限制)。
4.2 稳定性与容错
- 重试机制:对网络超时的请求自动重试 3 次(间隔 5 秒)。
- 日志记录:记录爬取成功、失败、重复链接等信息,便于排查问题(日志格式:时间+URL+状态)。
4.3 合规性
- 遵守网站
robots.txt
协议(爬取前检查https://milkywayidle.wiki.gg/robots.txt
,避免爬取禁止的路径)。 - 控制爬取频率,避免对目标服务器造成负载压力(符合“君子协议”)。
五、验收标准
测试用例 | 预期结果 |
---|---|
单页面爬取 | - 生成正确的 Markdown 文件,包含标题、段落、列表、链接。 - 链接为绝对路径,可正常跳转。 |
全站递归爬取 | - 从首页开始,爬取所有站内正文页面(无重复)。 - 目录结构清晰,文件按标题或 URL 命名。 |
异常处理测试 | - 输入无效 URL 时,提示错误并跳过。 - 遇到 404 页面时,记录日志但不中断爬取。 |
格式兼容性 | - 生成的 Markdown 可在主流编辑器(如 Typora、VS Code)正常显示,无格式错乱。 |
六、风险与应对
风险点 | 应对措施 |
---|---|
反爬机制 | - 添加随机 User-Agent 池,模拟真实浏览器请求。 - 增加请求间隔,避免高频访问。 |
页面结构变化 | - 使用灵活的标签选择器(如通过类名mw-parser-output 定位正文,而非固定标签层级)。- 定期检查维基页面结构,更新解析规则。 |
链接无限递归 | - 添加爬取深度限制(如最大深度 3 层),或设置链接数量上限(如最多爬取 1000 个页面)。 |
七、后续扩展建议
- 增强格式支持:添加对表格、代码块、图片(下载并本地化路径)的转换功能。
- 增量爬取:仅更新新增或修改的页面,避免重复爬取历史内容(需记录页面最后更新时间)。
- 可视化界面:开发图形化工具(如 GUI 或 Web 界面),支持配置爬取参数、查看进度和日志。