基于python和edge浏览器的网页批量保存方法探索

如题。

前段时间为了帮助老师完成一个批量存储网页的任务,借助codex探索了一下批量下载网页和批量网页转PDF的功能。

原理

网页(HTML)转PDF有好几条技术路线。

一种路线是使用pandoc 这个软件做转换。pandoc是一个文档格式中转站,可以在markdown/docx/latex/pdf/epub/… 等等上百种格式之间来回转换。对于HTML转PDF,pandoc内部会先将HTML翻译为latex,随后调用外部的latex编译器(texlive,tinytex,mactex等等)将latex源码编译为PDF。这条路线最为“极客”,可以流程化、自动化处理,灵活性很高,但对latex编译器有要求,很容易因为latex不兼容而编译出错或字符乱码。

另一种路线是浏览器自带的“工具→打印→打印为PDF”。现代的主流浏览器都支持。但是问题在于,大多数情况下我们需要手动去浏览器里点击这些按钮完成打印(劳动密集型工作说是)。

那么,如何在一个自动化流程中自动化的做这件事呢?

幸运的是,chromium系浏览器(包括chrome,Microsoft edge,以及许多国产“极速/高速/快速/安全/……”浏览器)支持这一点。Chromium 内核支持“无头模式”(--headless),也就是在不启动软件界面的前提下在命令行和后台渲染网页和实现一些功能。

具体怎么做?下面是代码

一个示例代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import subprocess
from pathlib import Path
EDGE = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
def convert_to_pdf(html_url,pdf_path) -> bool:
args = [
EDGE,
"--headless=new",
"--disable-gpu",
"--window-size=2560,1440",
"--no-first-run",
"--no-pdf-header-footer",
"--no-sandbox",
"--virtual-time-budget=2000",
f"--print-to-pdf={pdf_path}",
html_url,
]
#cmd = " ".join(args)
#print(cmd)
subprocess.run(
args,
timeout=120,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
return pdf_path.exists() and pdf_path.stat().st_size > 0

if __name__ == "__main__":
html_url = "https://wz.anoms.top/" # 这里填写网站url
pdf_path = Path("./ANOMS_blog.pdf").resolve() # 必须用.resolve()方法转为绝对路径
print("Convert result:",convert_to_pdf(html_url,pdf_path))

这里的EDGE变量存储了edge浏览器的安装路径。读者朋友的电脑上这个路径可能不一样,可以根据实际情况替换为实际的edge浏览器或者chrome浏览器的路径。

args参数这一栏,就是调用无头模式edge/chromium浏览器所需要的参数。其中最重要的是”–headless=new”,以及输入的pdf path和网站url。

需要注意的是,pdf path需要用绝对路径,否则浏览器在转换时会报错。

另外也需要注意一下VPN/Proxy设置,有时候网站打印失败,可能是因为挂着梯子导致网站访问出现异常。

上述代码的运行效果:

1
2
H:\temp>python demo.py
Convert result: True

image.png

如果还想要更加精细的调整(例如改变页面尺寸、隐藏或修改某个元素),可能就需要把网站html源代码+css样式表+资源文件全下载下来,然后hack进去修改html和css源码了——那是更深层次的工作。

只就“自动化保存网页为PDF”这一项,目前的代码已经能够很好的工作了。如果需要批量下载,那么在主函数里增加一个url列表即可。