如果不包含某些字符串,则替换某些子值?还是重写 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 留空。 我看到了;我指的是一个缺少价格的输入示例(即另一个<div>
元素)。知道它长什么样会很有用。
他们只是将 完全排除在 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 查询?网站抓取的主要内容,如果未能解决你的问题,请参考以下文章