Web Scrape Symfony2 - 不可能的挑战 - 履带式解析

时间:2015-03-26 15:41:12

标签: php regex symfony web-scraping domcrawler

(编辑:我仍然没有办法解决这个问题。$crawler对象看起来很荒谬,我只是想为特定的<td>解析它文本,有多难?我不能serialize()整个爬虫对象,并将网页的整个源代码变成字符串,否则我就可以解决那个字符串。请帮忙。我觉得我已经很好地描述了这个问题,如下所示。)

下面我使用Symfony,Goutte和DomCrawler来抓取网页。我一直试图通过其他问题弄清楚这一点并没有成功,但现在我只是发布我的所有代码,以尽可能地直截了当。

我能够获取页面并获取我正在寻找的第一位数据。第一个是从javascript打印的网址,其中包含一个带有a的{​​{1}}标记,并且是一个长字符串,因此我使用onclick来筛选并获得正确的内容需要。

我需要的下一位数据是preg_match标记内的一些文字。问题是,此网页包含10-20个不同的<td>标记,并且没有<table>id=""标记,因此难以隔离。所以我想要做的就是搜索&#34;事件标题&#34; 然后转到下一个兄弟class=""标签并提取其中的内部HTML,这将是实际的标题。

问题在于,对于第二部分,我似乎无法通过<td>对象正确解析。我不明白,我之前在$crawler preg_match版本的serialize()版本上做了$crawler,但对于下半部分,我似乎无法正确解析。

$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只返回一个空数组。我认为搜索$crawler对象是一个问题,因为它由许多节点组成。我一直试图将它全部转换为html然后转换为preg_match,但它只是拒绝工作。我已经完成了一些print_r语句,它只返回整个网页。

以下是抓取器对象中某些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对象并获得标题&#34;大自然的严酷面孔&#34;

我知道这一定是可能的,但是任何人想要提供的唯一答案是指向domcrawler页面的链接,此时我已经阅读了大约一千次。请帮忙。

3 个答案:

答案 0 :(得分:1)

鉴于上面的html片段,我能够提出XPath:

//table/tr/td[.='Title']/following-sibling::td[1]

您可以使用提供的html片段在Here

测试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]

真正的问题是围绕“事件标题”的前导和尾随空格。

答案 1 :(得分:0)

好吧,你可以做的是在你的

中使用一个班级

<td class="mytitle">The Harsh Face of Mother Nature</td>

您将使用哪个来过滤您的抓取工具,以便在这样的数组中获取所有标题:

$titles = $crawler->filter('td.mytitle')->extract(array('_text'));

其中td.mytitle是一个css选择器,选择带有mytitle类的td和extract _text,它引用节点内的文本。

比正则表达式更容易,更高效...

没有测试过这段代码,但它应该可行,你可以在这里获得更多关于爬虫的帮助和更多信息:

http://symfony.com/fr/doc/current/components/dom_crawler.html

答案 2 :(得分:0)

这是这个问题的另一个答案。

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
            }
        }


    });
});

您需要在567行上对Symfony \ dom-crawler \ Crawler.php文件进行一些更改。

public function nodeName()
    {
        if (!$this->nodes) {
            return null;
            // throw new \InvalidArgumentException('The current node list is empty.');
        }

        return $this->getNode(0)->nodeName;
    }