由於公司的一個汽車網站的後台的汽車內容都是主要是來自與汽車之家的,編輯的同事們必須天天手動去對著汽車之家來添加汽車,實在是太蛋疼了。於是乎,為了改變這種狀況,作為一個開發碼農,我的任務就來了。。。那就是准備做一個功能,只要粘貼對應的汽車之家的網址url就能對這些數據進行自動填充到我們後台的表單中,目前基本的填充都實現了,但是還是沒有能夠把對應的汽車相冊采集進來。
采集圖片的功能我以前也做過,但是汽車之家大部分的汽車都有挺多圖片的,開始的時候,我打算使用以前的采集圖片的辦法,也就是使用file_get_content獲取url對應的內容,然後匹配到圖片的地址,再使用file_get_content獲取這些圖片url的內容,再載入到本地去,代碼如下:
<?php header('Content-type:text/html;charset=utf-8'); set_time_limit(0); class runtime { var $StartTime = 0; var $StopTime = 0; function get_microtime() { list($usec, $sec) = explode(' ', microtime()); return ((float)$usec + (float)$sec); } function start() { $this->StartTime = $this->get_microtime(); } function stop() { $this->StopTime = $this->get_microtime(); } function spent() { return round(($this->StopTime - $this->StartTime) * 1000, 1); } } $runtime= new runtime(); $runtime->start(); $url = 'http://car.autohome.com.cn/pic/series-s15306/289.html#pvareaid=102177'; $rs = file_get_contents($url); // echo $rs;exit; preg_match_all('/(\/pic\/series-s15306\/289-\d+\.html)/', $rs, $urlArr); $avalie = array_unique($urlArr[0]); $count = array(); foreach ($avalie as $key => $ul) { $pattern = '/<img src="(http:\/\/car1\.autoimg\.cn\/upload\/\d+\/\d+\/\d+\/.*?\.jpg)"/'; preg_match_all($pattern, file_get_contents('http://car.autohome.com.cn'.$ul), $imgSrc); $count = array_merge($count, $imgSrc[1]); } foreach($count as $k=>$v) { $data[$k] = file_get_contents($v); } foreach($data as $k=>$v) { file_put_contents('./pic2/'.time().'_'.rand(1, 10000).'.jpg', $v); } $runtime->stop(); echo "頁面執行時間: ".$runtime->spent()." 毫秒";
結果發現,這種方法少圖片還好,圖片多了,那是相當的卡。。就本地測試也比較難跑,更不如說到時候上線了。百度之後,我采用了curl的辦法來下載圖片,經過測試後的確有所改善,但是感覺還是有點慢,要是php有多線程那有多好。。。
又經過一番折騰和找資料,發現php的curl庫其實還是可以模擬多線程的,那就是使用curl_multi_*系列的函數,經過改寫,代碼又變成了這樣:
<?php header('Content-type:text/html;charset=utf-8'); set_time_limit(0); class runtime { var $StartTime = 0; var $StopTime = 0; function get_microtime() { list($usec, $sec) = explode(' ', microtime()); return ((float)$usec + (float)$sec); } function start() { $this->StartTime = $this->get_microtime(); } function stop() { $this->StopTime = $this->get_microtime(); } function spent() { return round(($this->StopTime - $this->StartTime) * 1000, 1); } } $runtime= new runtime(); $runtime->start(); $url = 'http://car.autohome.com.cn/pic/series-s15306/289.html#pvareaid=102177'; $rs = file_get_contents($url); preg_match_all('/(\/pic\/series-s15306\/289-\d+\.html)/', $rs, $urlArr); $avalie = array_unique($urlArr[0]); $count = array(); foreach ($avalie as $key => $ul) { $pattern = '/<img src="(http:\/\/car1\.autoimg\.cn\/upload\/\d+\/\d+\/\d+\/.*?\.jpg)"/'; preg_match_all($pattern, file_get_contents('http://car.autohome.com.cn'.$ul), $imgSrc); $count = array_merge($count, $imgSrc[1]); } $handle = curl_multi_init(); foreach($count as $k => $v) { $curl[$k] = curl_init($v); curl_setopt($curl[$k], CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl[$k], CURLOPT_HEADER, 0); curl_setopt($curl[$k], CURLOPT_TIMEOUT, 30); curl_multi_add_handle ($handle, $curl[$k]); } $active = null; do { $mrc = curl_multi_exec($handle, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { // 這句在php5.3以後的版本很關鍵,因為沒有這句,可能curl_multi_select可能會永遠返回-1,這樣就永遠死在循環裡了 while (curl_multi_exec($handle, $active) === CURLM_CALL_MULTI_PERFORM); if (curl_multi_select($handle) != -1) { do { $mrc = curl_multi_exec($handle, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } foreach ($curl as $k => $v) { if (curl_error($curl[$k]) == "") { $data[$k] = curl_multi_getcontent($curl[$k]); } curl_multi_remove_handle($handle, $curl[$k]); curl_close($curl[$k]); } foreach($data as $k=>$v) { $file = time().'_'.rand(1000, 9999).'.jpg'; file_put_contents('./pic3/'.$file, $v); } curl_multi_close($handle); $runtime->stop(); echo "頁面執行時間: ".$runtime->spent()." 毫秒";
好了,多線程的采集真是非常酸爽,然後通過一系列的測試和對比,5次測試,curl多線程有4次是快於file_get_content的,而且時間還是file_get_content的3~5倍,總結起來,以後采集都盡量使用這種辦法,提高效率不在話下。