采集内容速度慢,我一直很头大,最近在研究多线程采集,下面贴出比较代码,有两个问题,一是获取的结果长度有点不一致;二是效率是不是还不够高?大伙帮忙分析,测试!
<?php
$timeStart = microtimeFloat();
function microtimeFloat() {
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
$data = '';
$urls = array('http://www.tzksgs.com/news/2012-09/article-217.html', 'http://www.tzksgs.com/news/2012-09/article-219.html', 'http://www.tzksgs.com/news/2012-09/article-222.html');
foreach($urls as $url){
echo strlen(file_get_contents($url)),'<br>';
}
$timeEnd = microtimeFloat();
echo sprintf("Spend time: %s second(s)\n", $timeEnd - $timeStart),'<br>';
$timeStart = microtimeFloat();
$timeout = 30;
$status = array();
$retdata = array();
$sockets = array();
$userAgent = $_SERVER['HTTP_USER_AGENT'];
foreach($urls as $id => $url) {
$tmp = parse_url($url);
$host = $tmp['host'];
$path = isset($tmp['path'])?$tmp['path']:'/';
empty($tmp['query']) or $path .= '?' . $tmp['query'];
if (empty($tmp['port'])) {
$port = $tmp['scheme'] == 'https' ? 443 : 80;
} else $port = $tmp['port'];
$fp = stream_socket_client("$host:$port", $errno, $errstr, 30);
if (!$fp) {
$status[$id] = "failed, $errno $errstr";
} else {
$status[$id] = "in progress";
$retdata[$id] = '';
$sockets[$id] = $fp;
fwrite($fp, "GET $path HTTP/1.1\r\nHost: $host\r\nUser-Agent: $userAgent\r\nConnection: Close\r\n\r\n");
}
}
// Now, wait for the results to come back inwhile (count($sockets)) {
$read = $write = $sockets;
//This is the magic function - explained below
if (stream_select($read, $write = null, $e = null, $timeout)) {
//readable sockets either have data for us, or are failed connection attempts
foreach ($read as $r) {
$id = array_search($r, $sockets);
$data = fread($r, 8192);
if (strlen($data) == 0) {
if ($status[$id] == "in progress") {
$status[$id] = "failed to connect";
}
fclose($r);
unset($sockets[$id]);
} else {
$retdata[$id] .= $data;
}
}
}
}
foreach($retdata as $data){
$data = trim(substr($data, strpos($data, "\r\n\r\n") + 4));
echo strlen($data),'<br>';
}
$timeEnd = microtimeFloat();
echo sprintf("Spend time: %s second(s)\n", $timeEnd - $timeStart);
?>

解决方案 »

  1.   

    fsockopen()函数也可以代替stream_*()系列函数,为什么要这么复杂?也许十行代码就可以搞定PHP没有线程这一说,而且抓取的速度与代码无关,与网络有关。所以能优化的地方,就在程序运行时资源占用上。 另microtime()函数可以有一个参数(boolean)true,它将会返回一个浮点数,和你的microtimeFloat();差不多。
      

  2.   

    如楼上所说,PHP只有单线程,少用正则表达式的情况下抓取的速度几乎差异不大.
    所以类似baidu,google之类的搜索引擎他们的抓取并非使用php来做的,他们用的都是CS程序开发的抓取程序.我认为最高的效率应该是CS程序多线程抓取内容,然后入库.
    而PHP只负责数据挖掘并显示给客户端.
      

  3.   

    你可以尝试 curl_multi_.... 并发执行
    这样可尽可能的减少 php 指令,至于楼上两位说的问题。绝不是php所能解决的
      

  4.   


    你可以把我上面的代码执行下,效率上stream方式确实比file_get_contents要高很多。
      

  5.   

    file_get_contents 比较慢,我上面的代码有两种方式的比较
      

  6.   

    当然,file_get_contents()是阻塞型的,所以如果是执行多个抓取任务,当然会慢。
    而socket_*(), fsockopen(), stream_*()都是非阻塞的。
      

  7.   

    慢到什么程度? 试下加上这个:$context = stream_context_create(array('http' => array('header'=>'Connection: close')));
    file_get_contents(".....",false,$context);
      

  8.   

    嗯, 看了一下, 你这个curl是并行的, 所以抓多个网页时要快. file_get_content目前大概还没办法.
      

  9.   

    sorry,  你这个stream方式.....