什么叫采集?
就是使用PHP程序,把其他網站中的信息抓取到我們自己的數據庫中、網站中。
PHP制作采集的技術:
從底層的socket到高層的文件操作函數,一共有3種方法可以實現采集。
1. 使用socket技術采集:
socket采集是最底層的,它只是建立了一個長連接,然后我們要自己構造http協議字符串去發送請求。
例如要想獲取這個頁面的內容,http://tv.youku.com/?spm=a2hww.20023042.topNav.5~1~3!2~A,用socket寫如下:
- <?php
- //連接,$error錯誤編號,$errstr錯誤的字符串,30s是連接超時時間
- $fp=fsockopen("www.youku.com",80,$errno,$errstr,30);
- if(!$fp) die("連接失敗".$errstr);
- //構造http協議字符串,因為socket編程是最底層的,它還沒有使用http協議
- $http="GET /?spm=a2hww.20023042.topNav.5~1~3!2~A HTTP/1.1\r\n"; // \r\n表示前面的是一個命令
- $http.="Host:www.youku.com\r\n"; //請求的主機
- $http.="Connection:close\r\n\r\n"; // 連接關閉,最后一行要兩個\r\n
- //發送這個字符串到服務器
- fwrite($fp,$http,strlen($http));
- //接收服務器返回的數據
- $data='';
- while (!feof($fp)) {
- $data.=fread($fp,4096); //fread讀取返回的數據,一次讀取4096字節
- }
- //關閉連接
- fclose($fp);
- var_dump($data);
- ?>
打印出的結果如下,包含了返回的頭信息及頁面的源碼:
2. 使用curl_一套函數
curl把HTTP協議都封裝成了很多函數,直接傳相應參數即可,降低了編寫HTTP協議字符串的難度。
前提:在php.ini中要開啟curl擴展。
- //生成一個curl對象
- $curl=curl_init();
- //設置URL和相應的選項
- curl_setopt($curl, CURLOPT_URL, "http://www.youku.com");
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //將curl_exec()獲取的信息以字符串返回,而不是直接輸出。
- //執行curl操作
- $data=curl_exec($curl);
- var_dump($data);
打印出的結果如下,只包含頁面的源碼:
3. 直接使用file_get_contents(最頂層的)
前提:在php.ini中設置允許打開一個網絡的url地址。
- //使用file_get_contents()
- $data=file_get_contents("http://www.youku.com");
- var_dump($data);
3種方式的選擇
網絡之間通信主要使用的是以上三種。其中后兩種用的較多:如果要批量采集大量的數據時使用第二種【CURL】,性能好、穩定。
偶爾發幾個請求發的頻繁不密集時使用第三種。
擴展:圖片的防盜鏈如何破?
比如7060網站上的圖片做了防盜鏈:在他的網站中可以看到圖片,把圖片拿到站外就無法訪問。
原理:在HTTP協議中有一個referer項,代表發這個請求的來源地址,服務器會判斷如果這個請求不是這個網站發來的就會過濾掉這個請求:
解決辦法:發HTTP時自己模擬referer即可:
擴展:有些要采集數據時時必須先登錄,可以使用模擬的試模擬在登錄狀態下的采集:
a. 先用瀏覽登錄一下,登錄完,瀏覽器的COOKIE中就會有SESSIONID
b. 發PHP發HTTP協議時,把瀏覽器中的SESSIONID放到PHP的HTTP協議請求里,這樣就在以登錄的狀態發請求。
總結:所有客戶端發過來的數據都可以被模擬,所以服務器上的程序必須要必要的地方過濾客戶端的數據。
什么時候用以上東西?接口開發時、采集時。
二、數據采集
例如我要采集這個url里的所有美國電影的信息,
http://list.youku.com/category/show/c_96_a_%E7%BE%8E%E5%9B%BD_s_1_d_1_p_3.html
則先要知道電影所在的節點的結構,我們使用firebug查看。
然后開始寫代碼:完整代碼如下
- /**
- * 發一個GET請求獲取數據
- */
- function get($url)
- {
- global $curl;
- // 配置curl中的http協議->可配置的薦可以查PHP手冊中的curl_
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
- curl_setopt($curl, CURLOPT_HEADER, FALSE);
- // 執行這個請求
- return curl_exec($curl);
- }
- // 生成一個curl對象
- $curl = curl_init();
- $url='http://list.youku.com/category/show/c_96_a_%E7%BE%8E%E5%9B%BD_s_1_d_1_p_3.html';
- $data=get($url);
- // 匹配電影所在位置
- $list_preg = '/<li class="yk-col4 mr1">.+<\/li>/Us';
- // 匹配img標簽上的src和alt
- $img_preg = '/<img class="quic" _src="(.*)" src="(.*)" alt="(.*)" \/>/U';
- //匹配電影的url
- $video_preg='/<a href="(.*)" title="(.*)" target="(.*)"><\/a>/U';
- //把所有的li存到$list里,$list是個二維數組
- preg_match_all($list_preg,$data,$list);
- //var_dump($list);
- foreach ($list[0] as $k => $v) { //這里$v就是每一個li標簽
- /* 獲取圖片及電影名稱
- preg_match($img_preg,$v,$img); //把匹配到的圖片的信息存到$img里
- var_dump($img);
- */
- /*獲取電影地址
- preg_match($video_preg,$v,$video); //把匹配到的電影的信息存到$video里
- var_dump($video);
- */
- preg_match($img_preg,$v,$img);
- preg_match($video_preg,$v,$video);
- echo $img[0].'<a href="'.$video[1].'">'.$video[2].'</a>';
- }
測試:
打印$list;
打印$img
打印$video
最終效果:
如果需要把圖片拷貝到硬盤上,則在foreach循環里加上以下代碼:
- $imgData = get($img[1]);
- // 把圖片文件寫到硬盤上【下載】
- // 因為操作系統是GBK的,所以要把UTF8轉成GBK
- is_dir('./youkuimg/') ? '': mkdir('./youkuimg/');
- file_put_contents('./youkuimg/'.mb_convert_encoding($img[3], 'gbk', 'utf-8').'.jpg', $imgData);
效果如下:在當前目錄下的youkuimg目錄下就會有下載好的圖片。