說到資料採集大家首先都會想到python,程式碼簡潔,高效,很容易就可以實現資料採集。
那PHP如何實現資料採集呢?非常簡單。
那什麼是資料採集呢?以下是百度百科的介紹:
資料採集,又稱資料獲取,是利用一種裝置,從系統外部採集資料並輸入到系統內部的一個介面。資料採集技術廣泛應用在各個領域。
你可以簡單的理解為偷別人網站的資料。
1. Guzzle
這是一個PHP HTTP客戶端,可以輕鬆傳送HTTP請求並輕鬆與Web服務整合。
安裝方式:
composer require guzzlehttp/guzzle:~6.0
或者:
在composer.json加入
"require": {
"guzzlehttp/guzzle": "~6.0"
}
}
2. QueryList
QueryList是一個基於phpQuery的PHP通用列表採集類,得益於phpQuery,讓使用QueryList幾乎沒有任何學習成本,只要會CSS3選擇器就可以輕鬆使用QueryList了,它讓PHP做採集像jQuery選擇元素一樣簡單。 QueryList的幾個特點:
- 學習簡單:只有一個核心的API
- 使用簡單:用jQuery選擇器來選擇頁面元素
- 自帶過濾功能,可過濾掉無用的內容
- 支援無限層級巢狀採集
- 採集結果直接以採集規則以列表的形式有序的返回
- 支援擴充套件
我們可以使用它來過濾html內容
安裝方式:
composer require jaeger/querylist:V3.2.1
我們以 LearnKu 社群為例,我們將採集社群的帖子資訊,並把這些資訊存入檔案和存入mysql資料庫。
1.安裝依賴
在命令列輸入以下命令
composer init
引入依賴
{
"require": {
"guzzlehttp/guzzle": "~6.0@dev",
"jaeger/querylist": "V3.2.1"
},
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
}
安裝依賴
composer install
2.採集類
app\Handle\ClientHandle.php
<?php
namespace App\Handle;
use GuzzleHttp\Client;
use QL\QueryList;
class ClientHandle
{
private $client;
public function __construct()
{
$this->client = new Client(['verify' => false]);
}
public function queryBody($url, $rules)
{
$html = $this->sendRequest($url);
$data = QueryList::Query($html, $rules)->getData(function ($item) {
if (array_key_exists('link',$item)){
$content = $this->sendRequest($item['link']);
$item['post'] = QueryList::Query($content, [
'title' => ['div.pull-left>span', 'text'],
'review' => ['p>span.text-mute:eq(0)', 'text'],
'comment' => ['p>span.text-mute:eq(1)', 'text'],
'content' => ['div.content-body', 'html'],
'created_at' => ['p>a>span', 'title'],
'updated_at' => ['p>a:eq(2)', 'data-tooltip']
])->data[0];
}
return $item;
});
//檢視採集結果
return $data;
}
private function sendRequest($url)
{
$response = $this->client->request('GET', $url, [
'headers' => [
'User-Agent' => 'testing/1.0',
'Accept' => 'application/json',
'X-Foo' => ['Bar', 'Baz']
],
'form_params' => [
'foo' => 'bar',
'baz' => ['hi', 'there!']
],
'timeout' => 3.14,
]);
$body = $response->getBody();
//獲取到頁面原始碼
$html = (string)$body;
return $html;
}
}
簡單分析:
-
__construct 建構函式中我們例項化了一個 guzzleClient,用來發起http請求的。
-
sendRequest 是傳入url,然後發起一個http請求並返回目標的html原始碼。
-
queryBody,接收一個url,和需要採集的規則,這裡不做延伸 queryList,只要會使用jquery,那相信你很快上手。
public function queryBody($url, $rules) { //發起一個請求,接收html原始碼 $html = $this->sendRequest($url); //將內容$html,和規則$rules 傳給QueryList的靜態方法Query處理,並獲取資料。 $data = QueryList::Query($html, $rules)->getData(function ($item) { //我首先獲取的是列表頁,然後通過列表的link連結再去獲取文章的詳細資訊。 //判斷是否匹配到link if (array_key_exists('link',$item)){ //獲取詳情頁的html原始碼 $content = $this->sendRequest($item['link']); //再交給QueryList 處理資料 $item['post'] = QueryList::Query($content, [ 'title' => ['div.pull-left>span', 'text'], 'review' => ['p>span.text-mute:eq(0)', 'text'], 'comment' => ['p>span.text-mute:eq(1)', 'text'], 'content' => ['div.content-body', 'html'], 'created_at' => ['p>a>span', 'title'], 'updated_at' => ['p>a:eq(2)', 'data-tooltip'] ])->data[0]; //採集到的是一個集合,所以我只取第一個 data[0] } return $item; }); //檢視採集結果 return $data; }
3. PDO類
App\Handle\PdoHandle.php
我們使用PDO來運算元據庫,這裡我簡單實現一個類
<?php
namespace App\Handle;
class PdoHandle
{
public $source;
private $driver;
private $host;
private $dbname;
private $username;
private $password;
/**
* PdoHandle constructor.
*/
public function __construct($driver = 'mysql', $host = 'localhost', $dbname = 'caiji', $username = 'root', $password = '')
{
$this->driver = $driver;
$this->host = $host;
$this->dbname = $dbname;
$this->username = $username;
$this->password = $password;
$dsn = $this->driver . ':host=' . $this->host . ';dbname=' . $this->dbname;
$this->source = new \PDO($dsn, $this->username, $this->password);
$this->source->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
}
相信都看得懂,就不介紹了
4. 寫入檔案
我們把採集到的內容,寫入到檔案裡
<?php
//設定請求時間無限制
set_time_limit(0);
//引入自動載入
require '../vendor/autoload.php';
//規則, 只取下標小於5的 也就是前5條資料
$rules = [
'title' => ['span.topic-title:lt(5)', 'text'],
'link' => ['a.topic-title-wrap:lt(5)', 'href']
];
//採集
$url = "https://learnku.com/laravel";
$client = new \App\Handle\ClientHandle();
$data = $client->queryBody($url, $rules);
//因為我們請求了兩級,所以返回的陣列需要處理成一級陣列
$data = array_map(function ($item) {
return $item['post'];
}, $data);
//寫入檔案
$handle = fopen('2.php','w');
$str = "<?php\n".var_export($data, true).";";
fwrite($handle,$str);
fclose($handle);
稍等幾秒後,你就可以看到檔案目錄下多出個 2.php 的檔案了,裡面有資料代表採整合功~
5. 寫入資料庫
把採集到的內容寫入到資料庫裡
1. 建立表
首先我們建立一張 posts表並有以下欄位:
`title`, `review`, `comment`, `content`,`created_at`,`updated_at`
created_at 和 updated_at 建議不要強制為時間型別和必填,否則需要再處理以下資料
2.操作
<?php
set_time_limit(0);
require '../vendor/autoload.php';
$rules = [
'title' => ['span.topic-title', 'text'],
'link' => ['a.topic-title-wrap', 'href']
];
$url = "https://learnku.com/laravel";
$client = new \App\Handle\ClientHandle();
$data = $client->queryBody($url, $rules);
$data = array_map(function ($item) {
return $item['post'];
}, $data);
//編寫sql語句
$sql = "INSERT INTO `posts`(`title`, `review`, `comment`, `content`,`created_at`,`updated_at`) VALUES";
//再過濾下沒有匹配到符合條件的特殊資料,避免入庫的時候麻煩
$data = array_filter($data,function($item){
return count($item) == 6;
});
//重置陣列下標
sort($data);
//組合sql語句
foreach ($data as $key => $item) {
//內容是有html標籤的,所以我們要用 base64 處理下才能入庫
$item['content'] = base64_encode($item['content']);
$value = "'" . implode("','", array_values($item)) . "'";
$sql .= "($value)";
if (count($data) - 1 != $key) {
$sql .= ",";
}
}
//採集
$db = new \App\Handle\PdoHandle();
try {
$db->source->query($sql);
echo '採集入庫成功!';
} catch (PDOException $exception) {
echo $exception->getMessage();
}
騷等幾秒鐘後,你就可以看到網頁上輸出 ‘採集入庫成功’ 的字樣,那代表成功了~
我們也可以只採集前幾條,只需要重寫$rules規則就行了
例如:只取前5條,我們可以這樣寫。
$rules = [
'title' => ['span.topic-title:lt(5)', 'text'],
'link' => ['a.topic-title-wrap:lt(5)', 'href']
];
6. 讀取資料
利用PDO讀取資料
<?php
require '../vendor/autoload.php';
$db = new \App\Handle\PdoHandle();
//查詢
$sql = "select * from `posts` limit 0,10";
$pdoStatement = $db->source->query($sql);
$data = $pdoStatement->fetchAll(PDO::FETCH_ASSOC);
foreach ($data as &$item){
//給內容解密
$item['content'] = base64_decode($item['content']);
}
var_dump($data);
希望對在看的你有點收穫吧,同時我也把它上傳到了github,需要的夥伴可以拉下來看下。