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

Laravel+Livewire项目二次提交表单出现Undefined array key 'name'错误

Laravel Livewire爬虫项目二次搜索报错「Undefined array key 'name'」解决方案

问题背景

基于Laravel和Livewire开发的电商商品爬虫项目,首次搜索可正常爬取商品并生成Product对象数组;二次提交搜索表单时,抛出「Undefined array key 'name'」错误。

核心原因

  1. Product模型设计问题:模型继承了Eloquent的Model类,但重写__construct方法时未调用父类构造逻辑,且未处理属性数组为空的情况。Livewire在组件刷新(二次搜索)时会尝试重新实例化模型,此时若属性缺失会触发数组键不存在的错误。
  2. 爬虫逻辑无异常处理:DomCrawler找不到指定选择器元素时会直接抛出异常,导致$name等变量未定义,创建Product时传入无效参数。

修复步骤

1. 修复Product模型

根据需求选择两种方案之一:

方案A:改为普通数据类(无需Eloquent功能)

如果该模型不需要与数据库交互,直接去掉Eloquent继承,同时添加属性默认值处理:

<?php

namespace App\Models;

class Product
{
    public $name;
    public $price;
    public $storeId;
    public $img;
    public $discount;
    public $discountText;

    public function __construct(array $attributes = []){
        // 使用null合并运算符处理属性缺失情况
        $this->name = $attributes["name"] ?? null;
        $this->price = $attributes["price"] ?? null;
        $this->storeId = $attributes["storeId"] ?? null;
        $this->img = $attributes["img"] ?? null;
        $this->discount = $attributes["discount"] ?? 'No';
        $this->discountText = $attributes["discountText"] ?? 'None';
    }
}

方案B:保留Eloquent模型(需数据库交互)

删除自定义的__construct方法,使用Eloquent内置的属性赋值逻辑,同时设置可填充字段:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    // 设置允许批量赋值的字段
    protected $fillable = ['name', 'price', 'storeId', 'img', 'discount', 'discountText'];
}

2. 完善爬虫逻辑的异常处理

在遍历商品元素时添加try-catch块,同时检查每个选择器是否存在元素,避免单个商品爬取失败导致整个搜索崩溃:

public function search(){
    $this->searched = false;
    $prods = [];
    $coto = [];
    $browser = new HttpBrowser(HttpClient::create()); 
    
    // 请求目标页面,对搜索参数做URL编码处理
    $crawler = $browser->request('GET', 'https://www.cotodigital3.com.ar/sitios/cdigi/browse?_dyncharset=utf-8&Dy=1&Ntt='.urlencode($this->product).'&Nty=1&Ntk=&siteScope=ok&_D%3AsiteScope=+&atg_store_searchInput='.urlencode($this->product).'&idSucursal=200&_D%3AidSucursal=+&search=Ir&_D%3Asearch=+&_DARGS=%2Fsitios%2Fcartridges%2FSearchBox%2FSearchBox.jsp');
    
    // 收集所有商品节点
    foreach($crawler->filter("[class='clearfix']") as $prod){ array_push($prods, $prod); }
    foreach($crawler->filter("[class='clearfix first']") as $prod){ array_push($prods, $prod); }
    foreach($crawler->filter("[class='clearfix first_max']") as $prod){ array_push($prods, $prod); }

    foreach($prods as $prod){
        try {
            $crawlerProd = new Crawler($prod);
            
            // 检查必要元素是否存在,不存在则跳过当前商品
            if(!$crawlerProd->filter("[class='descrip_full']")->count()) continue;
            if(!$crawlerProd->filter("[class='atg_store_newPrice']")->count()) continue;
            if(!$crawlerProd->filter("[class='atg_store_productImage'] > img")->count()) continue;
            
            // 提取商品信息
            $name = $crawlerProd->filter("[class='descrip_full']")->text();
            $price = $crawlerProd->filter("[class='atg_store_newPrice']")->text();
            $img = $crawlerProd->filter("[class='atg_store_productImage'] > img")->attr('src');
            
            // 处理折扣信息,默认无折扣
            $discountText = 'None';
            $discount = 'No';
            if($crawlerProd->filter("[class='info_discount']")->count()){
                $discountText = $crawlerProd->filter("[class='info_discount']")->children()->text();
                if($discountText != $price){
                    $discount = 'Yes';
                    $discountText = strstr($discountText, 'OFERTA');
                }
            }
            
            // 创建Product实例并加入结果数组
            $newProd = new Product([
                "name"=> $name,
                "price"=> $price,
                "storeId" => 'coto',
                "img" => $img,
                "discount" => $discount,
                "discountText" => $discountText
            ]);
            array_push($coto, $newProd);
        } catch (\Exception $e) {
            // 可添加日志记录,跳过当前异常商品
            continue;
        }
    }

    $this->productsAnswer = $coto;
    $this->searched = true;
}

额外优化建议

  • Livewire组件中,将public $productsAnswer = array();改为public $productsAnswer = [];,符合PHP现代语法规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 21:14:56