无法从网页获取产品名称
Trouble getting the name of a product from a webpage
我在 php 中编写了一个脚本来抓取位于网页右上角的产品的 title
。 title
显示为 Gucci
.
当我执行下面的脚本时,它给我一个错误 Notice: Trying to get property 'plaintext' of non-object in C:\xampp\htdocs\runcode\testfile.php on line 16
。
我怎样才能从那个网页上只得到名字Gucci
?
到目前为止我写了:
<?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>
Post 脚本:非常可悲的是,我不得不展示另一种语言的真实示例以确保名称 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
。
您的选择器确实可以在浏览器中使用,但是当您使用 curl 获取页面源代码时,您的选择器不存在。
尝试在终端中保存卷曲的页面,您会发现页面结构与您在浏览器中看到的不同。
大多数现代网站都是如此,因为它们大量使用 Javascript 而 curl 不适合您 运行 javascript。
我将卷曲结果保存到一个文件中,品牌信息如下所示:
<a itemprop="brand" class="generic" data-tstid="Label_ItemBrand" href="/bd/shopping/men/gucci/items.aspx" dir="ltr">Gucci</a>
成功的 Python 脚本与 PHP 脚本的主要区别在于 session 的使用。您的 PHP 脚本不使用 cookie,这会触发来自服务器的不同响应。
我们有两个选择:
更改选择器。如 Mark's answer 中所述,该项目仍在 html 上,但在不同的标签中。我们可以用这个选择器得到它:
'a[itemprop="brand"]'
使用 cookie。如果我们使用 CURLOPT_COOKIESESSION
和 write/read 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 写入文件,第二个请求读取并使用它们。
在这种情况下,服务器 returns 压缩响应,所以我使用 CURLOPT_ENCODING
来解压缩内容。
由于您使用 headers 只是为了设置一个 user-agent,因此最好使用 CURLOPT_USERAGENT
选项。
我已将 CURLOPT_SSL_VERIFYPEER
设置为 false,因为我没有设置证书,并且 CURL
无法使用 HTTPS。如果您可以与 HTTPS 站点通信,出于安全原因最好不要使用此选项。如果没有,您可以使用 CURLOPT_CAINFO
设置证书。
@t.m.adam 已经解决了这个问题,我只是想补充一点,今天没有充分的理由使用 simple_html_dom,似乎没有维护,开发在 2014 年停止,有很多未解决的错误报告,并且最重要的是,DOMDocument 和 DOMXPath 几乎可以做 simple_html_dom 可以做的所有事情,并且得到维护,并且是 PHP 的一个组成部分,这意味着您的脚本 include/bundle 没有什么可做的。用 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;
我在 php 中编写了一个脚本来抓取位于网页右上角的产品的 title
。 title
显示为 Gucci
.
当我执行下面的脚本时,它给我一个错误 Notice: Trying to get property 'plaintext' of non-object in C:\xampp\htdocs\runcode\testfile.php on line 16
。
我怎样才能从那个网页上只得到名字Gucci
?
到目前为止我写了:
<?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>
Post 脚本:非常可悲的是,我不得不展示另一种语言的真实示例以确保名称 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
。
您的选择器确实可以在浏览器中使用,但是当您使用 curl 获取页面源代码时,您的选择器不存在。
尝试在终端中保存卷曲的页面,您会发现页面结构与您在浏览器中看到的不同。
大多数现代网站都是如此,因为它们大量使用 Javascript 而 curl 不适合您 运行 javascript。
我将卷曲结果保存到一个文件中,品牌信息如下所示:
<a itemprop="brand" class="generic" data-tstid="Label_ItemBrand" href="/bd/shopping/men/gucci/items.aspx" dir="ltr">Gucci</a>
成功的 Python 脚本与 PHP 脚本的主要区别在于 session 的使用。您的 PHP 脚本不使用 cookie,这会触发来自服务器的不同响应。
我们有两个选择:
更改选择器。如 Mark's answer 中所述,该项目仍在 html 上,但在不同的标签中。我们可以用这个选择器得到它:
'a[itemprop="brand"]'
使用 cookie。如果我们使用
CURLOPT_COOKIESESSION
和 write/read 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 写入文件,第二个请求读取并使用它们。
在这种情况下,服务器 returns 压缩响应,所以我使用
CURLOPT_ENCODING
来解压缩内容。由于您使用 headers 只是为了设置一个 user-agent,因此最好使用
CURLOPT_USERAGENT
选项。我已将
CURLOPT_SSL_VERIFYPEER
设置为 false,因为我没有设置证书,并且CURL
无法使用 HTTPS。如果您可以与 HTTPS 站点通信,出于安全原因最好不要使用此选项。如果没有,您可以使用CURLOPT_CAINFO
设置证书。
@t.m.adam 已经解决了这个问题,我只是想补充一点,今天没有充分的理由使用 simple_html_dom,似乎没有维护,开发在 2014 年停止,有很多未解决的错误报告,并且最重要的是,DOMDocument 和 DOMXPath 几乎可以做 simple_html_dom 可以做的所有事情,并且得到维护,并且是 PHP 的一个组成部分,这意味着您的脚本 include/bundle 没有什么可做的。用 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;