如果不包含某些字符串,则替换某些子值?还是重写 XPATH 查询?网站抓取

Posted

技术标签:

【中文标题】如果不包含某些字符串,则替换某些子值?还是重写 XPATH 查询?网站抓取【英文标题】:Replace certain Child value if doesn't contain certain string? or Rewrite XPATH query? Website scrape 【发布时间】:2021-05-30 13:08:53 【问题描述】:

前言:这是我编写的第一个 XPath 和 DOM 脚本。

以下代码在一定程度上有效。

如果应该是 price 的 child->nodevalue 为空,它会丢弃其余元素,然后从那里滚雪球。我花了好几个小时阅读、重写,却想不出办法来解决它。

我认为我的 XPath 查询可能是问题所在,因为我不知道如何测试这是正确的子值。

我正在抓取的内容看起来像这样(实际上它看起来不像这样,每个产品都有 148 行 html,但这些是相关的):

<div class="some really long class name">
    <h2 class="second class">
        <a class="a-link-normal s-no-outline" href="TheURLINeed.php">
            <span class="a-size-base-plus a-color-base a-text-normal">
                The Title I Need
            </span>
        </a>
    </h2>
    <span class="a-offscreen">
      $1,000,000
    </span>
</div>

这是我正在使用的代码。

    $html =file_get_contents('http://localhost:8888/scraper/source.html');

    $doc = new \DOMDocument();
    $doc->loadHTML($html);
    $xpath = new \DOMXpath($doc);
    $xpath->preserveWhiteSpace = FALSE;

    $nodes= $xpath->query("//a[@class = 'a-link-normal s-no-outline'] | //span[@class = 'a-size-base-plus a-color-base a-text-normal'] | //span[@class = 'a-price']");

    $data =[];
    foreach ($nodes as $node) 
        $url =  $node->getAttribute('href');
        if(trim($url,"\xc2\xa0 \n \t \r") != '')
            array_push($data,$url);
        
        foreach ($node->childNodes as $child) 
            if (trim($child->nodeValue, "\xc2\xa0 \n \t \r") != '') 
                array_push($data, $child->nodeValue);
            
        
    
    $chunks = (array_chunk($data, 4));

    foreach($chunks as $chunk) 
        $newarray = [
            'url' => $chunk[0],
            'title' => $chunk[1],
            'todaysprice' => $chunk[2],
            'hiddenprice' => $chunk[3]
            ];

    echo '<p>' . $newarray['url'] . '<br>' . $newarray['title'] . '<br>' .                 
    $newarray['todaysprice'] . '</p>';

输出:

URL
Title
Price

URL
Title
Price

URL
Title
URL.   <---- "Price was missing so it used the next child node value and now everything from here down is wrong."

Title
Price
URL

我知道这段代码离右边很远,但我必须从某个地方开始。

【问题讨论】:

您能否编辑您的问题并添加一个示例,其中缺少价格以及两种情况下预期的确切输出? 它就在那里,在输出下,请参阅底部部分,它说 PRICE WAS MISSING 所以它使用了下一个孩子。并且没有价格的产品只是将 span a-offscreen 留空。 我看到了;我指的是一个缺少价格的输入示例(即另一个&lt;div&gt; 元素)。知道它长什么样会很有用。 他们只是将 完全排除在 html 之外。 我认为这就是我需要更改查询的原因...拉取周围 div 的内容,在示例中,检查包含 price 的跨度,如果不存在则跳到下一个....我想!就像我说的那样,我对此很陌生。 【参考方案1】:

如果我对您的理解正确,您可能正在寻找类似下面的内容。为了简单起见,我跳过了数组构建部分,只是回显了目标数据。

所以假设您的 html 如下所示:

$html = '
<body>
<div class="some really long class name">
    <h2 class="second class">
        <a class="a-link-normal s-no-outline" href="TheURLINeed.php">
            <span class="a-size-base-plus a-color-base a-text-normal">
                The Title I Need
            </span>
        </a>
    </h2>
    <span class="a-offscreen">
      $1,000,000
    </span>
</div>
<div class="some really long class name">
    <h2 class="second class">
        <a class="a-link-normal s-no-outline" href="TheURLINeed2.php">
            <span class="a-size-base-plus a-color-base a-text-normal">
                The other Title I Need
            </span>
        </a>
    </h2>
   
</div>
<div class="some really long class name">
    <h2 class="second class">
        <a class="a-link-normal s-no-outline" href="TheURLINeed3.php">
            <span class="a-size-base-plus a-color-base a-text-normal">
                The Final Title I Need
            </span>
        </a>
    </h2>
    <span class="a-offscreen">
      $2,000,000
    </span>
</div>
</body>
';

试试这个:

$doc = new DOMDocument();
$doc->loadHTML($html);

$xpath = new DOMXpath($doc);
$data = $xpath->query('//h2[@class="second class"]');

foreach($data as $datum)
    echo trim($xpath->query('.//a/@href',$datum)[0]->nodeValue),"\r\n";
    echo trim($xpath->query('.//a/span',$datum)[0]->nodeValue),"\r\n";
    #$price = $xpath->query('./following-sibling::span',$datum);
    #EDITED
    $price = $xpath->query('./following-sibling::span[@class="a-offscreen"]',$datum);
    if ($price->length>0) 
    echo trim($price[0]->nodeValue), "\r\n";
 else 
    echo("No Price"),"\r\n";
    

   
echo "\r\n";
;

输出:

TheURLINeed.php
The Title I Need
$1,000,000

TheURLINeed2.php
The other Title I Need
No Price

TheURLINeed3.php
The Final Title I Need
$2,000,000

【讨论】:

天哪,太接近了!!!!我可以使用一个类来获取价格吗,因为在实际价格之前有几个空跨度......我认为这并不重要,所以我把它们排除在外,不知道兄弟姐妹的事情...... @MelissaBean 是的,你可以。请参阅标记为 EDITED 的行。 好吧,我想我可以从这里得到它......它仍然是空的,但是有很多代码行要经过我开始认为我错过了介于两者之间的东西。 8 行文本 148 行....啊!顺便说一句,跟随兄弟姐妹可以链接吗?例如 ./following-sibling/following-sibling::?在这一页之后,我还有另一页要解析……如果我活得那么久,还有头发。 @MelissaBean 是的,follow-sibling 是可链接的,但我不会滥用它太多......该代码确实适用于答案中的示例 html,所以实际中必须有一些东西html 不同并导致错误的输出。 有...我发现 2 个 div 标签在将其格式化为可读的东西时错过了。实际上,我必须重写原始查询并从最外面的 div 开始,并从该 div 块中按类获取子节点。它现在 100% 有效,我确实赞成你的回答,因为它引导我走上通往完美结局的正确道路!谢谢!!

以上是关于如果不包含某些字符串,则替换某些子值?还是重写 XPATH 查询?网站抓取的主要内容,如果未能解决你的问题,请参考以下文章

用于检查字符串是不是不应包含某些单词的正则表达式,但如果这些单词前面有“to”或“for”,则这些单词是可以的

如果包含某些字符串 postgres 则拆分文本

如果网站 URL 不包含任何语言代码,则执行某些操作

用另一个字符替换字符串中的某些字符

替换不需要的字符时如何防止某些单词一起运行?

SSL 2058_字符串编辑_字符串