代码之家  ›  专栏  ›  技术社区  ›  Jim

有没有办法使用PHP来抓取链接?

php
  •  0
  • Jim  · 技术社区  · 16 年前

    我想用PHP来抓取一个文档,我们有大约6或7千个href链接。我们需要的是链接另一侧的内容,这意味着PHP必须跟踪每个链接并获取链接的内容。这能做到吗?

    谢谢

    6 回复  |  直到 16 年前
        1
  •  1
  •   Sander    16 年前

    当然,只需使用file_get_contents这样的函数获取起始url的内容( http://nl.php.net/file_get_contents ),使用正则表达式在该页面的内容中查找URL,获取这些URL的内容等等。

    Regexp将类似于:

    $regexUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
    
        2
  •  0
  •   Eineki    16 年前

    获取链接后,可以使用 curl 或者文件内容(在安全的环境中,文件内容不允许通过http协议)

        3
  •  0
  •   Yacoby    16 年前

    我只是有一个SQL表,包含我找到的所有链接,以及它们是否已被解析。

    然后我用 Simple HTML DOM 为了解析最早添加的页面,尽管它往往会因大页面(500kb+的html)而耗尽内存,但我对其中一些页面使用了正则表达式*。对于我找到的每个链接,我都会在需要解析时将其添加到SQL数据库中,以及找到它的时间。

    SQL数据库可以防止数据在出错时丢失,因为我有100000多个链接需要解析,所以我会花很长时间来解析。

    我不确定,但是你检查过文件_get_contents()的用户代理了吗?如果它不是你的页面,并且你发出了1000个请求,你可能想要更改用户代理,或者编写你自己的HTTP下载器,或者使用库中的一个(我使用Zend框架中的一个),但是cURL等可以很好地工作。如果您使用自定义用户代理,它允许管理员查看日志以查看有关您的机器人的信息。(我倾向于把我爬行的原因和一个接触点放在我的身上)。

    *我使用的正则表达式是:

    '/<a[^>]+href="([^"]+)"[^"]*>/is'
    

    更好的解决方案(来自Gumbo)可能是:

    '/<a\s+(?:[^"'>]+|"[^"]*"|'[^']*')*href=("[^"]+"|'[^']+'|[^<>\s]+)/i'
    
        4
  •  0
  •   Nolte    16 年前

    PHP Snoopy库有一系列内置函数,可以准确地完成所需的功能。

    http://sourceforge.net/projects/snoopy/

    您可以使用Snoopy下载页面本身,然后它还有另一个功能来提取该页面上的所有URL。它甚至会将链接更正为完整的URI(即,它们不只是相对于页面所在的域/目录)。

        5
  •  0
  •   Community Mohan Dere    9 年前

    你可以试试下面的方法。看见 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);
    ?>
    
        6
  •  -1
  •   Alex    16 年前

    我建议你把HTML文档和6000个URL放在一起,把它们解析出来,然后循环浏览你得到的列表。在循环中,使用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
    }
    ?>
    
    推荐文章