首页
Preview

实用指南:如何使用 Laravel Actions 构建网页爬虫

几乎可以抓取和解析在线上可用的任何数据。本文示例将展示从 JSON 中提取数据,这可能是最简单的。有些软件包可帮助解析其他格式,例如 HTML、XML、PDF、CSV、Excel 甚至是借助 AI 技术的图像。

在荷兰,有一个网站 (https://www.verlorenofgevonden.nl) 用于跟踪丢失和扣押的自行车。通过这个项目,我们将获取在该网站上发现的相关数据,以对原始数据进行一些分析。

该网站 的屏幕截图

入门指南

如果你已经熟悉此部分,则可以跳过。我们将遵循官方文档创建一个带有 Docker 的 Laravel 项目。我正在 MacOS 上进行此操作,因此请参阅文档,因为你的说明可能针对 LinuxWindows 有所不同。

创建项目

导航到你的项目目录并创建一个新项目。由于它将在本地拉取和构建容器,所以这可能需要一些时间。

curl -s "https://laravel.build/laravel-scraper" | bash

启动环境

导航到新目录并启动环境。建议创建别名,请参见 文档

cd laravel-scraper && sail up -d --build

# if you get a response like "command not found" you should
# learn to do as advised

一旦应用程序的 Docker 容器已启动,你可以在 Web 浏览器中访问应用程序,网址为 http://localhost。你应该会看到默认的起始页面。

默认的起始页面

依赖项

我们将使用一些基本的依赖项来帮助我们入门。

Laravel Actions

对于这个项目,我决定尝试使用 Laravel Actions。这不是必需的,但看起来是正确的工具。

sail composer require lorisleiva/laravel-actions

Guzzle HTTP 客户端

Laravel 提供了一个简洁的 API,围绕 Guzzle HTTP 客户端,允许你快速地进行出站 HTTP 请求,以与其他 Web 应用程序进行通信。

sail composer require guzzlehttp/guzzle

Laravel Pint (可选)

Laravel Pint 是一个面向极简主义者的 PHP 代码风格修复程序。Pint 建立在 PHP-CS-Fixer 之上,使得确保你的代码风格保持干净和一致变得简单。

sail composer require laravel/pint --dev

核心逻辑

从网站获取数据非常简单。你可以按照一些基本步骤来应用此方法到你的用例中。

  • 手动浏览网站。
  • 检查网络日志以确定网站如何获取数据,最理想的情况是找到一些可直接定位的 API 请求。
  • 使用类似 Postman 的工具手动复制请求,以了解数据的流程、参数和形状。

模式

为了本指南的简单起见,我们将仅创建一个 Bicycle 模型来存储数据。使用以下命令在终端中生成模型和迁移。

sail artisan make:model Bicycle --migration

文件: app/Models/Bicycle.php

class Bicycle extends Model
{
    protected $fillable = [
        'object_number',
        'type',
        'sub_type',
        'brand',
        'color',
        'description',
        'city',
        'storage_location',
        'registered_at',
    ];

    protected $casts = [
        'registered_at' => 'datetime',
    ];
}

文件: database/migrations/create_bicycles_table.php

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('bicycles', function (Blueprint $table) {
            $table->id();
            $table->string('object_number', 32)->unique();
            $table->string('type', 32);
            $table->string('sub_type', 32);
            $table->string('brand', 32);
            $table->string('color', 32);
            $table->text('description');
            $table->string('city', 32);
            $table->string('storage_location', 64);
            $table->dateTime('registered_at');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('bicycles');
    }
};

运行迁移

sail artisan migrate

爬虫

我们将创建一个单一类,使用 Laravel Actions 来包含所需的逻辑。示例命令将专注于获取最基本的数据。你可以随时扩展此功能并深入挖掘。

例如,你可以从描述中推断出唯一的“车架号”,以检查单辆自行车被扣押了多少次。

文件: app/Actions/Scrapers/FetchBicycles.php

class FetchBicycles
{
    use AsAction;

    public string $commandSignature = 'scraper:fetch-bicycles';

    public string $commandDescription = 'Fetch impounded bicycles from www.verlorenofgevonden.nl';

    public function asCommand(Command $command): void
    {
        $this->handle($command);
    }

    public function handle(Command $command): void
    {
        $this->fetch($command, now()->subMonth(), now());
    }

    private function fetch(
        Command $command,
        Carbon $dateFrom,
        Carbon $dateTo,
        int $from = 0
    ): void {
        $response = Http::acceptJson()->get('https://verlorenofgevonden.nl/scripts/ez.php', [
            'site' => 'nl',
            'q' => 'fietsendepot',
            'date_from' => $dateFrom->format('d-m-Y'),
            'date_to' => $dateTo->format('d-m-Y'),
            'timestamp' => now()->timestamp,
            'from' => $from,
        ]);

        $hits = collect($response->json('hits.hits'));
        if ($hits->isEmpty()) {
            $command->info('Done processing');

            return;
        }

        $upserts = collect();
        foreach ($hits as $hit) {
            $registeredAt = Carbon::parse(data_get($hit, '_source.RegistrationDate'));
            $upserts->push([
                'object_number' => data_get($hit, '_source.ObjectNumber'),
                'type' => data_get($hit, '_source.Category'),
                'sub_type' => data_get($hit, '_source.SubCategory'),
                'brand' => data_get($hit, '_source.Brand'),
                'color' => data_get($hit, '_source.Color'),
                'description' => data_get($hit, '_source.Description'),
                'city' => data_get($hit, '_source.City'),
                'storage_location' => data_get($hit, '_source.StorageLocation.Name'),
                'registered_at' => $registeredAt,
            ]);
        }

        Bicycle::upsert($upserts->toArray(), ['object_number'], [
            'type',
            'sub_type',
            'brand',
            'color',
            'description',
            'city',
            'storage_location',
            'registered_at',
        ]);

        $total = $from + $upserts->count();
        $command->info(sprintf('Processed %d results', $total));
        $this->fetch($command, $dateFrom, $dateTo, $total);
    }
}

文件: app/Console/Kernel.php

class Kernel extends ConsoleKernel
{
    protected $commands = [
        FetchBicycles::class,
    ];
    
    // ...
}

运行命令

sail artisan scraper:fetch-bicycles

运行命令的示例

数据样例

对历史数据进行深入分析

由于我自行车被没收了两次,所以我受到启发从该网站中抓取数据并检查统计数据。事实上,我两次都是非法停车。

从抓取到的数据中发现了一些有趣的结果,我从中生成了以下图表。请注意,这些图表是在2022年10月1日生成的。

自2018年以来每个季度城市的没收情况

自2021年以来阿姆斯特丹与总数的比较

每个月城市的没收情况

自2018年以来没收罚款的估计金额

想法:自行车拍卖应用

我相信在荷兰没收自行车市场上存在一些空白。该网站帮助社区找回他们丢失或被没收的自行车,并允许你通过支付罚款和运费来获得它们。

阿姆斯特丹的自行车库 — 请查看

荷兰的自行车库里堆满了成千上万的自行车。许多人从未取回他们没收的自行车,导致了不断增长的废弃自行车。

有人应该创建一个简单的应用程序,将这些废弃自行车拍卖出去。获取数据非常简单,正如本指南所证明的那样。为了闭环,允许所有者设定一个最低竞价和/或截止日期。所有者可以在竞价成功后通过邮寄将钥匙发送给买家,而标准的交付过程可以用来将自行车交付给新所有者。

GitHub - HendrikPrinsZA/laravel-scraper: Simple web scraper built with Laravel Actions

译自:https://hendrikprinsza.medium.com/practical-guide-how-to-build-a-web-scraper-with-laravel-actions-63575c33df71

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
anko
宽以待人处事,严于律己修身。

评论(0)

添加评论