PHP單線程實現並行抓取網頁

來源:互聯網
上載者:User

   本PHP教程將類比並行抓取多個頁面資訊的過程,關鍵在於單線程的平行處理。

  一般情況下,大家寫抓取多個頁面資訊的程式都採用串列方案,但擷取周期過長,不實用。於是我想到用curl 去並行抓取。但是,最後發現,那個虛擬伺服器上沒有curl,這真是讓人糾結。於是,我決定改變思路,用單個線程也實現多個線程的效果。我想對網路編程有點

  瞭解的人肯定知道IO複用這個概念,當然PHP上也是支援的,而且,內部支援,不需要任何擴充。

  可能有很多年編程經驗的人對PHP的stream 函數可能不太瞭解。PHP的壓縮檔流,檔案流,tcp 協議下的應用 都封裝成一個stream。所以,讀本地檔案

  和讀網路檔案沒有任何的差別。說了這樣多,我想大家都基本上明白了,直接貼上代碼吧:

  代碼比較的粗糙,如果大家要實際用的話,還是要處理一些細節問題。

  代碼

  

  function http_get_open($url)

  {

  $url = parse_url($url);

  if (empty($url['host'])) {

  return false;

  }

  $host = $url['host'];

  if (empty($url['path'])) {

  $url['path'] = "/";

  }

  $get = $url['path'] . "?" . @$url['query'];

  $fp = stream_socket_client("tcp://{$host}:80", $errno, $errstr, 30);

  if (!$fp) {

  echo "$errstr ($errno)
n";

  return false;

  } else {

  fwrite($fp, "GET {$get} HTTP/1.0rnHost: {$host}rnAccept: */*rnrn");

  }

  return $fp;

  }

  function http_multi_get($urls)

  {

  $result = array();

  $fps = array();

  foreach ($urls as $key => $url)

  {

  $fp = http_get_open($url);

  if ($fp === false) {

  $result[$key] = false;

  } else {

  $result[$key] = '';

  $fps[$key] = $fp;

  }

  }

  while (1)

  {

  $reads = $fps;

  if (empty($reads)) {

  break;

  }

  if (($num = stream_select($reads, $w = null, $e = null, 30)) === false ) {

  echo "error";

  return false;

  } else if ($num > 0) {//can read

  foreach ($reads as $value)

  {

  $key = array_search($value, $fps);

  if (!feof($value)) {

  $result[$key] .= fread($value, 128);

  } else {

  unset($fps[$key]);

  }

  }

  } else {//time out

  echo "timeout";

  return false;

  }

  }

  foreach ($result as $key => &$value)

  {

  if ($value) {

  $value = explode("rnrn", $value, 2);

  }

  }

  return $result;

  }

  $urls = array();

  $urls[] = "http://www.qq.com";

  $urls[] = "http://www.sina.com.cn";

  $urls[] = "http://www.sohu.com";

  $urls[] = "http://www.blue1000.com";

  //並行的抓取

  $t1 = microtime(true);

  $result = http_multi_get($urls);

  $t1 = microtime(true) - $t1;

  var_dump("cost: " . $t1);

  //串列的抓取

  $t1 = microtime(true);

  foreach ($urls as $value)

  {

  file_get_contents($value);

  }

  $t1 = microtime(true) - $t1;

  var_dump("cost: " . $t1);

  ?>

  最後啟動並執行結果:

  string 'cost: 3.2403128147125' (length=21)

  string 'cost: 6.2333900928497' (length=21)

  基本上是兩倍的效率,當然,發現新浪非常的慢,要2.5s 左右,

  基本上是被他給拖累了,360隻要 0.2s

  如果,所有網站都差不多的速度,並行的數目更大,那麼差的倍數也就越大。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.