DOMDocument是PHP解析HTML表格最稳妥方案,但需预处理编码、包裹div、关闭空白符保留,并用XPath或childNodes获取th/td;colspan/rowspan需手动展开为稀疏矩阵以匹配人眼视图。
DOMDocument 是 PHP 里最稳妥的起点,但直接用它转数组容易漏掉 th、跳过空行、崩在 malformed HTML 上,也默认不处理 colspan 和 rowspan。别急着写正则,先看这几个关键点。
DOMDocument 加载 HTML 时总报 Warning 或结果为空根本原因是 loadHTML() 会自动补全不规范结构(比如缺 <html> 或 <body>),同时触发 libxml 的警告。这些警告不中断执行,但会让 $dom->getElementsByTagName('table') 找不到东西。
解决方法很简单:
@ 抑制警告(仅开发期临时用):@$dom->loadHTML($html)
mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8') 统一编码,再补一层 <div> 包裹,避免根节点冲突$dom->preserveWhiteSpace = false,否则 nodeValue 会混入大量换行和空格getElementsByTagName('td') 为什么拿不到 th?getElementsByTagName() 只认一个标签名,'td' 和 'th' 是分开的。硬写两次再合并,容易错位——尤其当某行是 <tr><th>A</th><td>B</td></tr> 这种混合结构时。
立即学习“前端免费学习笔记(深入)”;
正确做法是用 XPath 或组合查询:
$row->getElementsByTagName('*'),再过滤 nodeName === 'td' || nodeName === 'th'
$row->childNodes 遍历所有子节点,判断 nodeType === XML_ELEMENT_NODE 且 nodeName 匹配getElementsByTagName(['td','th']) —— PHP 不支持数组参数,会直接报错colspan="2" 就少一列?原始 DOM 不做单元格“展开”,colspan="2" 的 <td> 在数组里仍只占一个位置,但视觉上它横跨两列。如果目标是导出 CSV 或渲染对齐表格,这就导致列数错乱。
手动填充逻辑要满足两个前提:
th/td,累加 colspan 值)colspan 向右填值,跳过已被占用的位置(用二维数组标记已写)rowspan 同理,但需跨行维护“当前列占用状态”,比 colspan 多一层状态管理简单场景下可跳过填充,只记录原始结构;真要导出,建议用现成逻辑如 getTableData() 函数(JS 端)或封装好的 PHP 类,自己实现容易在边界 case(如 rowspan 超出行数)崩溃。
别。正则解析 HTML 是反模式,哪怕只是提取表格。你看到的“能跑”的正则代码,基本都假设:
<td> 和 </td> 在同一行,且中间没换行符 )、没 JS 动态插入内容一旦网页来自真实爬虫或 CMS 输出,这些假设立刻失效。DOM 解析慢一点,但稳定;正则快一点,但上线后第一张含 data-* 属性的表格就挂。
真正该省时间的地方,是提前剪裁 HTML:用 preg_match('/<table[^>]*?>.*?</table>/is', $html, $match) 先捞出 table 片段,再交给 DOMDocument,比整个页面解析快得多。
复杂点不在怎么取文本,而在怎么定义“一行一列”——colspan 和 rowspan 让行列关系变成稀疏矩阵,而多数业务只要“人眼看到的表格形状”。这时候,宁可多花 20 行代码模拟渲染逻辑,也不要妥协成“能跑就行”的扁平数组。