断网也能看API文档?Python偷懒利器pywebcopy实战指南
最近在折腾CherryPy和Sanic这些Web框架的服务部署,偏偏网络不太稳定,每次查阅官方API文档都卡得让人心烦。当时脑子里就冒出一个想法:要是能把整个技术文档站点完整“拖”到本地离线查看就好了。
以前遇到这种需求,很多人可能会想到用wget或者手写复杂的爬虫逻辑去处理图片、CSS和JS文件的路径依赖。其实大可不必这么折腾。今天给大家分享一个专门解决这个痛点的Python利器:pywebcopy。
请在微信客户端打开
它最大的卖点就是“傻瓜式”操作。你给它一个链接,它不仅能把HTML扒下来,还会自动帮你下载网页里引用的图片、样式表和脚本,并且极其聪明地把原本的绝对路径统统重写成本地的相对路径。等它跑完,你双击本地的HTML文件,看到的排版和在线网页几乎一模一样。
它是怎么工作的?
为了让大家有个直观的了解,我画了一个简单的内部执行流程图。它的核心逻辑其实就是“抓取-解析-下载-重写”的闭环。
graph TDA[输入目标URL与本地存储路径] --> B[初始化全局配置]B --> C[下载目标网页的主HTML]C --> D[解析HTML的DOM树结构]D --> E{遇到资源标签?}E -- 是: img, link, script等 --> F[下载静态资源到本地]F --> G[将HTML中的原链接重写为本地相对路径]E -- 否: 外部网页链接 --> H[跳过或根据设定深度继续爬取]G --> I[重新组装并保存本地HTML]H --> II --> J[生成可离线完美浏览的网页]
废话不多说,直接上代码
要用它,第一步当然是安装。直接在终端敲:
pip install pywebcopy
场景一:单页克隆(适合保存单篇长文章或单页文档)
如果你只是想保存某个具体的页面,比如一篇写得很详细的技术博客,或者某个特定的说明页面,用 save_webpage 函数就够了。
from pywebcopy import save_webpage# 你想要克隆的页面地址target_url = 'https://cherrypy.dev/'# 下载内容存放的本地根目录download_dir = './offline_docs/'# 配置参数字典kwargs = {'bypass_robots': True, # 很多时候我们需要绕过robots.txt限制'project_name': 'cherrypy_home' # 这会成为你下载目录下的子文件夹名字}print("开始拉取单页面...")# 调用核心函数save_webpage(url=target_url,project_folder=download_dir,**kwargs)print("下载完成!去文件夹里看看吧。")
运行完这段代码后,你会发现在 offline_docs/cherrypy_home 目录下,不仅有 index.html,还有一个包含了所有静态资源的文件夹。双击打开,排版一点都没乱。
场景二:整站克隆(适合囤积官方文档或小型静态站)
这是它最强大的地方。比如我想把Sanic的整个英文文档站都缓存到本地,在高铁上慢慢看。这时候就需要用到 save_website,并且可以通过 config 模块做一些精细化的设置。
from pywebcopy import save_website, configtarget_url = 'https://sanic.dev/en/'download_dir = './offline_docs/'# 推荐写法:先设置全局配置config.setup_config(url=target_url,project_folder=download_dir,project_name='sanic_full_docs',bypass_robots=True,debug=True, # 开启debug能看到它到底在下载哪些碎文件open_in_browser=False, # 下载完后是否自动用浏览器打开delay=1, # 礼貌爬取,每次请求间隔1秒,别把人家服务器打挂了threaded=True # 开启多线程下载图片等资源,速度快很多)print("开始执行整站克隆,这可能需要一点时间...")# 执行整站下载save_website(url=target_url,project_folder=download_dir,project_name='sanic_full_docs',bypass_robots=True,debug=False,delay=None,threaded=False)print("整站打包完毕!")
场景三:更细粒度的控制(自己接管下载逻辑)
有时候官方封装的函数不能满足需求,比如你只想提取网页里的所有图片,或者想自己决定哪些链接该跟进,哪些该放弃。你可以直接实例化它底层的 WebPage 类。
from pywebcopy import WebPage, config# 初始化配置config.setup_config(url='https://example.com',project_folder='./custom_download/',project_name='my_custom_task')# 实例化WebPage对象wp = WebPage()# 加载并解析目标URLwp.get('https://example.com')# 这个时候,网页已经被解析成一棵树了# 我们可以直接查看它抓取到了哪些文件链接print("发现的图片资源:")for img in wp.images:print(img)print("\n发现的CSS文件:")for css in wp.css:print(css)# 如果你觉得没问题了,可以手动触发保存wp.save_complete()
避坑指南(说点实在的)
用了这段时间,我也摸清了它的一些脾气。写代码不能只说好话,这里的几个坑大家一定要注意:
动态渲染的网页它是搞不定的:pywebcopy 的底层是基于 requests 和 lxml 的。这意味着什么?如果目标网站是靠 Vue 或者 React 在浏览器端通过 JavaScript 异步渲染内容的(比如很多现代的单页应用 SPA),它抓下来的可能就是一个空壳 HTML。它没有内置无头浏览器(像 Playwright 或 Selenium 那样)来执行 JS 代码。
深不见底的网站慎用 save_website:如果你对着维基百科或者大型门户网站跑整站下载,你的硬盘可能会爆炸。它会顺着链接一直爬下去,所以一定要评估目标站点的大小。
路径乱码问题:有些不太规范的网站,其静态资源的 URL 带有大量奇怪的特殊字符或长参数,本地文件系统可能不支持这么长的文件名,偶尔会导致保存报错。
总的来说,如果你平时经常需要离线查阅技术文档,或者需要把某些传统静态网页整个打包归档,用它来替代手动另存为,能省下大量枯燥的体力活。稍微写个十几行脚本,让电脑自己去跑就行了。

夜雨聆风