PHP爬取商品页报Call to a member function find() on bool错误
问题说明
运行PHP商品信息爬取脚本时触发致命错误:
Fatal error: Uncaught Error: Call to a member function find() on bool in C Stack trace: #0 {main} thrown in C on line 16
脚本逻辑为读取Book1.csv中存储的商品编码,拼接生成对应商品详情页URL,借助simple_html_dom库抓取页面.ProductDetailsTable节点下的商品属性信息,写入test.csv文件。此前已成功处理900余条商品编码的爬取任务,运行中途突发报错,暂不确定是否与XAMPP Apache运行环境有关。
原代码如下:
<?php // example of how to use basic selector to retrieve HTML contents include('simple_html_dom.php'); $file = fopen("Book1.csv","r"); $file2 = fopen("test.csv","w"); $links = []; while (($result = fgetcsv($file)) !== false) { $link = "https://mall/Product/".$result[0]; $links[] = $link; $row_data = []; $page = file_get_html($link); $product_details = $page->find('.ProductDetailsTable tr'); //line 16 if(count($product_details)==0) { $row_data[] = $result[0]; $row_data[] = 'not found'; fputcsv($file2, $row_data); continue; } //second method $article_number = ''; $product_description = ''; $product_family = ''; $product_lifecycle = ''; $plm_date = ''; $notes = ''; $EAN = ''; $UPC = ''; $country_of_origin = ''; foreach($product_details as $table_row) { if(count($table_row->find('td'))==1){ //ignore } elseif(count($table_row->find('td'))==2) { $key = $table_row->find('td')[0]->plaintext; $value = $table_row->find('td')[1]->plaintext; if($key=="EAN") { $EAN = $value; } elseif($key=='Article Number (Market Facing Number)') { $article_number = $value; } elseif ($key=='Product Description') { $product_description = $value; } elseif ($key=='Product family') { $product_family = $value; }elseif ($key=='Product Lifecycle (PLM)') { $product_lifecycle = $value; }elseif ($key=='PLM Effective Date') { $plm_date = $value; }elseif ($key=='Notes') { $notes = $value; }elseif ($key=='UPC') { $UPC = $value; }elseif ($key=='Country of origin') { $country_of_origin = $value; } } } $row_data[] = trim($article_number); $row_data[] = trim($product_description); $row_data[] = trim($product_family); $row_data[] = trim($product_lifecycle); $row_data[] = trim($plm_date); $row_data[] = trim($notes); $row_data[] = trim($EAN); $row_data[] = trim($UPC); $row_data[] = trim($country_of_origin); fputcsv($file2, $row_data); } fclose($file); fclose($file2); echo 'done'; ?>
错误根因
该错误与XAMPP Apache运行环境无关,核心问题是第15行file_get_html($link)调用返回了布尔值false,代码未做返回值校验,直接在第16行对false调用find()方法触发报错。file_get_html返回false的常见触发场景(与运行900余条后才报错的特征完全匹配):
- 某条拼接生成的商品URL无效,对应商品已下架/不存在,服务端返回404/500错误
- 短时间请求频率过高,触发站点反爬策略,返回403拦截页或验证码页
- 单次请求遭遇网络波动、连接超时,未拿到合法HTML内容
simple_html_dom存在内存泄漏问题,连续加载大量HTML文档后未手动释放内存,解析失败返回false
排查思路
- 打印报错时点正在处理的商品编码和拼接后的URL,直接在浏览器访问确认页面是否正常加载
- 抓取请求返回的响应状态码,确认失败原因是页面不存在、反爬拦截还是网络异常
- 打印脚本运行过程中的内存占用,确认是否为内存溢出导致的解析失败
修复方案
- 增加
file_get_html返回值校验,拿到false时直接记录异常,跳过当前条目继续处理,避免整个脚本崩溃 - 每次处理完单条页面后手动释放
simple_html_dom占用的内存,避免连续爬取时内存溢出 - 增加合理请求间隔,降低被反爬拦截的概率
- 增加错误标记,记录失败的URL和原因,方便后续补爬
核心修复代码片段参考:
$page = file_get_html($link); // 新增页面获取失败的兜底逻辑 if ($page === false) { $row_data[] = $result[0]; $row_data[] = 'page fetch failed'; fputcsv($file2, $row_data); $page = null; // 增加100ms请求间隔,避免请求过快 usleep(100000); continue; } $product_details = $page->find('.ProductDetailsTable tr'); // 原有解析逻辑保持不变 // 单条数据处理完成后,手动释放DOM对象占用内存 $page->clear(); $page = null; // 请求间隔 usleep(100000);
内容的提问来源于stack exchange,提问作者user19267705
相关产品推荐
相关产品推荐

