You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用XPath获取子段落内容并合并为单字符串?PHP实现遇阻

解决PHP DOM获取指定div下所有p标签文本的问题

我看你遇到的问题主要出在两个关键地方:一是XPath的class匹配逻辑不够严谨,二是全局查询所有目标p标签后用索引对应$facts的方式容易出错,毕竟没法保证两组查询的结果数量完全对应上。咱们一步步来修正:

首先,修正XPath的class匹配逻辑

你原来用contains(@class, 'b-list-fact__item-explanation js-fact-explanation')的写法有隐患——如果目标元素的class属性里这两个类的顺序变了,或者多了其他类,这个匹配就会失效。正确的写法应该是用空格包裹类名,确保匹配完整的类:

// 精准匹配同时包含两个类的div
$divs = $finder->query("//div[contains(concat(' ', normalize-space(@class), ' '), ' b-list-fact__item-explanation ') and contains(concat(' ', normalize-space(@class), ' '), ' js-fact-explanation ')]");

然后,针对每个div单独获取内部p标签的文本

不要全局查询所有p标签,而是遍历每个匹配到的div,再在这个div的上下文里查询p标签,这样能保证每个div对应的p文本都能正确收集,然后合并成单个字符串:

完整示例代码

$html = file_get_contents('https://...');
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
$dom = new DOMDocument;
@$dom->loadHTML($html);
$finder = new DomXPath($dom);

// 先匹配所有目标div
$divs = $finder->query("//div[contains(concat(' ', normalize-space(@class), ' '), ' b-list-fact__item-explanation ') and contains(concat(' ', normalize-space(@class), ' '), ' js-fact-explanation ')]");

$dataArr = [];
// 遍历每个div,收集并合并内部p标签的文本
foreach ($divs as $div) {
    $ps = $finder->query(".//p", $div);
    $mergedText = '';
    foreach ($ps as $p) {
        // 去除每个p文本的首尾空白后拼接
        $mergedText .= trim($p->textContent) . ' ';
    }
    // 最后清理整体多余空格
    $mergedText = trim($mergedText);
    $dataArr[] = $mergedText;
}

// 如果你还要关联原来的$facts标题,建议在对应上下文查询(假设标题和解释div是关联节点)
$facts = $finder->query("//a[contains(concat(' ', normalize-space(@class), ' '), ' b-list-fact__item-text ')]");
foreach ($facts as $fact) {
    $factText = trim(str_replace("\n", " ", $fact->textContent));
    $dataArr[] = $factText;
    
    // 获取当前标题对应的解释div(假设是标题的下一个兄弟节点,可根据实际结构调整)
    $relatedDiv = $finder->query("./following-sibling::div[contains(concat(' ', normalize-space(@class), ' '), ' b-list-fact__item-explanation ')]", $fact)->item(0);
    if ($relatedDiv) {
        $ps = $finder->query(".//p", $relatedDiv);
        $mergedText = '';
        foreach ($ps as $p) {
            $mergedText .= trim($p->textContent) . ' ';
        }
        $dataArr[] = trim($mergedText);
    }
}

为什么之前的写法失效?

  • 你的XPath匹配class的方式不够健壮,容易因为class属性的顺序变化、额外类的添加导致匹配不到目标div
  • 全局查询所有p标签后用$long_fact[$key]对应$facts条目,一旦两组结果数量不匹配(比如有的div无p标签、有的条目无对应div),就会出现索引错误或获取错误文本
  • 当你用//p/text()查询时,返回的是文本节点集合而非元素节点,调用textContent会出错,应该直接取nodeValue

内容的提问来源于stack exchange,提问作者Ricardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:05:47