Web Scrape Symfony2 - 不可能的挑战 - 爬虫解析
Web Scrape Symfony2 - Impossible Challenge - Crawler Parsing
(编辑:我仍然找不到解决这个问题的方法。$crawler
object 看起来很荒谬,我只是想解析它特定的 <td>
文本,这有多难?我不能 serialize()
整个爬虫 object 也不能将网页的整个源代码变成一个字符串,否则我只能解析它用困难的方式串起来。请帮忙。我觉得我已经在下面很好地描述了这个问题。)
下面我使用 Symfony、Goutte 和 DomCrawler 抓取网页。我一直试图通过其他问题来解决这个问题,但没有成功,但现在我将 post 我的所有代码尽可能简单明了。
我能够获取页面并获取我要查找的第一位数据。第一个是 url,它是从 javascript 打印出来的,位于带有 onclick
的 a
标签中,是一个长字符串,所以我使用 preg_match
筛选并得到我需要的东西。
我需要的下一位数据是 <td>
标签中的一些文本。问题是,此网页有 10-20 个不同的 <table>
标签,并且没有 id=""
或 class=""
标签,因此很难隔离。所以我想做的是搜索单词 "Event Title" 然后转到下一个同级 <td>
标记并提取它的 innerHtml,这将是实际标题。
问题是,对于第二部分,我似乎无法通过 $crawler
object 正确解析。我不明白,我之前在 $crawler
object 的 serialize()
版本上做了 preg_match
,但是对于下半部分我似乎无法正确解析.
$crawler = $client->request('GET', 'https://movies.randomjunk.com/events/EventServlet?ab=mov&eventId=154367');
$aurl = 'http://movies.randomjunk.com/r.htm?e=154367'; // event url beginning string
$gas = $overview->filter('a[onclick*="' . $aurl . '"]');
$string1 = serialize($gas->filter('a')->attr('onclick')); //TEST
$string1M = preg_match("/(?<=\')(.*?)(?=\')/", $string1, $finalURL);
$aString = $finalURL[0];
echo "<br><br>" . $aString . "<br><br>";
// IT WORKS UP TO HERE
// $title = $crawler->filterXPath('//td[. = "Event Title"]/following-sibling::td[1]')->each(funtion (Crawler $crawler, $i) {
// return $node->text();
// }); // No clue why, but this doesn't work.
$html = $overview->getNode(0)->ownerDocument->saveHTML();
$re = "/>Event\sTitle.*?<\/td>.*?<td>\K.*?(?=<\/td>)/s";
$str = serialize($html);
print_r($str);
preg_match_all($re, $str, $matches);
$gas2 = $matches[0];
echo "<pre>";
print_r($gas2);
echo "</pre>";
我的 preg_match
只是 returns 一个空数组。我认为搜索 $crawler
object 有问题,因为它由许多节点组成。我一直在尝试将其全部转换为 html,然后再转换为 preg_match
,但它只是拒绝工作。我做了几个 print_r
语句,它只是 returns 整个网页。
下面是爬虫 object 中的一些 html 示例:
{lots of other html and tables}
<table>
<tr>
<td>Title</td>
<td>The Harsh Face of Mother Nature</td>
<td>The Harsh Face of Mother Nature</td>
</tr>
.
.
</table>
{lots of other html and tables}
目标是解析整个页面/$crawler
object 并获得标题 "The Harsh Face of Mother Nature"。
我知道这一定是可能的,但任何人想要提供的唯一答案是 link 到 domcrawler 页面,此时我已经阅读了大约一千次。请帮忙。
好的,您可以在 :
中使用 class
<td class="mytitle">The Harsh Face of Mother Nature</td>
您将使用它来过滤您的抓取工具,以将所有标题放在一个数组中,如下所示:
$titles = $crawler->filter('td.mytitle')->extract(array('_text'));
其中 td.mytitle 是 css select 或 select td with mytitle class 并提取引用节点内文本的 _text。
比正则表达式更简单、更高效...
没有测试此代码,但它应该可以工作,您可以在此处获得更多帮助和有关爬虫的更多信息:
http://symfony.com/fr/doc/current/components/dom_crawler.html
鉴于上面的 html 片段,我能够得出以下的 XPath:
//table/tr/td[.='Title']/following-sibling::td[1]
您可以在 Here
使用您提供的 html 片段测试 XPath
$html = '<table><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr></table>';
$crawler = new Symfony\Component\DomCrawler\Crawler($html);
$query = "//table/tr/td[.='Event Title']/following-sibling::td[1]";
$crawler->filterXPath($query)->each(function($crawler, $i) {
echo $crawler->text() . PHP_EOL;
});
输出:
The Harsh Face of Mother Nature
The Harsh Face of Mother Nature
The Harsh Face of Mother Nature
更新:测试成功:
$html = '<html><table><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr></table><table><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr></table><table><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr></table></html>';
更新:从网站获得示例 html 后,我能够使用以下 XPath 解析内容:
//td[normalize-space(text()) = 'Event Title']/following-sibling::td[1]
真正的问题是 "Event Title" 左右的前导和尾随白色 space。
这里是这个问题的另一个答案。
use Weidner\Goutte\GoutteFacade;
use Symfony\Component\DomCrawler\Crawler;
$crawler = GoutteFacade::request('GET','http://localhost/php_notes.php');
// find the parent table
$table = $crawler->filter('table')->each(function($table){
$tdText = $table->filter('td')->each(function ($node){
$alike = $node->previousAll(); // calculate the elements of the same level above this element :Will return array containing the tags above this tag.
$elementTag = $alike->eq(0); // find the tag above this <td> tag.
if($elementTag->nodeName()=='td'){
if($elementTag->text()=='Title')
{
dump("Title Heading => ".$elementTag->text()); // Title
dd("Title Value => ".$node->text()); // The Harsh Face of Mother Nature
}
}
});
});
您需要对 Symfony\dom-crawler\Crawler.php 文件的 567 行进行一些更改。
public function nodeName()
{
if (!$this->nodes) {
return null;
// throw new \InvalidArgumentException('The current node list is empty.');
}
return $this->getNode(0)->nodeName;
}
(编辑:我仍然找不到解决这个问题的方法。$crawler
object 看起来很荒谬,我只是想解析它特定的 <td>
文本,这有多难?我不能 serialize()
整个爬虫 object 也不能将网页的整个源代码变成一个字符串,否则我只能解析它用困难的方式串起来。请帮忙。我觉得我已经在下面很好地描述了这个问题。)
下面我使用 Symfony、Goutte 和 DomCrawler 抓取网页。我一直试图通过其他问题来解决这个问题,但没有成功,但现在我将 post 我的所有代码尽可能简单明了。
我能够获取页面并获取我要查找的第一位数据。第一个是 url,它是从 javascript 打印出来的,位于带有 onclick
的 a
标签中,是一个长字符串,所以我使用 preg_match
筛选并得到我需要的东西。
我需要的下一位数据是 <td>
标签中的一些文本。问题是,此网页有 10-20 个不同的 <table>
标签,并且没有 id=""
或 class=""
标签,因此很难隔离。所以我想做的是搜索单词 "Event Title" 然后转到下一个同级 <td>
标记并提取它的 innerHtml,这将是实际标题。
问题是,对于第二部分,我似乎无法通过 $crawler
object 正确解析。我不明白,我之前在 $crawler
object 的 serialize()
版本上做了 preg_match
,但是对于下半部分我似乎无法正确解析.
$crawler = $client->request('GET', 'https://movies.randomjunk.com/events/EventServlet?ab=mov&eventId=154367');
$aurl = 'http://movies.randomjunk.com/r.htm?e=154367'; // event url beginning string
$gas = $overview->filter('a[onclick*="' . $aurl . '"]');
$string1 = serialize($gas->filter('a')->attr('onclick')); //TEST
$string1M = preg_match("/(?<=\')(.*?)(?=\')/", $string1, $finalURL);
$aString = $finalURL[0];
echo "<br><br>" . $aString . "<br><br>";
// IT WORKS UP TO HERE
// $title = $crawler->filterXPath('//td[. = "Event Title"]/following-sibling::td[1]')->each(funtion (Crawler $crawler, $i) {
// return $node->text();
// }); // No clue why, but this doesn't work.
$html = $overview->getNode(0)->ownerDocument->saveHTML();
$re = "/>Event\sTitle.*?<\/td>.*?<td>\K.*?(?=<\/td>)/s";
$str = serialize($html);
print_r($str);
preg_match_all($re, $str, $matches);
$gas2 = $matches[0];
echo "<pre>";
print_r($gas2);
echo "</pre>";
我的 preg_match
只是 returns 一个空数组。我认为搜索 $crawler
object 有问题,因为它由许多节点组成。我一直在尝试将其全部转换为 html,然后再转换为 preg_match
,但它只是拒绝工作。我做了几个 print_r
语句,它只是 returns 整个网页。
下面是爬虫 object 中的一些 html 示例:
{lots of other html and tables}
<table>
<tr>
<td>Title</td>
<td>The Harsh Face of Mother Nature</td>
<td>The Harsh Face of Mother Nature</td>
</tr>
.
.
</table>
{lots of other html and tables}
目标是解析整个页面/$crawler
object 并获得标题 "The Harsh Face of Mother Nature"。
我知道这一定是可能的,但任何人想要提供的唯一答案是 link 到 domcrawler 页面,此时我已经阅读了大约一千次。请帮忙。
好的,您可以在 :
中使用 class<td class="mytitle">The Harsh Face of Mother Nature</td>
您将使用它来过滤您的抓取工具,以将所有标题放在一个数组中,如下所示:
$titles = $crawler->filter('td.mytitle')->extract(array('_text'));
其中 td.mytitle 是 css select 或 select td with mytitle class 并提取引用节点内文本的 _text。
比正则表达式更简单、更高效...
没有测试此代码,但它应该可以工作,您可以在此处获得更多帮助和有关爬虫的更多信息:
http://symfony.com/fr/doc/current/components/dom_crawler.html
鉴于上面的 html 片段,我能够得出以下的 XPath:
//table/tr/td[.='Title']/following-sibling::td[1]
您可以在 Here
使用您提供的 html 片段测试 XPath$html = '<table><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr></table>';
$crawler = new Symfony\Component\DomCrawler\Crawler($html);
$query = "//table/tr/td[.='Event Title']/following-sibling::td[1]";
$crawler->filterXPath($query)->each(function($crawler, $i) {
echo $crawler->text() . PHP_EOL;
});
输出:
The Harsh Face of Mother Nature
The Harsh Face of Mother Nature
The Harsh Face of Mother Nature
更新:测试成功:
$html = '<html><table><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr></table><table><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr></table><table><tr><td>Event Title</td><td>The Harsh Face of Mother Nature</td><td>The Harsh Face of Mother Nature</td></tr></table></html>';
更新:从网站获得示例 html 后,我能够使用以下 XPath 解析内容:
//td[normalize-space(text()) = 'Event Title']/following-sibling::td[1]
真正的问题是 "Event Title" 左右的前导和尾随白色 space。
这里是这个问题的另一个答案。
use Weidner\Goutte\GoutteFacade;
use Symfony\Component\DomCrawler\Crawler;
$crawler = GoutteFacade::request('GET','http://localhost/php_notes.php');
// find the parent table
$table = $crawler->filter('table')->each(function($table){
$tdText = $table->filter('td')->each(function ($node){
$alike = $node->previousAll(); // calculate the elements of the same level above this element :Will return array containing the tags above this tag.
$elementTag = $alike->eq(0); // find the tag above this <td> tag.
if($elementTag->nodeName()=='td'){
if($elementTag->text()=='Title')
{
dump("Title Heading => ".$elementTag->text()); // Title
dd("Title Value => ".$node->text()); // The Harsh Face of Mother Nature
}
}
});
});
您需要对 Symfony\dom-crawler\Crawler.php 文件的 567 行进行一些更改。
public function nodeName()
{
if (!$this->nodes) {
return null;
// throw new \InvalidArgumentException('The current node list is empty.');
}
return $this->getNode(0)->nodeName;
}