【问题标题】:$domxpath->query - Table Contents$domxpath->query - 表内容
【发布时间】:2023-03-07 19:39:02
【问题描述】:

大约有两天我收到了使用 DOM 文档而不是正则表达式的建议

我还是不知道如何正确使用查询

在下面的链接中是会话“TERRITÓRIO E AMBIENTE”,我想获取下面这4行的内容

https://cidades.ibge.gov.br/brasil/sp/sao-paulo/panorama

$html = file_get_contents( 'https://cidades.ibge.gov.br/brasil/sp/sao-paulo/panorama' );    
            $document = new DOMDocument();              
            $document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
            $domxpath = new DOMXPath($document);
            $paragraphs = $domxpath->query('
                //th[*[
                        contains(text(), "TERRITÓRIO E AMBIENTE")
                      ]
                    ]
                /following-sibling::tr[
                        position() = 12 
                    ]'
            );

我输入了 12 <tr> 的数量,因为这是源代码中出现的内容,但我不知道我是否正确执行此查询,这对我来说出现了这些错误

Warning: DOMDocument::loadHTML(): Tag app invalid in Entity, line: 25 
Warning: DOMDocument::loadHTML(): Misplaced DOCTYPE declaration in Entity, line: 25
Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 25 

谢谢

【问题讨论】:

    标签: php domdocument domxpath


    【解决方案1】:

    您的代码中有几个问题。

    • 您从该网站获得的 HTML 无效,因此您需要忽略错误(通常不建议这样做,但在这种情况下我认为可以)。

    @$document->loadHTML($html);
    
    • 您要查找的文本是小写的(由于其样式,它以大写显示),因此您需要对其进行规范化或将文本设为小写
    • 你的方法(生第 12 个孩子)太脆弱了。我稍微检查了代码,很难让它不那么脆弱,但我认为这很接近:

    //th[contains(text(), "Território e Ambiente")]/parent::tr/following-sibling::tr[1]/td[3]
    

    得到一个包含文本Território e Ambienteth元素,然后得到父标签tr,然后转到下一个tr兄弟,最后得到第三个td元素(其中值为)。仍然非常脆弱,但要密切关注网站的变化,它不太可能改变。

    所以现在您需要再重复该 XPath 查询 3 次,更改第 n 个 tr 兄弟(添加两个,因为每个中间都有一个空元素)。它最终看起来像这样:

    $document = new DOMDocument();
    @$document->loadHTML($html);
    $domxpath = new DOMXPath($document);
    $paragraphs = $domxpath->query('//th[contains(text(), "Território e Ambiente")]/parent::tr/following-sibling::tr[1]/td[3]');
    echo "First: ".preg_replace('/\s+/', ' ', $paragraphs[0]->nodeValue);
    echo "<br>";
    $paragraphs = $domxpath->query('//th[contains(text(), "Território e Ambiente")]/parent::tr/following-sibling::tr[3]/td[3]');
    echo "Second: ".preg_replace('/\s+/', ' ', $paragraphs[0]->nodeValue);
    echo "<br>";
    $paragraphs = $domxpath->query('//th[contains(text(), "Território e Ambiente")]/parent::tr/following-sibling::tr[5]/td[3]');
    echo "Third: ".preg_replace('/\s+/', ' ', $paragraphs[0]->nodeValue);
    echo "<br>";
    $paragraphs = $domxpath->query('//th[contains(text(), "Território e Ambiente")]/parent::tr/following-sibling::tr[7]/td[3]');
    echo "Fourth: ".preg_replace('/\s+/', ' ', $paragraphs[0]->nodeValue);
    

    第一:1.521,110 平方公里
    第二:92,6 %
    第三:74,8 %
    第四:50,3 %

    注意使用preg_replace() 去除大量空白。

    使用更多的 XPath 魔法,我们可以让它只处理一个查询:

    //th[contains(text(), "Território e Ambiente")]/parent::tr/following-sibling::tr[position() mod 2 = 1]/td[3]
    

    与其他元素的工作方式相同,但不是获取特定的 tr 兄弟元素,而是获取其他所有元素。

    $paragraphs = $domxpath->query('//th[contains(text(), "Território e Ambiente")]/parent::tr/following-sibling::tr[position() mod 2 = 1]/td[3]');
    foreach ($paragraphs as $i => $p) {
        echo ($i + 1)." value: ".preg_replace('/\s+/', ' ', $p->nodeValue);
        echo "<br>";
    }
    

    【讨论】:

    • 再次完美运行,非常感谢@ishegg
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-09
    • 2016-02-24
    • 2020-04-19
    • 2014-08-19
    • 2018-05-23
    • 1970-01-01
    相关资源
    最近更新 更多