从网页获取产品名称时遇到问题

Posted

技术标签:

【中文标题】从网页获取产品名称时遇到问题【英文标题】:Trouble getting the name of a product from a webpage 【发布时间】:2019-02-23 16:17:55 【问题描述】:

我用 php 编写了一个脚本来抓取位于网页右上角的产品的titletitle 显示为 Gucci

当我执行下面的脚本时,它给了我一个错误Notice: Trying to get property 'plaintext' of non-object in C:\xampp\htdocs\runcode\testfile.php on line 16

我如何才能从该网页中仅获取名称 Gucci

Link to the url

到目前为止我已经写了:

<?php
include "simple_html_dom.php";
$link = "https://www.farfetch.com//bd/shopping/men/gucci-rhyton-web-print-leather-sneaker-item-12964878.aspx"; 

function get_content($url)
    
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('User-Agent: Mozilla/5.0',));
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $htmlContent = curl_exec($ch);
        curl_close($ch);
        $dom = new simple_html_dom();
        $dom->load($htmlContent);
        $itemTitle = $dom->find('#bannerComponents-Container [itemprop="name"]', 0)->plaintext;
        echo "$itemTitle";
    
get_content($link);
?>

顺便说一句,我在脚本中使用的选择器完美无缺。

为了消除混淆,我从 页面源 复制了一大块 html 元素,这些元素既不是动态生成也不是 javascript 加密,所以我找不到任何理由curl 无法处理:

<div class="cdb2b6" id="bannerComponents-Container">
    <p class="_41db0e _527bd9 eda00d" data-tstid="merchandiseTag">New Season</p>
    <div class="_1c3e57">
        <h1 class="_61cb2e" itemProp="brand" itemscope="" itemType="http://schema.org/Brand">
            <a href="/bd/shopping/men/gucci/items.aspx" class="fd9e8e e484bf _4a941d f140b0" data-trk="pp_infobrd" data-tstid="cardInfo-title" itemProp="url" aria-label="Gucci">
                <span itemProp="name">Gucci</span>
            </a>
        </h1>
    </div>
</div>

后记:很遗憾,我不得不展示一个来自另一种语言的真实生活示例,以确保名称 Gucci 不是动态生成的,因为很少有 cmets 并且答案已经表明

以下脚本是用python编写的(使用无法处理动态内容的requests模块):

import requests
from bs4 import BeautifulSoup

url = "https://www.farfetch.com//bd/shopping/men/gucci-rhyton-web-print-leather-sneaker-item-12964878.aspx"

with requests.Session() as s:
    s.headers["User-Agent"] = "Mozilla/5.0"
    res = s.get(url)
    soup = BeautifulSoup(res.text,"lxml")
    item = soup.select_one('#bannerComponents-Container [itemprop="name"]').text
    print(item)

输出它产生:

Gucci

现在,很明显我要查找的内容是静态的。

请查看下图以识别我已经用铅笔标记的title

【问题讨论】:

$itemTitle = $dom-&gt;find('#bannerComponents-Container [itemprop="name"]', 0); 是否返回一个对象? 输入 HTML 的结构是什么?请将其包含在问题中。 试试[itemProp=name](由于某种原因大写P) 请查看编辑。为了清晰起见,我添加了一些材料。 【参考方案1】:

@tmadam 已经解决了这个问题,我只是想补充一点,今天没有充分的理由使用 simple_html_dom,似乎没有维护,开发在 2014 年停止,有很多未解决的错误报告,最重要的是,DOMDocument 和 DOMXPath 可以做到几乎所有 simple_html_dom 都可以并且得到维护,并且是 PHP 的一个集成部分,这意味着没有什么可以包含/捆绑到您的脚本中。用 DOMDocument 和 DOMXPath 解析它看起来像:

$htmlContent = curl_exec($ch);
curl_close($ch);
fclose($cookieFileh); // thanks to tmpfile(), this also deletes the cookie file.
$dom = @DOMDocument::loadHTML($htmlContent);
$xp=new DOMXPath($dom);
$itemTitle = $xp->query('//*[@id="bannerComponents-Container"]//*[@itemprop="name"]')->item(0)->textContent;
echo $itemTitle;

【讨论】:

如果我希望使用 css 选择器而不是 xpath 来满足您的上述方法,那么修改后的部分会是什么样子?感谢您的宝贵意见@hanshenrik。 @asmitu 对不起,afaik 没有任何内置的 PHP 支持 CSS - 但是如果你使用 Symfony,他们有这个CSS-to-xpath converter,在这种情况下你可以运行$converter = new Symfony\Component\CssSelector\CssSelectorConverter(); $itemTitle = $xp-&gt;query($converter-&gt;toXPath('#bannerComponents-Container [itemprop="name"]'))-&gt;item(0)-&gt;textContent; 【参考方案2】:

