如何用PHP/JS从带分页及请求限制的API获取全量数据?
实现全量数据获取的方案
一、PHP 实现方案
你的现有代码已经能获取单页数据,只需要扩展分页循环、频率控制和数据持久化逻辑即可。注意30万条数据直接存数组会占用大量内存,建议直接写入文件(比如CSV或JSON)避免内存溢出。
核心思路
- 先请求第一页,获取总条数/总页数(API通常会返回
total或total_pages这类字段); - 按照API的频率限制(3分钟50次,即平均每3.6秒1次)控制请求间隔;
- 循环请求每一页,将数据追加写入文件,或分批存入数组后再批量写入;
- 增加基础错误处理,应对请求失败、Token过期等异常。
示例代码扩展
<?php // 初始化配置 $apiUrl = "你的API地址"; $token = "你的JWT Token"; $perPage = 25; $maxRequestsPer3Min = 50; $requestInterval = (3 * 60) / $maxRequestsPer3Min; // 计算每次请求间隔:3.6秒 // 第一步:获取总页数 $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $apiUrl . "?page=1&per_page={$perPage}", CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"], CURLOPT_RETURNTRANSFER => true ]); $response = curl_exec($curl); $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); if ($httpCode !== 200) { die("获取第一页数据失败,HTTP状态码:{$httpCode}"); } $result = json_decode($response, true); $totalItems = $result['total'] ?? 0; // 假设API返回total字段表示总条数 $totalPages = ceil($totalItems / $perPage); // 准备存储文件(用CSV更适合大数据量) $fileHandle = fopen('full_data.csv', 'w'); // 写入表头(假设返回数据的第一个元素是结构示例) if (!empty($result['data'])) { fputcsv($fileHandle, array_keys($result['data'][0])); } // 第二步:循环请求所有页面 $requestCount = 0; for ($page = 1; $page <= $totalPages; $page++) { // 频率控制:每50次请求后等待3分钟,或每次请求后等待固定间隔 if ($requestCount > 0 && $requestCount % $maxRequestsPer3Min === 0) { echo "已达请求上限,等待3分钟...\n"; sleep(3 * 60); } elseif ($requestCount > 0) { usleep($requestInterval * 1000000); // 转为微秒 } // 请求当前页 $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $apiUrl . "?page={$page}&per_page={$perPage}", CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"], CURLOPT_RETURNTRANSFER => true ]); $response = curl_exec($curl); $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); if ($httpCode !== 200) { echo "第{$page}页请求失败,HTTP状态码:{$httpCode},跳过该页\n"; continue; } $pageData = json_decode($response, true); if (empty($pageData['data'])) { echo "第{$page}页无数据,跳过\n"; continue; } // 写入文件 foreach ($pageData['data'] as $item) { fputcsv($fileHandle, $item); } $requestCount++; echo "已完成第{$page}/{$totalPages}页数据获取\n"; } fclose($fileHandle); echo "所有数据已写入full_data.csv\n"; ?>
注意事项
- 如果API没有返回总条数,可以循环请求直到返回数据为空;
- 若Token有过期时间,要在循环中检查并重新获取Token;
- 可以加入日志记录,方便排查异常;
- 避免用数组存储全量数据,30万条数据会占用数百MB内存,直接写文件更高效。
二、是否用JS处理更合适?
分两种情况看:
- 前端浏览器JS:完全不适合。浏览器有跨域限制(除非API允许CORS),且页面关闭、刷新会中断任务,同时浏览器的请求并发数和时长限制也不支持长时间抓取几十万条数据。
- Node.js:可以实现,逻辑和PHP类似,但你已经有PHP的基础代码,继续用PHP更省心,不需要切换技术栈。除非你有特定的Node.js生态依赖,否则没必要换。
内容的提问来源于stack exchange,提问作者Matredok
相关产品推荐
相关产品推荐

