You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Goutte\Client的爬虫超时优化及Laravel队列使用咨询

解决方案:Laravel队列落地+爬虫&匹配逻辑优化

一、Laravel队列完整落地步骤

1. 确认队列驱动配置

先在.env中配置适合本地的队列驱动(推荐database,无需额外服务):

QUEUE_CONNECTION=database

生成队列所需的数据表:

php artisan queue:table
php artisan migrate

2. 完善CheckPages任务类

任务类改为单条订单处理,避免一次性处理大量数据导致超时:

<?php

namespace App\Jobs;

use Goutte\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Order;

class CheckPages implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $order;
    public $timeout = 30; // 任务超时时间,按需调整

    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    public function handle()
    {
        // 配置Goutte底层Guzzle的超时参数
        $guzzleClient = new \GuzzleHttp\Client([
            'timeout' => 15,
            'connect_timeout' => 5,
            'verify' => false, // 本地测试可关闭SSL验证,生产环境按需开启
        ]);
        $client = new Client();
        $client->setClient($guzzleClient);

        try {
            // 爬取目标页面并提取href
            $crawler = $client->request('GET', $this->order->target_url);
            $pageHrefs = $crawler->filter('a')->extract(['href']);
            
            // 过滤无效链接并去重
            $pageHrefs = array_filter(array_unique($pageHrefs), function ($href) {
                return !empty($href) && strpos($href, '#') !== 0;
            });

            // 用数据库查询替代多层循环匹配
            $dbLinks = \App\Models\PageData::whereIn('link', $pageHrefs)->pluck('link')->toArray();
            $matched = array_intersect($pageHrefs, $dbLinks);
            $unmatched = array_diff($pageHrefs, $dbLinks);

            // 存储验证结果
            $this->order->update([
                'matched_links' => json_encode($matched),
                'unmatched_links' => json_encode($unmatched),
                'check_status' => 'completed'
            ]);
        } catch (\Exception $e) {
            // 标记任务失败并记录错误
            $this->order->update([
                'check_status' => 'failed',
                'error_msg' => $e->getMessage()
            ]);
            $this->release(60); // 60秒后重试,最多重试次数由worker配置决定
        }
    }
}

3. 批量分发任务

创建Artisan命令批量分发未验证订单的任务:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\Order;
use App\Jobs\CheckPages;

class DispatchCheckOrders extends Command
{
    protected $signature = 'orders:check';
    protected $description = '分发订单页面验证任务';

    public function handle()
    {
        $orders = Order::where('check_status', 'pending')->get();
        
        foreach ($orders as $order) {
            CheckPages::dispatch($order);
            usleep(100000); // 0.1秒延迟,避免瞬间压垮目标服务器
        }

        $this->info('任务分发完成,共'.$orders->count().'条订单');
    }
}

运行命令分发任务:

php artisan orders:check

4. 启动队列Worker

本地开发直接启动:

php artisan queue:work --tries=3 --timeout=30

Linux环境后台运行:

nohup php artisan queue:work --tries=3 --timeout=30 > storage/logs/queue.log 2>&1 &

二、爬虫与匹配逻辑优化

1. Goutte性能优化

  • 给Guzzle设置明确的超时时间,避免无限等待
  • 本地测试可关闭SSL验证,减少握手耗时
  • 爬取后立即过滤无效链接,减少后续处理的数据量

2. 数据库匹配优化

  • 用whereIn替代多层循环,将匹配逻辑交给数据库处理,大幅提升速度
  • 给PageData表的link字段添加索引:
php artisan make:migration add_index_to_link_on_page_data_table --table=page_data

迁移文件内容:

public function up()
{
    Schema::table('page_data', function (Blueprint $table) {
        $table->index('link');
    });
}

public function down()
{
    Schema::table('page_data', function (Blueprint $table) {
        $table->dropIndex('link');
    });
}

执行迁移:

php artisan migrate

3. 批量处理进阶技巧

  • 配置定时任务,自动分发新增的未验证订单
  • 用队列优先级区分订单,比如重要订单走high队列
  • 用php artisan queue:failed查看失败任务,queue:retry重试指定任务

内容的提问来源于stack exchange,提问作者scorpions77

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 11:17:51