成功的 Python 脚本和 PHP 脚本的主要区别在于会话的使用。您的 PHP 脚本不使用 cookie,这会触发来自服务器的不同响应。

我们有两个选择:

    更改选择器。如Mark's answer 中所述,该项目仍在 html 上,但在不同的标记中。我们可以用这个选择器得到它:

    'a[itemprop="brand"]'
    

    使用 cookie。如果我们使用CURLOPT_COOKIESESSION 和一个临时文件来写入/读取cookie,我们可以获得与您的Python 脚本相同的响应。

    function get_content($url) 
        $cookieFileh = tmpfile();
        $cookieFile=stream_get_meta_data($cookieFileh)['uri'];
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');
        curl_setopt($ch, CURLOPT_COOKIESESSION, true);
        curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile); 
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //
        curl_setopt($ch, CURLOPT_ENCODING, "gzip");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_exec($ch);
        $htmlContent = curl_exec($ch);
        curl_close($ch);
        fclose($cookieFileh); // thanks to tmpfile(), this also deletes the cookie file.
        $dom = new simple_html_dom();
        $dom->load($htmlContent);
        $itemTitle = $dom->find('#bannerComponents-Container [itemprop="name"]', 0)->plaintext;
        echo "$itemTitle";
    
    
    $link = "https://www.farfetch.com/bd/shopping/men/gucci-rhyton-web-print-leather-sneaker-item-12964878.aspx"; 
    get_content($link);
    //Gucci
    

    这个脚本执行两个请求;第一个请求将 cookie 写入文件,第二个请求读取并使用它们。

    在这种情况下,服务器返回一个压缩响应,所以我使用CURLOPT_ENCODING 来解压缩内容。

    由于您仅使用标头来设置用户代理,因此最好使用 CURLOPT_USERAGENT 选项。

    我已将 CURLOPT_SSL_VERIFYPEER 设置为 false,因为我尚未设置证书,并且 CURL 无法使用 HTTPS。如果您可以与 HTTPS 站点通信,出于安全原因,最好不要使用此选项。如果没有,您可以使用CURLOPT_CAINFO 设置证书。

【讨论】:

你一直是我的救星。您的解决方案永远不会误入歧途。非常感谢。我有两个小问题: 1. 您的解决方案确实与Notice: tempnam(): file created in the system's temporary directory in C:\xampp\htdocs\runcode\testfile.php on line 5 这一行一起获得了正确答案。我怎样才能摆脱这个错误。 2.有什么方法可以让我使用php以编程方式获取page sourcehtml content,就像我们在python中使用res = requests.get(url) ; print(res.text)一样? 这不是错误,而是通知我们有关临时文件的通知。你可以用@ 压制它,例如:$cookieFile = @tempnam("/cookies", "CURLCOOKIE");。关于您的第二个问题,您可以直接回显响应内容,如果这就是您的意思,例如echo $htmlContent; 请查看this post 了解我获取源代码或html 内容的意思。我删除了该帖子,但现在为您取消删除。 顺便说一句,echoing $htmlContent; 我可以看到脚本只是打开了那个网页,就像我们在浏览器中打开一个网页而不是 html 的东西一样。你应该得到赏金。不过,只要它还活着,我们就等着吧。 好的,我想我明白你的意思了。您正在尝试在浏览器上打印 HTML 代码,对吗?问题在于,Web 浏览器旨在解释 HTML 代码,因此您只能看到文本。对不起,我不能帮你。但是让我搜索答案,如果我发现任何有用的信息,我会告诉你。 如果您无权访问 /cookies 文件夹会怎样?使用 tmpfile。除了特殊的临时文件夹(由 sys_get_temp_dir() 返回 - 但 tmpfile() 将负责为您定位文件夹并负责清理句柄关闭/或脚本终止时的文件。)【参考方案3】:

您的选择器确实可以在浏览器中使用,但是当您使用 curl 获取页面源时,您的选择器不存在。

尝试将卷曲的页面保存在终端中,您会发现页面结构与您在浏览器中看到的不同。

对于大多数现代网站来说都是如此,因为它们大量使用 Javascript,而 curl 不会为您运行 javascript。

我将 curl 结果保存到一个文件中,品牌信息如下所示:

&lt;a itemprop="brand" class="generic" data-tstid="Label_ItemBrand" href="/bd/shopping/men/gucci/items.aspx" dir="ltr"&gt;Gucci&lt;/a&gt;

【讨论】:

以上是关于从网页获取产品名称时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

我从所有 $Users 获取信息到邮件时遇到问题,只能从 1 台机器获取信息

在 UIAutomation 中从 UIAElementArray 中按名称获取元素时遇到问题

使用 AutoIt 从 iframe 获取表单名称

我在自动刷新网页内容时遇到问题

需求获取常见的方法是进行客户访谈,结合你的实践谈谈会遇到什么问题,你是怎么解决的?

第一次使用VS2013时遇到的问题