【问题标题】:solving the xpath property error even though xpath looks good解决 xpath 属性错误,即使 xpath 看起来不错
【发布时间】:2020-03-06 11:26:06
【问题描述】:

我尝试从网页中提取版本信息,但即使 XPath 在 HTML 页面上看起来不错,我也会收到错误消息。

我试过的代码是

use DOMDocument;
use DOMXPath;
function getVersionFromDownloads(string $url): string
{
    // support only windows
    $content = $this->fetch($url);
    $curl = curl_init($url);

    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);
    $content = curl_exec($curl);
    curl_close($curl);

    $dom = new DOMDocument();
    @$dom->loadHTML($content);

    $xpath = new DOMXPath($dom);

    $result = $xpath->query("//a[contains(text(),'paint.net')]");

    $header = $result->item(0)->textContent;
    echo $header;

}
getVersionFromDownloads('https://www.dotpdn.com/downloads/pdn.html');

想要的结果是4.2.10

当我签入 HTML 页面时,XPath 看起来不错,并且显示了正确的元素。但是当我试图提取文本内容时,它给出了一个错误。

错误给定语句:$header = $result->item(0)->textContent;

【问题讨论】:

  • dom 是否太大而无法在此处提供?可以var_dump($result->item(0));吗?
  • @mickmackusa 它给了NULL。 xpath->query 中似乎有一些东西。但在检查元素中它只显示正确的元素。
  • 我认为您的 curl/fetch 可能有问题。 3v4l.org/23HvD 作为开发人员,我们希望您能够隔离最早的损坏点。

标签: php xpath web-scraping


【解决方案1】:

在测试我的解决方案时,我在使用 $dom->load() 时遇到了很多 DOM 错误。您可以使用在线 html 验证器(例如 https://www.freeformatter.com/html-validator.html)查看所有无效标记。 这个程序咆哮着许多次要的弃用,然后是一些值得注意的项目,例如:

格式错误的字节序列:“a9”。

格式错误的字节序列:“ae”。

当我尝试使用 $dom->loadHTML() 编写自己的 php 代码时...

$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->load('https://www.dotpdn.com/downloads/pdn.html');
$xpath = new DOMXPath($dom);
return libxml_get_last_error();

我用var_export()将返回值打印到屏幕上来查看:

LibXMLError::__set_state(array( 'level' => 3, 'code' => 77, 'column' => 8, 'message' => 'tag html line 1 中的数据过早结束', 'file ' => 'https://www.dotpdn.com/downloads/pdn.html', 'line' => 153, ))


推荐

所以我决定不使用load(),而是尝试file_get_contents($url) 来获取源代码并将其提供给DOM 解析器。

function getVersionFromDownloads($url)
{
    $dom = new DOMDocument();
    $dom->loadHTML(file_get_contents($url));
    $xpath = new DOMXPath($dom);
    $text = $xpath->query("//a[contains(text(),'paint.net')]")->item(0)->textContent;
    return preg_replace('/paint\.net\s+/', '', $text);
}
var_export(getVersionFromDownloads('https://www.dotpdn.com/downloads/pdn.html'));

输出:

'4.2.10'
  • 要删除单引号,请使用echo 而不是var_export()。我只是用它来证明没有前导或尾随空格。

  • preg_replace() 在返回之前使用,以便删除字符串中的paint.net 后跟多个连续空格。

  • 作为记录,这种提取技术的工作原理相同:

     $xpath->query("//a[contains(text(),'paint.net')]/text()")->item(0)->nodeValue;
    
  • 在你的:

     function getVersionFromDownloads(string $url): string
    

    : string 要求从您的函数返回一个字符串值,但您只是在回显——请务必返回一个字符串值。

【讨论】:

    【解决方案2】:
     $result = explode(" ",trim($xpath->query("//b/a")[0]->nodeValue))[1];
    

    这就是你要找的吗?

    【讨论】:

    • 这绝对不是解决方案。 OP 并没有在查询中挣扎,而是在此之前获取 DOM。
    • 对检索到的 DOM 字符串正确使用 OP 的查询是可行的——所以问题不在于查询。即使这个答案确实解决了问题(它没有),它也不会清理它显然试图做的输出。证明:3v4l.org/tHWR6 加上这是一个纯代码的答案——所有答案都应该解释
    猜你喜欢
    • 1970-01-01
    • 2019-09-27
    • 1970-01-01
    • 2018-08-08
    • 2018-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多