我希望有人可以帮我解决这个问题。我目前正在用PHP写一个蜘蛛函数,它递归地遍历一个网站(通过它在网站页面上找到的链接)直到预先指定的深度。
到目前为止,我的蜘蛛适用于最多2级深度。我的问题是当深度降低3级或更多时,特别是在较大的网站上。我得到了一个致命的内存错误,我认为这与使用cURL的所有递归多处理有关(并且还因为某些站点上的3个级别可能意味着处理了数千个URL)。
致命错误:第105行的C:\ xampp \ htdocs \ crawler.php中允许的内存大小为134217728个字节(尝试分配366030个字节)
我的问题是我可能做错了什么(或者我应该做什么)来减少内存消耗。
以下是代码当前的样子,其中与内存使用相关的重要区域保持不变,更复杂的处理部分替换为伪代码/注释(以使其更易于阅读)。谢谢!
<?php
function crawler( $urlArray, $visitedUrlArray, $depth ){
/* Recursion check
--------------- */
if( empty( $urlArray) || ( $depth < 1 ) ){
return;
}
/* Set up Multi-Handler
-------------------- */
$multiCURLHandler = curl_multi_init();
$curlHandleArray= array();
foreach( $urlArray as $url ){
$curlHandleArray[$url] = curl_init();
curl_setopt( $curlHandleArray[$url], CURLOPT_URL, $url );
curl_setopt( $curlHandleArray[$url], CURLOPT_HEADER, 0 );
curl_setopt( $curlHandleArray[$url], CURLOPT_TIMEOUT, 1000 );
curl_setopt( $curlHandleArray[$url], CURLOPT_RETURNTRANSFER , 1 );
curl_multi_add_handle( $multiCURLHandler, $curlHandleArray[$url] );
}
/* Run Multi-Exec
-------------- */
$running = null;
do {
curl_multi_exec( $multiCURLHandler, $running );
}
while ( $running > 0 );
/* Process URL pages to find links to traverse
------------------------------------------- */
foreach( $curlHandleArrayas $key => $curlHandle ){
/* Grab content from a handle and close it
--------------------------------------- */
$urlContent = curl_multi_getcontent( $curlHandle );
curl_multi_remove_handle( $multiCURLHandler, $curlHandle );
curl_close( $curlHandle );
/* Place content in a DOMDocument for easy link processing
------------------------------------------------------- */
$domDoc = new DOMDocument( '1.0' );
$success = @$domDoc -> loadHTML( $urlContent );
/* The Array to hold all the URLs to pass recursively
-------------------------------------------------- */
$recursionURLsArray = array();
/* Grab all the links from the DOMDocument and add to new URL array
---------------------------------------------------------------- */
$anchors = $domDoc -> getElementsByTagName( 'a' );
foreach( $anchors as $element ){
// ---Clean the link
// ---Check if the link is in $visited
// ---If so, continue;
// ---If not, add to $recursionURLsArray and $visitedUrlArray
}
/* Call the function recursively with the parsed URLs
-------------------------------------------------- */
$visitedUrlArray = crawler( $recursionURLsArray, $visitedUrlArray, $depth - 1 );
}
/* Close and unset variables
------------------------- */
curl_multi_close( $multiCURLHandler );
unset( $multiCURLHandler );
unset( $curlHandleArray );
return $visitedUrlArray;
}
?>
答案 0 :(得分:1)
这是你的问题:
"I'm currently writing a spider function in PHP that recursively crawls across a website"
不要那样做。您将进入无限循环并导致拒绝服务。你真正的问题是内存不足。您真正的问题是您要删除正在抓取的网站。
真正的网络蜘蛛不会攻击您的网站,并且像您正在做的那样点击每一页繁荣热潮。你这样做的方式更像是攻击,而不是合法的网络浏览器。他们被称为“爬行者”,因为他们“爬行”,因为“走得很慢”。另外,合法的webcrawler会读取robots.txt文件,而不会根据该文件读取不受限制的页面。
你应该这样做:
读取一页并将链接保存到URL具有UNIQUE约束的数据库中,这样您就不会多次获得相同的链接。此表还应具有状态字段,以显示是否已读取URL。
从状态字段显示未读的数据库中抓取一个URL。阅读它,将它链接到的URL保存到数据库中。更新数据库上的状态字段以显示其已被读取。
根据需要重复#2 ..但是按照爬行的速度。
来自http://en.wikipedia.org/wiki/Web_crawler#Politeness_policy:
来自访问日志的轶事证据表明,来自已知抓取工具的访问时间间隔各不相同 在20秒到3-4分钟之间。