技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

hQuery.php:用正则挑战 libxml 的 PHP 网页抓取库

项目背景与痛点

在 PHP 生态里解析 HTML 一直是个尴尬活。官方路线是 DOMDocument 或 SimpleXML,底层都走 libxml2:校验严格、内存开销大,碰到混乱的页面就抛一堆 warning,严重时干脆拒绝解析。于是大量项目用 libxml_use_internal_errors(true) 兜底,再把整棵 DOM 塞进内存。抓几十 KB 的页面还好,批量跑几万页时,解析开销经常比网络请求本身还大。

另一条路是用正则硬啃,简单场景够用,一旦要处理嵌套结构就迅速失控。

hQuery.php 恰好卡在中间:零扩展依赖,用纯 PHP 正则做词法切分,自己维护一个栈来建树,再配一套 jQuery 风格的 CSS 选择器。README 里“解析 MB 级非法 HTML 只需一眨眼”并非营销话术——它省掉的正是 libxml 的严格校验和完整 DOM 的数据结构成本。

核心技术揭秘

hQuery 的整个流程可以概括为“先切分、再建树、后查询”,全程不追求真正的 DOM 语义。

graph TD A[原始 HTML 字符串] --> B[预处理:编码转换、去除冗余空白] B --> C[正则词法切分] C --> D[标签、文本、注释、CDATA 流] D --> E[栈式构建节点树] E --> F[hQuery_Element 根节点] F --> G{"查询请求"} G -->|"标签 / 类 / ID"| H[逐层遍历匹配] G -->|"属性 / 伪类"| I[结果集过滤] H --> J[hQuery_ElementList] I --> J J --> K[提取 attr / text / html]

关键设计有三点:

  1. 正则词法切分。把 HTML 当纯字符串,用一组精心构造的正则切成标签、文本、注释等 token。相比 libxml 的完整 tokenizer,这里只做“识别边界”一件事,不做合法性校验,因此能轻松处理各种畸形标签。
  2. 栈式建树与隐式闭合。维护一个节点栈:开标签压栈、闭标签出栈。针对最常见的非法 HTML——<p>、<li>、<td> 未闭合——采用隐式闭合策略:遇到同层块级标签时就地补齐闭合动作。这正是它比 DOMDocument 更能容忍真实网页的关键。
  3. 轻量节点对象。每个节点只保留标签名、属性数组、子节点和父指针,不维护命名空间、DTD、样式表等冗余信息,内存占用远低于 libxml 构建的树。

选择器引擎则是自研的:find() 从根节点遍历,把 CSS 选择器拆成若干约束逐层过滤,结果封装成 hQuery_ElementList,支持链式调用和常见的伪类、属性选择器。

hQuery 的取舍非常明确:放弃“完全正确”,换取“足够快且足够稳”。

功能亮点与差异

和同类方案相比,hQuery 的差异集中在前两项差异上:

  • 对比 DOMDocument 系(含 symfony/dom-crawler):hQuery 不做严格校验,非法 HTML 不抛异常;内存峰值更低;无扩展依赖,在共享主机或精简容器里也能跑。
  • 对比纯正则爬虫:它有真正的树结构和选择器引擎,能从根节点开始查询任意深度的元素,正则方案的脆弱性被大幅削弱。
  • 对比 Python 的 BeautifulSoup / lxml:跨语言比较意义有限,但 hQuery 的 API 更贴近 jQuery,迁移成本低。
  • 内置能力:字符集转换、URL 抓取封装(hQuery_Cached 支持带缓存的请求)、链式提取属性与文本,这些在同类轻量库里往往要自己拼。

应用场景与落地建议

适合的场景:中等规模的页面抓取、SEO 与内容抽取、模板数据提取、RSS/聚合源生成、把脏 HTML 转成结构化数组的 ETL 脚本。

不太适合:需要严格 HTML5 语义或 DOM 规范的场景(例如要做 DOM diff、要跟浏览器行为完全一致的解析)。正则解析在 <script>、<style>、CDATA、注释嵌套等边界上永远存在灰色地带。

落地建议:

  • 用真实语料做回归测试,重点覆盖未闭合标签、错误的嵌套层级和自闭合标签。
  • 如果已有基于 DOMDocument 的代码,切换前务必做结果对比,不要假设两者等价。
  • 大文件场景注意内存:hQuery 是全量解析,复杂度仍是 O(n),不要以为“快”就等于“流式”。
  • 生产环境加一层超时与大小上限保护,避免恶意页面拖垮进程。

综合评价

优点:解析速度快、内存友好、零依赖,对非法 HTML 的容错能力是真实痛点上的真实解法;API 设计贴近 jQuery,上手成本极低;PHP 5.3+ 的兼容性让它在老系统里也能直接用。

缺点:基于正则的解析在极端边界下不如 libxml 可靠;复杂选择器的查询性能会随 DOM 规模下降;项目维护节奏偏慢,文档以 README 为主,遇到冷门问题需要读源码。

一句话总结:如果你要的不是一棵“正确”的 DOM 树,而是一次“够快、够稳、够省”的结构化抽取,hQuery.php 值得放进工具箱。

关于

GitHub 原始描述(英文)

An extremely fast web scraper that parses megabytes of invalid HTML in a blink of an eye. PHP5.3+, no dependencies.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
518
价值分
237
活跃状态
活跃

语言占比

HTML
JavaScript
PHP
Shell