90 lines
4.3 KiB
Markdown
90 lines
4.3 KiB
Markdown
# 网页文章离线下载
|
||
|
||
使用 uv 管理 Python 环境和依赖(Python 3.10 或更新版本)。将 `download_article.py` 与 `requirements.txt` 放在同一个目录,并确保已安装 uv。
|
||
|
||
## 安装与运行
|
||
|
||
在这两个文件所在目录打开终端,执行:
|
||
|
||
```sh
|
||
uv run --no-project --python 3.12 --with-requirements requirements.txt python download_article.py 'https://mp.weixin.qq.com/s/Jcu2J5YlaMdxbAUgLMd56A'
|
||
```
|
||
|
||
uv 会自动准备 Python 3.12 和所需依赖,无需手动创建或激活虚拟环境。后续运行相同命令即可复用缓存。依赖继续通过 `requirements.txt` 管理,无需创建 `pyproject.toml`。
|
||
|
||
默认在**运行命令时的当前目录**创建文章目录,也可以用 `-o /你的/保存目录` 指定父目录。
|
||
|
||
```text
|
||
当前目录/
|
||
└── 文章标题/
|
||
├── 文章标题.md
|
||
├── image001.png
|
||
└── image002.jpg
|
||
```
|
||
|
||
图片后缀按实际文件内容判断;同一地址的图片只下载一次。正文中的图片引用使用相对路径,离线阅读时请保留整个目录。支持微信的延迟加载图片和行内 CSS 背景图,保留常见的标题、段落、列表、链接、表格等 Markdown 格式;公众号的复杂视觉排版不会原样复刻。
|
||
|
||
Markdown 开头不添加原文链接和作者/公众号信息,文章末尾统一追加 `来源:公众号作者,如有侵权,请联系删除。`。无法获取公众号作者时使用“未知作者”。接口返回的 `source_url` 仍保留,方便调用方追踪来源。
|
||
|
||
文件名中系统不允许的字符会替换为 `_`,过长标题会截短。已有同名目录时创建 `文章标题 (2)/文章标题 (2).md`,不会覆盖已有内容。
|
||
|
||
## 其他任务通过命令行调用
|
||
|
||
```sh
|
||
uv run --no-project --python 3.12 --with-requirements requirements.txt python download_article.py 'https://mp.weixin.qq.com/s/Jcu2J5YlaMdxbAUgLMd56A' --json
|
||
```
|
||
|
||
也可以从标准输入读取单个 JSON 请求:
|
||
|
||
```sh
|
||
printf '%s' '{"url":"https://mp.weixin.qq.com/s/Jcu2J5YlaMdxbAUgLMd56A","output_root":".","timeout":30,"allow_missing_images":false}' | uv run --no-project --python 3.12 --with-requirements requirements.txt python download_article.py --stdin-json
|
||
```
|
||
|
||
每次进程处理一个网址。JSON 模式下,标准输出只有一个 JSON 对象,路径均为绝对路径。调用方应解析 JSON,不要依赖错误消息的具体文字。
|
||
|
||
成功返回退出码 `0`:
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"title": "文章标题",
|
||
"source_url": "https://example.com/article",
|
||
"directory": "/完整路径/文章标题",
|
||
"markdown": "/完整路径/文章标题/文章标题.md",
|
||
"images": ["/完整路径/文章标题/image001.png"],
|
||
"warnings": []
|
||
}
|
||
```
|
||
|
||
失败返回退出码 `1`:
|
||
|
||
```json
|
||
{"ok": false, "error": "错误说明", "error_type": "ArticleDownloadError"}
|
||
```
|
||
|
||
命令行参数格式错误由 argparse 返回退出码 `2`,说明写入标准错误。`--stdin-json` 使用 JSON 中的参数,不使用其他命令行下载选项。
|
||
|
||
## 其他 Python 任务直接调用
|
||
|
||
将脚本放入调用方的 Python 模块搜索路径,并在调用方的 uv 环境中安装本脚本 `requirements.txt` 所列依赖后:
|
||
|
||
```python
|
||
from download_article import save_article
|
||
|
||
result = save_article(
|
||
url="https://mp.weixin.qq.com/s/Jcu2J5YlaMdxbAUgLMd56A",
|
||
output_root=".",
|
||
timeout=30,
|
||
allow_missing_images=False,
|
||
)
|
||
saved_directory = result.directory # 已保存文件所在目录(绝对路径字符串)
|
||
print(saved_directory)
|
||
# 完整结果可调用 result.to_dict()
|
||
```
|
||
|
||
函数失败时抛出异常,调用方可自行捕获。默认任何图片失败都会终止保存并清理半成品。若只希望尽量保存正文,可传 `allow_missing_images=True` 或命令行添加 `--allow-missing-images`,失败图片会替换为文字提示,详情写入 `warnings`。
|
||
|
||
微信可能返回验证、登录或失效页面,脚本会报告未找到正文,不会绕过访问限制。普通网页使用 article/main/body 提取,不适用于必须执行 JavaScript 才出现正文的页面。原文中的外链仍需联网,文章文字及成功下载的图片可离线查看。
|
||
|
||
如果接口对外提供服务,请由调用方限制网址及重定向目的地,只允许可信站点;此脚本本身允许访问运行机器能连接的 HTTP 地址。
|