PHP實現簡單的數據採集併入庫

引言

​ 說到數據採集你們首先都會想到python,代碼簡潔,高效,很容易就能夠實現數據採集。php

​ 那PHP如何實現數據採集呢?很是簡單。html

概念

​ 那什麼是數據採集呢?如下是百度百科的介紹:python

數據採集,又稱數據獲取,是利用一種裝置,從系統外部採集數據並輸入到系統內部的一個接口。數據採集技術普遍應用在各個領域。mysql

你能夠簡單的理解爲偷別人網站的數據。jquery

須要的擴展包

1. Guzzle

這是一個PHP HTTP客戶端,能夠輕鬆發送HTTP請求並輕鬆與Web服務集成。laravel

安裝方式:git

composer require guzzlehttp/guzzle:~6.0
複製代碼

或者:github

在composer.json加入sql

"require": {
      "guzzlehttp/guzzle": "~6.0"
   }
}
複製代碼

2. QueryList

​ QueryList是一個基於phpQuery的PHP通用列表採集類,得益於phpQuery,讓使用QueryList幾乎沒有任何學習成本,只要會CSS3選擇器就能夠輕鬆使用QueryList了,它讓PHP作採集像jQuery選擇元素同樣簡單。 QueryList的幾個特色:數據庫

  1. 學習簡單:只有一個核心的API
  2. 使用簡單:用jQuery選擇器來選擇頁面元素
  3. 自帶過濾功能,可過濾掉無用的內容
  4. 支持無限層級嵌套採集
  5. 採集結果直接以採集規則以列表的形式有序的返回
  6. 支持擴展

咱們可使用它來過濾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;
    }
}
複製代碼

簡單分析:

  1. __construct 構造函數中咱們實例化了一個 guzzleClient,用來發起http請求的。

  2. sendRequest 是傳入url,而後發起一個http請求並返回目標的html源碼。

  3. 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,須要的夥伴能夠拉下來看下。

案例

我的博客

原文地址

相關文章
相關標籤/搜索