PHP爬蟲 100萬條資料其實不難

2021-10-08 01:40:30 字數 3266 閱讀 5659

php爬取100萬條資料,首先要思考這三個問題:

怎麼爬取?

怎麼提公升爬取速度?

怎麼存放爬取的資料?

第乙個想到是不是分布式爬蟲呢,主機多的話是可以這麼張狂任性的,單機的話就要內斂些了。

不能分布式,那可以多執行緒啊,換個方向也是很有逼格的。

php多執行緒,我首選

swoole

了,不僅可以

多執行緒,還可以

多工投遞

,還能非同步執行

,這跟爬蟲不是很般配麼。

先考慮下mysql,畢竟平時用的多,總要給點面子。爬取到一條資料,就存入mysql,如果這樣執著的話,那這100萬條資料估計不知道什麼時候能爬完。存放在mysql,本質上是存放在磁碟的,io操作那就乙個字唄,慢。

放磁碟上慢,那就考慮記憶體唄,是不是想到memcache和redis了。memcache不能持久化,電源斷了資料就沒了,這100萬的資料也不是一兩個小時能爬完,顯然也不合適。再考慮

redis

,redis主打

海量資料

、高併發

、可持久化

,一聽就知道這就是我們想要的了。

爬取資料,首先要確定爬取什麼資料,這裡就簡單點,爬取左邊的這個部落格資訊。

這裡有暱稱、碼齡、原創文章數、粉絲等十幾個資訊可以爬取。但是我們要爬取100萬條資料,那就要找到這麼多的使用者資訊。可以通過下面這種裂變方式找到更多的使用者資訊。

再來分析下怎麼實現這種裂變:

部落格主頁,也就是獲取暱稱等資訊的頁面:

粉絲頁面:

關注頁面:

這就是整體構思過程,下面來看戲按具體的實現。

這裡採用物件導向的程式設計思想,分為server(swoole伺服器)、spider(爬蟲類)、redisdb(redis資料庫)這三個類,以下分別說明這三個類的職責。

spider(爬蟲類)

根據收到的uid,獲取粉絲和關注列表裡的所有uid(返回uid陣列)、獲取使用者的暱稱等資訊(返回info陣列);

注意:不使用swoole的話,也可以直接使用new spider類爬取資訊,spider類與其他兩個類無耦合。

redisdb(redis資料庫

將爬取到的uid陣列push入list;儲存uid的狀態,避免重複爬取;儲存使用者的資訊

server(swoole伺服器

server類裡面分為worker程序和taskworker程序:

worker程序負責呼叫spider類的crawllist($cur_uid),獲取粉絲和關注列表裡的所有uid(返回uid陣列),將這些uid放入redisdb的list(佇列)中,並設定$cur_uid的狀態為已存在,避免重複爬取,並將$cur_uid投放到任務池中;

taskworker程序從任務池獲取到uid,呼叫spider爬蟲類的crawlinfo($uid)(返回info陣列),然後再將info存入redis中;

注意:生產任務的速度要小於消費任務的速度,不然任務池將會溢位。

由於篇幅,這裡僅貼出spider類的**

<?php 

class spider

/*** @title 根據使用者uid,爬取該使用者的粉絲和關注的uid

* @param string uid 使用者唯一id

* return array 返回爬取到的 使用者粉絲和關注的uid組成的陣列

*/public function crawllist($uid)

return $list;

}/**

* @title 根據使用者uid,爬取該使用者的資訊

* @param string uid 使用者唯一id

* return array 返回使用者資訊

*/public function crawlinfo($uid)

// 匹配到了404頁面

$extra_reg = '##';

$count = preg_match($extra_reg, $html, $rs);

if(!empty($count))

// 正規表示式陣列

$reg_arr = array(

'username' => '#([^

'code_age' => '#碼齡([\d])年#',

'raw_count' => '#[\s]*?[\s]*?]*?>[^原創#',

'fans_count' => '##',

'hot_count' => '#[\s]*?[\s]*?[^

'visit_count' => '#[\s]*?[\s]*?[^

'jifen_count' => '#[\s]*?[\s]*?[^

'collect_count' => '#[\s]*?[\s]*?[^

'week_ranking' => '#[\s]*?[\s]*?[^周排名#',

'total_ranking' => '#[\s]*?[\s]*?[^總排名#',

);$info['uid'] = $uid;

foreach($reg_arr as $key => $reg)

return $info;

}/**

* @title 根據url 請求並返回頁面

* return false|string

*/public function request($url)

}

可以通過以下的方式看下效果:

$spider = new spider();

// 所要爬取的uid

$cur_uid = "qq_36034503";

// 獲取粉絲和關注裡所有的uid

$list = $spider->crawllist($cur_uid);

// 獲取使用者資訊

$info = $spider->crawlinfo($cur_uid);

// 輸出看下效果

var_dump($list);

var_dump($info);

對swoole和redis有了解的可以嘗試,用以上的思路實現下將每個uid當做任務,多工投遞、非同步執行

swoole學習文件:

redis學習文件:

批量插入100萬條資料

建立資料庫 create database create database bulktestdb gouse bulktestdb go create table create table bulktesttable id int primary key,username nvarchar 32 p...

Oracle查詢前100萬條資料

oracle不支援select top語句,在oracle中經常是用order by跟rownum select 列名1 列名n from select 列名1 列名n from 表名 order by 列名1 where rownum n 抽出記錄數 order by rownum asc 如 按...

php實現匯出10萬條資料

開發中經常遇到需要從資料庫匯出大量資料的問題,匯出excel需要占用太多記憶體,最終回導致記憶體溢位而失敗。csv是更好的選擇。同時可以使用php5.5之後賦予的新功能 yield 生成器 來優化效能,具體可以看鳥哥部落格 分段匯出所有使用者 public function exportall as...