【问题标题】:Scraping within a table using PHP DOM使用 PHP DOM 在表内抓取
【发布时间】:2014-06-21 18:08:27
【问题描述】:

所以我一直在尝试使用 PHP Simple HTML Parser 和 PHP 5 的内置 PHP DOM 解析器来抓取网站。

我们以此为例:http://www.ammunitiondepot.com/12-Gauge-Shotgun-Ammo-s/1922.htm

我正在尝试获取 v65-productDisplay 表中的所有产品图片。我能够抓取页面上的所有图像,但尝试仅抓取表格中的图像时遇到了困难。

这是我用来抓取所有图像的代码:

$html = file_get_contents('http://www.ammunitiondepot.com/12-Gauge-Shotgun-Ammo-s/1922.htm');
$dom = new domDocument;
$dom->loadHTML($html);
$dom->preserveWhiteSpace = false;
$images = $dom->getElementsByTagName('img');
foreach ($images as $image) {
    echo $image->getAttribute('src');
}

【问题讨论】:

  • 看看Goutte,你会喜欢的。
  • 我可以用它来抓取网站并将图像来源、产品标题、价格等信息保存到 csv 文件中吗?
  • 当然,它是很棒的工具。看一看。 link 我也推荐 Simple HTML DOM parser
  • 这个有教程吗,不知道怎么用。我尝试运行那个 ClientTest.php 替换 example.com 与我想抓取的网站,但什么也没发生。
  • 那里有一个自述文件。看看它。它是一些 Symfony 组件的包装器,因此请查看 Github 中的自述文件。它有足够的信息让你开始。让我告诉你,它是一个强大的工具,可以做你想做的大部分事情。

标签: php web-scraping


【解决方案1】:

你得到所有<img>src-attributes的问题基本上是因为你运行

$images = $dom->getElementsByTagName('img');

这表示您想从整个文档中获取所有 <img> 元素。但实际上您只想获取特定表格内的那些图像。至少你现在是这么认为的,但现在让我们直接这样做。您要查找的表格是文档顺序中的第 13 个表格。因此,您现在解决问题的方法是首先获取 <table>,然后从中获取所有 <img> 元素:

$tables = $dom->getElementsByTagName('table');
$table  = $tables->item(12); # 13th table in the document
$images = $table->getElementsByTagName('img');

这将已经为您提供了您在问题中要求的图像(src 属性的摘录):

//cdn3.volusion.com/sfvhn.cpdkd/v/vspfiles/photos/SPL12-00BK-1.jpg?1381182668
/v/vspfiles/templates/ammunition/images/clear1x1.gif
/v/vspfiles/templates/ammunition/images/clear1x1.gif
/v/vspfiles/templates/ammunition/images/clear1x1.gif
/v/vspfiles/templates/ammunition/images/clear1x1.gif
/v/vspfiles/templates/ammunition/images/buttons/btn_addtocart_small.gif
/v/vspfiles/templates/ammunition/images/clear1x1.gif
...

显然这会导致一些进一步的问题:

  1. 图片列表中有大量您不感兴趣的图片。您需要.jpg 文件,而不是所有那些许多 1 像素 gif 或购物车按钮。
  2. 表的编号是硬编码的。这不是很稳定,最好是寻找class="v65-productDisplay" 属性(你甚至已经在你的问题中写了它)。
  3. 图片 URL 是相对于文档的,所以需要解析。

我现在将首先展示如何解决前两个问题。

似乎getElementsByTagName 即使有用,也不能灵活地满足您的抓取需求。还有一种更好的方法可以从文档中查询元素,那就是xpath (ref)。它是一种查询语言,您可以在其中表达您想要的元素。因此,我们希望特定表中的图像 src 属性是 jpegs。 xpath 查询看起来像这样:

//table[@class="v65-productDisplay"]/tr/td/a/img/@src[contains(., ".jpg")]

这是在DOMXPath 的帮助下运行的,如下所示:

$xpath = new DOMXPath($dom);
$srcQuery = '//table[@class="v65-productDisplay"]/tr/td/a/img/@src[contains(., ".jpg")]';
/** @var DOMAttr $src */
foreach ($xpath->query($srcQuery) as $src) {
    echo $src->nodeValue, "\n";
}

现在这已经大大减少了列表的内容,同时也不那么冗长:

//cdn3.volusion.com/sfvhn.cpdkd/v/vspfiles/photos/SPL12-00BK-1.jpg?1381182668
//cdn3.volusion.com/sfvhn.cpdkd/v/vspfiles/photos/GTL1275-1.jpg?1380206953
//cdn3.volusion.com/sfvhn.cpdkd/v/vspfiles/photos/SS12L8-1.jpg?1390326206
//cdn3.volusion.com/sfvhn.cpdkd/v/vspfiles/photos/LEF127RS-1.jpg?1368458526
//cdn3.volusion.com/sfvhn.cpdkd/v/vspfiles/photos/LE13300-1.jpg?1368458467
//cdn3.volusion.com/sfvhn.cpdkd/v/vspfiles/photos/ADLE13300AC-1.jpg?1393516003
...

所以现在只剩下清理 URI 的问题了,即解析文档 URI(因为文档中没有进一步的基本 URI)并且可能清理查询字符串。我是在Net_URL2 的帮助下完成的,这里单独处理 src:

/** @var DOMAttr $src */
foreach ($xpath->query($srcQuery) as $src) {
    $href = $uri->resolve($src->nodeValue);
    $href->setQuery(false);
    echo $href, "\n";
}

这是一个完整的例子:

<?php
/*
 * @link http://stackoverflow.com/questions/24344420/scraping-within-a-table-using-php-dom
 * @auhtor hakre <http://hakre.wordpress.com>
 */

# uses Net_URL2 -- http://pear.php.net/package/Net_URL2/ -- https://packagist.org/packages/pear/net_url2
require __DIR__ . '/vendor/autoload.php';

$uri   = new Net_URL2('http://www.ammunitiondepot.com/12-Gauge-Shotgun-Ammo-s/1922.htm');
$cache = '12-Gauge-Shotgun-Ammo-s-1922.htm';

if (is_readable($cache)) {
    $html = file_get_contents($cache);
} else {
    $options = [
        'http' => [
            'user_agent'    => "Godzilla/42.4 (Gabba Gandalf Client 7.3; C128; Z80) Lord of the Table Weed Edition (KHTML, like Gold Dust Day Gecko) Chrome/97.0.43043.0 Safari/1337.42",
            'max_redirects' => 1, # do not follow redirects
        ]
    ];
    $context = stream_context_create($options);
    $html    = file_get_contents($uri, null, $context);
    file_put_contents($cache, $html);
}

$dom                     = new domDocument;
$dom->preserveWhiteSpace = false;

$save = libxml_use_internal_errors(true);
$dom->loadHTML($html);
libxml_use_internal_errors($save);
$dom->documentURI = $uri;

$xpath    = new DOMXPath($dom);
$srcQuery = '//table[@class="v65-productDisplay"]/tr/td/a/img/@src[contains(., ".jpg")]';
/** @var DOMAttr $src */
foreach ($xpath->query($srcQuery) as $src) {
    $href = $uri->resolve($src->nodeValue);
    $href->setQuery(false);
    echo $href, "\n";
}

这里是 HTML 供将来参考:http://pastebin.com/HCTTRm9E

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-08
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多