网页内容提取的痛点
目前给 LLM 平台提供网页提取或者搜索功能的 API 一般依赖于 Playwright 或 Puppeteer 等技术。这些技术十分强大,能够完美处理动态网页,但也带来了一个显著的问题:过于笨重。
它们通常要求在使用时下载体积庞大的独立完整浏览器二进制文件,在运行时也需要启动完整的浏览器进程。对于一套仅仅用来抓取文本的后端服务来说,这不仅占用了较多的磁盘存储和执行内存,在不同环境部署时也显得有些麻烦。
更为棘手的问题在于跨架构的支持。笔者同时担任着 Arch Linux for Loong64 的维护者,在适配 LoongArch 架构时深有体会。这其实是双重的挑战:首先,像 Playwright 这样的工具本身在 LoongArch 下从源码构建就困难重重,笔者至今也没有成功构建出其稳定可用的版本;其次,它们在运行时强依赖于上游官方预编译发布的 Chromium 等独立浏览器二进制文件,而官方并没有提供针对 LoongArch 等非主流架构的打包分支,这让常规的方法很困难。
在这样的背景下,笔者开发了 qt-web-extractor 项目。项目的核心目标是打造一个简单、易用、轻量且真正跨平台的通用网页内容提取工具。在 Linux、Windows、macOS 在内的各平台上都能轻松部署运行,不再受限于强绑定的独立浏览器二进制文件;同时,它也顺带完美解决了前文所述的跨指令集架构难题——可以直接使用发行版提供的 Qt WebEngine 库。
为什么选择 Qt WebEngine
既然需要一个能解析 JavaScript、执行客户端动态渲染并且高度跨平台的轻量级替代方案,Qt WebEngine 成为了极佳的选择。
Qt WebEngine 本质上是 Chromium 的封装,前端渲染和 JS 执行能力与现代浏览器完全一致。它本身就是一个极其成熟及通用的跨平台基础构件,只需引入对应的 Python 绑定包 PySide6,即可直接作为轻量的提取引擎工作,免去了繁琐的额外配置。
而在 Linux 平台下,它还额外带来了得天独厚的优势:作为非常通用的基础 GUI 依赖,从 x86 到 LoongArch、RISC-V 等各种指令集的分支,几乎所有的主流发行版都已经把它在软件仓库中打包集成好了。如果在 Linux 下使用,它可以直接复用系统的动态库,无需再去第三方服务器下载动辄好几百兆的 Chromium 内核。只要用常规的包管理器备齐环境,部署本项目几乎不会带来任何额外的存储占用开销。
Qt Web Extractor 简介
Qt Web Extractor 是一个基于 Qt WebEngine 和 Qt PDF 实现的通用网页内容提取工具。它通过 Qt 的 offscreen 模式实现无头运行,不需要显示器或显卡参与渲染,专门用于解决提取那些依赖 JavaScript、由客户端动态加载渲染的现代网页内容,弥补普通 HTTP 请求无法执行 JS 的短板。
项目仅依赖于 PySide6 与 Qt6 WebEngine 模块,方便部署。
核心特性
- 全面的 JavaScript 渲染支持:对于常见的单页应用或客户端渲染构建的页面,普通的 requests 纯 HTTP 请求只能获取基础的 HTML 代码。本项目会等待页面渲染完毕,返回包含实际完整内容的纯文本或 DOM 代码。
- 多种使用接口:提供命令行工具、Python 模块 API,以及内置的 HTTP REST API 服务。
- 通用的 HTTP API:服务端常驻后台后,能为各类 AI 平台、监控脚本等提供统一的页面与文本获取服务。同时,它还开箱即用支持被配置为 Open WebUI 的外部网页加载器,源码目录中也包含了作为对话自定义工具引用的脚本。
- 原生 PDF 解析:这个扩展特性针对的是一个非常影响现实体验的痛点。之前笔者发现在 Open WebUI 中,如果 LLM 使用 Open WebUI 自带的默认提取器去调取一个 PDF 类型的链接,会把 PDF 的二进制格式文件直接拉下来,然后当成文本直接塞到对话的上下文中。这可以说是一场灾难,模型不仅获取其中的有效信息,还会浪费巨量 Token。而在本机提取中,遇到 PDF 文件时,可以直接利用与 Qt WebEngine 搭配的 Qt PDF 库将文件中的真正可读文本层解析、提取并返回,完美解决了这个十分影响用户体验的痛点。
- 部署极简:依赖简洁且不需要独立下载浏览器,提供 systemd 服务文件和基于 AUR 的部署方式,安装和后台启停都非常方便。
使用方式展示
常驻 HTTP 服务
工具最常见的使用方式是作为后端的公共常驻服务。项目内置了 HTTP 服务器:
qt-web-extractor serve --host 127.0.0.1 --port 8766 --api-key mysecretkey
启动以后,它就可以作为一个通用的 REST API 供其他程序调用。例如在 Open WebUI 的管理后台中,将 Web Loader Engine 设置为 external,填写这个地址和配置好的 API Key。此后环境中所有的网页阅读、数据拉取都会交由它进行渲染分析。因为能执行 JS 的缘故,它自然也可以顺利加载更多的网页(比如通过简单 HTTP 访问不能获取的知乎、Hugging Face 等等),并且能在应对含有弹窗或单页路由的页面时获取到渲染后的实际 DOM 文本。
命令行工具
通过命令行可以直接快速提取目标源并将结果输出到终端:
# 纯文本提取
python -m qt_web_extractor https://example.com
# 输出 JSON 格式
python -m qt_web_extractor --json https://example.com
# 提取渲染后的 HTML 代码
python -m qt_web_extractor --html https://example.com
# 解析 PDF 文本
python -m qt_web_extractor https://example.com/document.pdf
Python 代码调用
项目本身也是一个标准的 Python 包:
from qt_web_extractor import QtWebExtractor
extractor = QtWebExtractor(timeout_ms=30000)
result = extractor.extract("https://example.com")
print(result.text) # 提取经过渲染的网页纯文本
print(result.html) # 提取渲染后的 HTML
工具引擎在主线程运行 Qt 的事件循环,通过后台线程处理 HTTP 接口。面对每次请求,会在网页完成加载后再给出一定的缓冲时间保证 JS 执行完毕,确保提取的是最终视图数据。
总结
Qt Web Extractor 通过系统自带的 Qt WebEngine 来进行加载和提取,既保留了执行现代前端框架必备的 Chromium 核心能力,又规避了平台架构支持的局限和额外的存储烦恼。
如果你也面临特殊指令集的部署难题或者厌倦了总是要下载臃肿的浏览器环境,可以尝试一下这个极简的方案。在 Arch Linux 上可以通过 AUR 直接安装包。
项目仓库地址:GitHub · Qt Web Extractor
项目协议:GPL-3.0-or-later