需求:
對於剛搭建的網站,數據比較單一,那么如何采集點數據呢。
前言:
這里我們可以用PHP寫的一個框架QueryList,官網文檔:http://www.querylist.cc/docs/guide/v4/overview;
說明:
如果你之前沒有做過數據采集,希望快速的理解,和入門。那么下面的文字可以給你帶來幫助。
什么是數據采集:
數據采集就是通過代碼,模擬瀏覽器請求,將第三方網站上資源(圖片資源,文字資源),采集到本地。簡而言之,比如有一個線上的博客網站,你自己也搭建了一個網站,但是沒有博客怎么辦。一般你可以通過復制粘貼,搬運到自己的網站上。所謂的數據采集,就是通過代碼實現剛才的操作流程。
核心處理點:
這里使用代碼操作,主要就是兩塊:
一個是,如何按規則選中我們要采集的網站字段;這個主要是用 DOM內容選擇:CSS選擇器
一個是,如何將選中的數據采集下來;這個就是通過 HTTP客戶端:GuzzleHTTP
簡而言之,代碼主要是用css選擇器按規則,選中需要采集的數據,然后用模擬HTTP客戶端請求,采集數據。
我們要做什么:
現在,我們要將一個第三方網站的數據,采集下來,然后寫入到自己數據庫中。
我們大致怎么做:
步驟一,按官方文檔,在自己項目(這邊項目是用tp6.0搭建的項目)中安裝QueryList擴展;
步驟二,采集博客列表,然后循環列表,采集列表詳情,而后將詳情里面的圖片下載到本地,最后對數據進行處理,自己需要哪些字段就存取哪些字段;
步驟三,對上面的數據進行格式化后,寫入到自己數據庫中;
上代碼:
1、在ThinkPHP6.0項目中通過Composer安裝QueryList擴展
composer require jaeger/querylist
2、DataCj.php控制器中引入 use QL\QueryList類,按步驟處理,用redis做數據中轉,最后拿到具體格式數據。對於選擇器的使用具體見QueryList文檔。
<?php /* * @Fun: 數據采集 * @User: JessieK * @Date: 2021-11-03 15:50:22 */ namespace app\v1\controller; use think\Request; use QL\QueryList; use think\facade\Cache; use think\facade\Db; use lib\XFace; use think\Model; class DataCj { protected $api_url;//接口域名 public function __construct() { $host = 1;//環境切換 1:test環境;2:prod環境 if($host == 1){ $this->api_url = 'https://a.cn'; }else{ $this->api_url = 'https://b.cn'; } } /** * @name: 采集尋找朋友數據 列表 * @param {Request} $request * @return {*} */ public function xunrenla_xunzhaopengyou(Request $request) { $page = $request->param('page', 1); $renewal = $request->param('renewal', 0); //放入緩存 $redis = Cache::store('redis'); $key = $request->action() .'_'. $page; $data_list = $redis->get($key); if(!$data_list || $renewal){ //采集網址 $url = 'http://www.xunrenla.com/xunzhaopengyou/list_6_'. $page .'.html'; //元素采集規則 $rules = [ //姓名 'name' => ['.siteContent a', 'title'], //詳情地址 'url' => ['.siteContent a', 'href'], //圖片地址 'img' => ['.siteImg img', 'src'], ]; //切片選擇器,選擇列表范圍 $range = '.layui-col-md8 .layui-card-body>div'; //開始采集 $rt = QueryList::get($url)->rules($rules)->range($range)->queryData(); $rt_key = count($rt) - 1; unset($rt[$rt_key]); // d($rt); $res = $redis->set($key, $rt, 2592000); echo '開始寫入緩存'.$res; exit('寫入緩存,數量值='.$rt_key); }else{ exit('已有緩存,數量值='. count($data_list)); } } /** * @name: 采集尋找朋友數據 下載圖片到本地 * @param {Request} $request * @return {*} */ public function xunrenla_xr(Request $request) { $page = $request->param('page', 1); $key = 'xunrenla_xunzhaopengyou_'. $page; //取的緩存里面的數據 $redis = Cache::store('redis'); $xr_list = $redis->get($key); if($xr_list){ lg('已取出,開始處理圖片='. count($xr_list)); //定義圖片存放路徑 $img_path = runtime_path() . 'xrl_img/'; $time = time(); foreach($xr_list as $key => $value){ //判斷圖片地址是否存在 if(strstr($value['img'], 'http')){ $img_string = file_get_contents($value['img']); lg('准備下載會員='.$value['name']); //保存圖片 $name = md5($value['name'] . $time . $key).'.jpg'; $img_name = $img_path . $name; $put_res = file_put_contents($img_name, $img_string); lg('下載結果='.$put_res); //追加路徑 $xr_list[$key]['img_path'] = $img_name; }else{ //刪除圖片不存在的 unset($xr_list[$key]); lg('當前圖片路徑不存在,跳過'); } } lg('准備寫入緩存,實際下載數量='.count($xr_list)); $res = $redis->set($request->action() . '_'. $page, $xr_list, 2592000); exit('處理完成res='.$res); }else{ exit('暫無數據'); } } /** * @name: 圖片上傳 test服務器 * @param {Request} $request * @return {*} */ public function xunrenla_upd_img(Request $request) { $page = $request->param('page', 1); $key = 'xunrenla_xr_'. $page; //取的緩存里面的數據 $redis = Cache::store('redis'); $xr_list = $redis->get($key); if(!$xr_list){ exit('暫無數據'); } $upd_key = $request->action() . '_'. $page; $upd_value = $redis->get($upd_key); if($upd_value){ exit('已處理'.count($upd_value)); } lg('開始處理圖片,待處理數='.count($xr_list)); foreach($xr_list as $key => $value){ //獲取圖片base64字符 $base_sting = imgToBase64($value['img_path']); if($base_sting){ lg('獲取圖片base64字符成功name'.$value['name']); lg('准備上傳test服務器'); $https_res = httpCurl($this->api_url . '/index/baseStringApi', ['chars' => $base_sting, 'filename' => md5($value['name'])], 1); if($https_res && $https_res['code'] == 200){ lg('上傳成功path='.$https_res['data']['path']); $xr_list[$key]['test_img_path'] = $https_res['data']['path'];//追加到新元素 }else{ unset($xr_list[$key]); lg('上傳失敗https_res='.$https_res['msg']); } }else{ unset($xr_list[$key]); lg('獲取圖片base64失敗'); } } lg('准備寫入緩存,實際上傳數='.count($xr_list)); $res = $redis->set($upd_key, $xr_list, 2592000); exit('處理完成res='.$res); } /** * @name: 采集尋人朋友 列表詳情 * @param {Request} $request * @return {*} */ public function xunrenla_details(Request $request) { $page = $request->param('page', 1); $key = 'xunrenla_upd_img_'. $page; //取的緩存里面的數據 $redis = Cache::store('redis'); $xr_list = $redis->get($key); if(!$xr_list){ exit('暫無數據'); } foreach($xr_list as $key => $value){ $ql = QueryList::get($value['url']); lg('開始采集詳情='.$value['name']); $rt = []; $rt['name'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(1)')->text(), ':'); $rt['sex'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(2)')->text(), ':'); $rt['age'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(3)')->text(), ':'); $rt['lost_time'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(4)')->text(), ':'); $rt['jg'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(5)')->text(), ':'); $rt['szdd'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(6)')->text(), ':'); $rt['sg'] = jq_zq(jq_zh($ql->find('.layui-col-md9 li:nth-child(7)')->text(), ':'), 'C'); $rt['lxr'] = jq_zh($ql->find('.layui-col-md9 li:nth-child(9)')->text(), ':'); $rt['ph'] = jq_zq(jq_zh($ql->find('.layui-col-md9 li:nth-child(10)')->text(), ':'), '提'); $rt['fp'] = jq_zh($ql->find('.layui-col-md8 .layui-hide-xs')->text(), ':'); $rt['ms'] = jq_zh($ql->find('.article-content div:nth-child(1) p')->text(), ':'); //數組詳情追加 $xr_list[$key]['detaile'] = $rt; } lg('采集完成,准備寫入緩存'); $res = $redis->set($request->action() . '_'. $page, $xr_list, 2592000); exit('處理完成res='.$res); } /** * @name: 對采集數據進行清洗,格式化經緯度 * @param {Request} $request * @return {*} */ public function xunrenla_data_up(Request $request) { $page = $request->param('page', 1); $key = 'xunrenla_details_'. $page; //取的緩存里面的數據 $redis = Cache::store('redis'); $xr_list = $redis->get($key); if(!$xr_list){ exit('暫無數據'); } $upd_key = $request->action() . '_'. $page; $upd_value = $redis->get($upd_key); // d($upd_value); if($upd_value){ exit('已處理'.count($upd_value)); } // d($xr_list); lg('開始處理數據,待處理數='.count($xr_list)); $data_list = []; foreach($xr_list as $key => $value){ //解析地址 lg('准備解析地址'); $dzz = str_replace(' ', '', $value['detaile']['jg']); $addres_res = XFace::showLocation($dzz); if($addres_res['status']){ lg('地址解析失敗,res='.$addres_res['msg']); unset($xr_list[$key]); }else{ lg('解析成功,res='.$addres_res['msg']); $data_list[$key]['member_id'] = 8;//會員uid $data_list[$key]['member_name'] = '人人尋客服-小尋';//會員昵稱 $data_list[$key]['member_headr'] = 'https://thirdwx.qlogo.cn/mmopen/vi_32/IxNUxicGvfiaibrSkUd9wMYibhOicua4icbwNUr8VQKKePQTnpUxxUL9kYTRBakq2Nsg9QxJVx4gpM5FHbibrOFloJwKQ/132';//會員頭像 $data_list[$key]['lost_type'] = 1;//尋人類型,0找親人,1幫忙找', // $data_list[$key]['title'] = $value['name'];//尋人標題 $data_list[$key]['name'] = $value['name'];//姓名 if($value['detaile']['sex'] == '男'){//性別(1男,2女 $data_list[$key]['sex'] = 1; }else{ $data_list[$key]['sex'] = 2; } $data_list[$key]['age'] = getAge(strtotime($value['detaile']['age']));//年齡 $data_list[$key]['height'] = $value['detaile']['sg'];//身高 $data_list[$key]['face_img'] = $value['test_img_path'];//圖片 // $data_list[$key]['phone'] = '';//手機號id // $data_list[$key]['lost_trait'] = $value['detaile']['ms'];//外貌特征 $data_list[$key]['lost_time'] = strtotime($value['detaile']['lost_time'] . '14:35');//走失時間 $data_list[$key]['lost_lon'] = $addres_res['data']['lon'];//走失地點(經度', $data_list[$key]['lost_lat'] = $addres_res['data']['lat'];//走失地點(緯度' // $data_list[$key]['address'] = $value['detaile']['szdd'];//具體位置(通過經緯度解析) // $data_list[$key]['province_id'] = 1;//省id', // $data_list[$key]['city_id'] = 1;//市id', // $data_list[$key]['district_id'] = 1;//區id', $data_list[$key]['address_detail'] =$dzz;//詳細地址(預留字段', $data_list[$key]['describe'] = str_replace(' ', '', $value['detaile']['ms']);//走失描述 $data_list[$key]['insert_time'] = strtotime($value['detaile']['fp']);//創建時間 $data_list[$key]['make_type'] = 2;//創建類型(1會員發布,2采集發布,默認為1', $data_list[$key]['m_phone'] = $value['detaile']['ph'];//采集發布,手機號', $data_list[$key]['laiyuan'] = '尋人啦www.xunrenla.com';//來源 } } lg('采集完成,准備寫入緩存,實際寫入數='.count($data_list)); $res = $redis->set($upd_key, $data_list, 2592000); exit('處理完成res='.$res); } /** * @name: 將采集數據 寫入test數據庫 * @param {Request} $request * @return {*} */ public function xunrenla_data_insert(Request $request) { $page = $request->param('page', 1); $key = 'xunrenla_data_up_'. $page; //取的緩存里面的數據 $redis = Cache::store('redis'); $xr_list = $redis->get($key); // d($xr_list);die; if(!$xr_list){ exit('暫無數據'); } $debug = $request->param('debug', 0); if($debug != 99){ d($xr_list); die; } lg('開始組裝數據'); $inser_data = []; foreach($xr_list as $key => $value){ //組裝數據 $time = time(); $pj_data = [ 'name' => $value['name'], 'sex' => $value['sex'], 'age' => $value['age'], 'height' => $value['height'], 'face_img' => $value['face_img'], // 'phone' => $data['phone'], 'member_id' => $value['member_id'], 'member_name' => $value['member_name'], 'member_headr' => $value['member_headr'], 'lost_type' => $value['lost_type'], // 'title' => $data['title'], // 'lost_trait' => $value['describe'],//外貌特征 'lost_time' => $value['lost_time'], 'lost_lon' => $value['lost_lon'],//經度 'lost_lat' => $value['lost_lat'],//緯度 'address_detail' => $value['address_detail'],//詳細位置 // 'address' => $adres_res['data']['formatted_address'],//具體地址(經緯度解析 // 'province_id' => $adres_res['data']['province_id'], // 'city_id' => $adres_res['data']['city_id'], // 'district_id' => $adres_res['data']['district_id'], 'describe' => $value['describe'],//走失描述 'insert_time' => $time, // 'update_time' => $time, 'make_type' => $value['make_type'], 'm_phone' => $value['m_phone'], 'laiyuan' => $value['laiyuan'], ]; $inser_data[$key] = $pj_data; // lg('准備寫入數據庫name='.$value['name']); // $tset_data = Db::table('t_lost_person')->insert($insert_data); // lg('寫入完成tset_data='.$tset_data); // die; } lg('組裝完成,總計inser_data='.count($inser_data)); lg('准備批量寫入數據庫'); $tset_data = Db::table('t_lost_person')->insertAll($inser_data); exit('批量寫入完成tset_data='.$tset_data); // d($inser_data); } }
說明:
以上請在采集的時候,注意網站版權問題,如上代碼,僅做學習使用,請勿用作商業用途。