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

PHP多URL数据解析问题:循环页面数据无法完整抓取

解决PHP循环抓取动态分页代课数据的问题

听起来你遇到的情况很常见——面对这种自动循环刷新、每日页数不固定的分页内容,很容易因为终止条件判断不准、请求逻辑疏漏或者HTML解析不完整导致漏抓数据。我帮你拆解几个核心问题点,再给你一个可参考的完整脚本:

常见的错误原因排查

  • 硬编码分页数量:如果脚本里写死了只抓固定页数,那页数变化时就会漏抓;更糟的是,页面循环后你可能会重复抓取旧数据。
  • 没有处理页面循环逻辑:当到达最后一页后,网站会跳回subst_001.htm,如果你没检测到内容重复,会陷入无限循环,同时可能覆盖或漏抓中间数据。
  • 请求没有规避缓存/反爬:服务器可能对频繁请求做限制,或者返回缓存页面,导致你拿到的不是最新内容。
  • HTML解析逻辑不完善:代课数据通常在表格里,如果你的解析代码只提取了部分行/列,或者没处理换行、空格等格式问题,就会丢失数据。

完整的改进版脚本示例

下面是一个兼顾分页检测、循环终止、数据解析和数据库存储的脚本,你可以对照自己的代码找差异:

<?php
// 初始化配置
$baseUrl = 'http://plan.regenbogen-gesamtschule.de/vertretung/lehrer/subst_';
$pageSuffix = '.htm';
$visitedHashes = [];
$maxRetries = 3; // 单页面重试次数
$dbHost = 'localhost';
$dbName = '你的数据库名';
$dbUser = '用户名';
$dbPass = '密码';

// 连接数据库
try {
    $pdo = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
    die("数据库连接失败: " . $e->getMessage());
}

// 准备插入语句(根据你的表结构调整字段)
$insertStmt = $pdo->prepare("INSERT INTO vertretung_data (page_num, datum, lehrer, vertretung, stunde, fach, raum) 
                            VALUES (:page_num, :datum, :lehrer, :vertretung, :stunde, :fach, :raum)
                            ON DUPLICATE KEY UPDATE vertretung=VALUES(vertretung), stunde=VALUES(stunde)");

$pageNum = 1;
while(true) {
    $currentUrl = $baseUrl . sprintf('%03d', $pageNum) . $pageSuffix;
    $pageContent = '';
    $retryCount = 0;

    // 带重试的请求逻辑,模拟浏览器请求头
    while($retryCount < $maxRetries) {
        $context = stream_context_create([
            'http' => [
                'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36\r\n" .
                            "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" .
                            "Cache-Control: no-cache\r\n",
                'timeout' => 10
            ]
        ]);
        $pageContent = @file_get_contents($currentUrl, false, $context);
        
        if($pageContent !== false) break;
        $retryCount++;
        sleep(2); // 重试前等待2秒
    }

    if($pageContent === false) {
        echo "页面 $pageNum 请求失败,跳过\n";
        $pageNum++;
        continue;
    }

    // 计算页面哈希,检测是否循环回到已抓取的页面
    $pageHash = md5($pageContent);
    if(in_array($pageHash, $visitedHashes)) {
        echo "检测到页面循环,已抓取所有唯一页面,停止爬取\n";
        break;
    }
    $visitedHashes[] = $pageHash;

    // 解析HTML表格数据(假设数据在<table>标签内,根据实际结构调整)
    $dom = new DOMDocument();
    @$dom->loadHTML($pageContent);
    $tables = $dom->getElementsByTagName('table');
    
    if($tables->length === 0) {
        echo "页面 $pageNum 未找到数据表格,跳过\n";
        $pageNum++;
        continue;
    }

    $table = $tables->item(0); // 假设第一个表格是数据表格
    $rows = $table->getElementsByTagName('tr');
    
    foreach($rows as $index => $row) {
        // 跳过表头行(根据实际表头位置调整)
        if($index === 0) continue;
        
        $cols = $row->getElementsByTagName('td');
        if($cols->length < 6) continue; // 确保列数足够
        
        // 提取数据(根据实际列顺序调整)
        $datum = trim($cols->item(0)->nodeValue);
        $lehrer = trim($cols->item(1)->nodeValue);
        $vertretung = trim($cols->item(2)->nodeValue);
        $stunde = trim($cols->item(3)->nodeValue);
        $fach = trim($cols->item(4)->nodeValue);
        $raum = trim($cols->item(5)->nodeValue);

        // 插入数据库
        try {
            $insertStmt->execute([
                ':page_num' => $pageNum,
                ':datum' => $datum,
                ':lehrer' => $lehrer,
                ':vertretung' => $vertretung,
                ':stunde' => $stunde,
                ':fach' => $fach,
                ':raum' => $raum
            ]);
        } catch(PDOException $e) {
            echo "插入数据失败: " . $e->getMessage() . "\n";
        }
    }

    echo "页面 $pageNum 数据抓取完成\n";
    $pageNum++;
    sleep(1); // 避免请求过于频繁
}

echo "所有数据抓取并存储完成\n";
?>

关键改进点说明

  • 动态终止条件:通过计算页面内容的MD5哈希值,检测到重复页面时停止爬取,避免无限循环和重复抓取。
  • 健壮的请求逻辑:添加了重试机制和浏览器请求头,降低请求失败概率,避免被服务器拦截。
  • 可靠的HTML解析:使用DOMDocument代替正则表达式解析HTML,更稳定地提取表格数据。
  • 数据库安全:使用预处理语句插入数据,防止SQL注入,同时通过ON DUPLICATE KEY UPDATE处理重复数据。

你可以对照这个脚本检查自己的代码:比如是不是没处理页面循环?解析表格时是不是漏了某些行?数据库插入是不是没做异常处理?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:20:44