ReactPHP 爬虫实战:下载整个网站的图片 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区

[ReactPHP 爬虫实战:下载整个网站的图片 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区]

什么是网页抓取?

你是否曾经需要从一个没有提供 API 的站点获取信息? 我们可以通过网页抓取,然后从目标网站的 HTML 中获得我们想要的信息,进而解决这个问题。 当然,我们也可以手动提取这些信息, 但手动操作很乏味。 所以, 通过爬虫来自动化来完成这个过程会更有效率。

在这个教程中我们会从 Pexels 抓取一些猫的图片。这个网站提供高质量且免费的素材图片。他们提供了API, 但这些 API 有 200次/小时 的请求频率限制。

[file

](https://lccdn.phphub.org/uploads/images/201809/20/1/18CUcgVuV8.jpg?imageView2/2/w/1240/h/0)

发起并发请求

在网页抓取中使用异步 PHP (相比使用同步方式)的最大好处是可以在更短的时间内完成更多的工作。使用异步 PHP 使得我们可以立刻请求尽可能多的网页而不是每次只能请求单个网页并等待结果返回。 因此,一旦请求结果返回我们就可以开始处理。

首先,我们从 GitHub 上拉取一个叫做 buzz-react  的异步 HTTP 客户端的代码 -- 它是一个基于 ReactPHP 的简单、致力于并发处理大量 HTTP 请求的异步 HTTP 客户端:

composer require clue/buzz-react

现在, 我们就可以请求 pexels 上的图片页面 了:

<?php

require __DIR__ . '/vendor/autoload.php';

use Clue\React\Buzz\Browser;

$loop = \React\EventLoop\Factory::create();

$client = new Browser($loop);
$client->get('https://www.pexels.com/photo/kitten-cat-rush-lucky-cat-45170/')
    ->then(function(\Psr\Http\Message\ResponseInterface $response) {
        echo $response->getBody();
    });

$loop->run();

我们创建了 Clue\React\Buzz\Browser 的实例, 把它作为 HTTP client 使用。上面的代码发起了一个异步的 GET 请求来获取网页内容(包含一张小猫们的图片)。 $client->get($url) 方法返回了一个包含 PSR-7 response 的 promise 对象。

客户端是异步工作的,这意味着我们可以很容易地请求几个页面,然后这些请求会被同步执行:

<?php

require __DIR__ . '/vendor/autoload.php';

use Clue\React\Buzz\Browser;

$loop = \React\EventLoop\Factory::create();

$client = new Browser($loop);
$client->get('https://www.pexels.com/photo/kitten-cat-rush-lucky-cat-45170/')
    ->then(function(\Psr\Http\Message\ResponseInterface $response) {
        echo $response->getBody();
    });

$client->get('https://www.pexels.com/photo/adorable-animal-baby-blur-177809/')
    ->then(function(\Psr\Http\Message\ResponseInterface $response) {
        echo $response->getBody();
    });

$loop->run();

这里的代码含义如下:

  • 发起一个请求
  • 获取响应
  • 添加响应的处理程序
  • 当响应解析完毕就处理响应

所以,这个逻辑可以提取到一个类里,这样我们可以很容易地请求多个 URL 并添加相同的响应处理程序。让我们基于Browser创建一个包装器。

用下面的代码创建一个名为Scraper的类:

<?php

use Clue\React\Buzz\Browser;
use Psr\Http\Message\ResponseInterface;

final class Scraper
{
    private $client;

    public function __construct(Browser $client)
    {
        $this->client = $client;
    }

    public function scrape(array $urls)
    {
        foreach ($urls as $url) {
            $this->client->get($url)->then(
                function (ResponseInterface $response) {
                    $this->processResponse((string) $response->getBody());
                });
        }
    }

    private function processResponse(string $html)
    {
        // ...
    }
}

我们把Browser作为依赖项注入到构造函数并提供一个公共方法scrape(array $urls)。接着对每个指定的 URL 发起一个GET请求。当响应完成时,我们调用一个私有方法processResponse(string $html)。这个方法负责遍历 HTML 代码并下载图片。下一步是审查收到的 HTML 代码,然后从里面提取图片。

    • *

Practice makes perfect.

原文地址:https://sergeyzhuk.me/2018/08/31/fast-we...

译文地址:https://laravel-china.org/topics/17492

本帖已被设为精华帖!


Original url: Access

Created at: 2018-10-10 14:08:16

Category: default

Tags: none

请先后发表评论
  • 最新评论
  • 总共0条评论