【发布时间】:2009-09-17 08:18:47
【问题描述】:
我想使用 PHP 来抓取我们拥有的包含大约 6 或 7000 个 href 链接的文档。我们需要的是链接另一侧的内容,这意味着 PHP 必须跟踪每个链接并获取链接的内容。这个可以吗?
谢谢
【问题讨论】:
标签: php
我想使用 PHP 来抓取我们拥有的包含大约 6 或 7000 个 href 链接的文档。我们需要的是链接另一侧的内容,这意味着 PHP 必须跟踪每个链接并获取链接的内容。这个可以吗?
谢谢
【问题讨论】:
标签: php
当然,只需使用 file_get_contents (http://nl.php.net/file_get_contents) 之类的函数获取起始 url 的内容,使用正则表达式在此页面的内容中查找 URL,获取这些 url 的内容等等。
正则表达式类似于:
$regexUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
【讨论】:
获取链接后,您可以使用curl 或 file_get_contents(但在安全环境中,file_get_contents 不应允许通过 http 协议)
【讨论】:
我只有一个我找到的所有链接的 SQL 表,以及它们是否已被解析。
然后我使用Simple HTML DOM 来解析最旧的添加页面,尽管由于它倾向于用大页面(500kb+ 的 html)耗尽内存,我对其中一些使用正则表达式*。对于我找到的每个链接,我将其添加到 SQL 数据库中作为需要解析,以及我找到它的时间。
SQL 数据库可防止数据因错误而丢失,并且由于我有 100,000 多个要解析的链接,因此我会在很长一段时间内进行分析。
我不确定,但你检查过 file_get_contents() 的用户代理吗?如果不是您的页面并且您发出了 1000 次请求,您可能想要更改用户代理,方法是编写自己的 HTTP 下载器或使用库中的一个(我使用 Zend 框架中的那个)但 cURL 等工作正常。如果您使用自定义用户代理,它允许管理员查看日志以查看有关您的机器人的信息。 (我倾向于把我爬的原因和一个联系人放在我的里面)。
*我使用的正则表达式是:
'/<a[^>]+href="([^"]+)"[^"]*>/is'
更好的解决方案(来自 Gumbo)可能是:
'/<a\s+(?:[^"'>]+|"[^"]*"|'[^']*')*href=("[^"]+"|'[^']+'|[^<>\s]+)/i'
【讨论】:
> 字符并用单引号括起来,甚至根本不用引号。所以最好使用这个:/<a\s+(?:[^"'>]+|"[^"]*"|'[^']*')*href=("[^"]+"|'[^']+'|[^<>\s]+)/i
PHP Snoopy 库有许多内置函数可以完全满足您的需求。
http://sourceforge.net/projects/snoopy/
您可以使用 Snoopy 下载页面本身,然后它还有一个功能可以提取该页面上的所有 URL。它甚至会将链接更正为完整的 URI(即它们不只是相对于页面所在的域/目录)。
【讨论】:
您可以尝试以下方法。详情请见this thread
<?php
//set_time_limit (0);
function crawl_page($url, $depth = 5){
$seen = array();
if(($depth == 0) or (in_array($url, $seen))){
return;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
$result = curl_exec ($ch);
curl_close ($ch);
if( $result ){
$stripped_file = strip_tags($result, "<a>");
preg_match_all("/<a[\s]+[^>]*?href[\s]?=[\s\"\']+"."(.*?)[\"\']+.*?>"."([^<]+|.*?)?<\/a>/", $stripped_file, $matches, PREG_SET_ORDER );
foreach($matches as $match){
$href = $match[1];
if (0 !== strpos($href, 'http')) {
$path = '/' . ltrim($href, '/');
if (extension_loaded('http')) {
$href = http_build_url($url, array('path' => $path));
} else {
$parts = parse_url($url);
$href = $parts['scheme'] . '://';
if (isset($parts['user']) && isset($parts['pass'])) {
$href .= $parts['user'] . ':' . $parts['pass'] . '@';
}
$href .= $parts['host'];
if (isset($parts['port'])) {
$href .= ':' . $parts['port'];
}
$href .= $path;
}
}
crawl_page($href, $depth - 1);
}
}
echo "Crawled {$href}";
}
crawl_page("http://www.sitename.com/",3);
?>
【讨论】:
我建议您使用包含 6000 个 URL 的 HTML 文档,将它们解析出来并循环浏览您拥有的列表。在您的循环中,使用 file_get_contents 获取当前 URL 的内容(为此,在您的服务器上启用 file_get_contents 时,您实际上并不需要 cURL),再次解析出包含的 URL,等等。
看起来像这样:
<?php
function getUrls($url) {
$doc = file_get_contents($url);
$pattern = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
preg_match_all($pattern, $doc, $urls);
return $urls;
}
$urls = getUrls("your_6k_file.html");
foreach($urls as $url) {
$moreUrls = getUrls($url);
//do something with moreUrls
}
?>
【讨论】: