无法从网页上获取产品名称

时间:2018-09-19 13:13:50

标签: php curl web-scraping simple-html-dom

我已经用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加密的,因此我找不到任何理由卷曲无法处理:

<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,因为很少有评论,并且已经给出了答案

以下脚本是用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

enter image description here

3 个答案:

答案 0 :(得分:3)

@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;

答案 1 :(得分:2)

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

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

这对于大多数现代网站都是正确的,因为它们大量使用Javascript,而curl无法为您运行JavaScript。

我将卷曲结果保存到文件中,品牌信息如下:

<a itemprop="brand" class="generic" data-tstid="Label_ItemBrand" href="/bd/shopping/men/gucci/items.aspx" dir="ltr">Gucci</a>

答案 2 :(得分:2)

成功的Python脚本和PHP脚本之间的主要区别是会话的使用。您的PHP脚本不使用cookie,因此会触发服务器的不同响应。

我们有两个选择:

  1. 更改选择器。如Mark's answer中所述,该项目仍位于html上,但标签不同。我们可以使用以下选择器来获取它:

    'a[itemprop="brand"]'
    
  2. 使用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设置证书。