引言
说到数据采集大家首先都会想到 python,代码简洁,高效,很容易就可以实现数据采集。
那 PHP 如何实现数据采集呢?非常简单。
概念
那什么是数据采集呢?以下是百度百科的介绍:
数据采集,又称数据获取,是利用一种装置,从系统外部采集数据并输入到系统内部的一个接口。数据采集技术广泛应用在各个领域。
你可以简单的理解为偷别人网站的数据。
需要的扩展包
这是一个 PHP HTTP 客户端,可以轻松发送 HTTP 请求并轻松与 Web 服务集成。
安装方式:
1
| composer require guzzlehttp/guzzle:~6.0
|
或者:
在 composer.json 加入
1 2 3 4
| "require": { "guzzlehttp/guzzle": "~6.0" } }
|
QueryList 是一个基于 phpQuery 的 PHP 通用列表采集类,得益于 phpQuery,让使用 QueryList 几乎没有任何学习成本,只要会 CSS3 选择器就可以轻松使用 QueryList 了,它让 PHP 做采集像 jQuery 选择元素一样简单。 QueryList 的几个特点:
- 学习简单:只有一个核心的 API
- 使用简单:用 jQuery 选择器来选择页面元素
- 自带过滤功能,可过滤掉无用的内容
- 支持无限层级嵌套采集
- 采集结果直接以采集规则以列表的形式有序的返回
- 支持扩展
我们可以使用它来过滤 html 内容
安装方式:
1
| composer require jaeger/querylist:V3.2.1
|
采集案例
我们以 LearnKu 社区为例,我们将采集社区的帖子信息,并把这些信息存入文件和存入 mysql 数据库。
1.安装依赖
在命令行输入以下命令
引入依赖
1 2 3 4 5 6 7 8 9 10 11
| { "require": { "guzzlehttp/guzzle": "~6.0@dev", "jaeger/querylist": "V3.2.1" }, "autoload": { "psr-4": { "App\\": "app/" } } }
|
安装依赖
2.采集类
app\Handle\ClientHandle.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| <?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,那相信你很快上手。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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; }
|
3. PDO 类
App\Handle\PdoHandle.php
我们使用 PDO 来操作数据库,这里我简单实现一个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?php
namespace App\Handle;
class PdoHandle { public $source;
private $driver; private $host; private $dbname; private $username; private $password;
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. 写入文件
我们把采集到的内容,写入到文件里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
set_time_limit(0);
require '../vendor/autoload.php';
$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 表并有以下字段:
1
| `title`, `review`, `comment`, `content`,`created_at`,`updated_at`
|
created_at 和 updated_at 建议不要强制为时间类型和必填,否则需要再处理以下数据
2.操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <?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 = "INSERT INTO `posts`(`title`, `review`, `comment`, `content`,`created_at`,`updated_at`) VALUES";
$data = array_filter($data,function($item){ return count($item) == 6; });
sort($data);
foreach ($data as $key => $item) { $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 条,我们可以这样写。
1 2 3 4
| $rules = [ 'title' => ['span.topic-title:lt(5)', 'text'], 'link' => ['a.topic-title-wrap:lt(5)', 'href'] ];
|
6. 读取数据
利用 PDO 读取数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?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,需要的伙伴可以拉下来看下。
案例
个人博客