如何使用PHP从指定URL获取数据并爬取所有分页内容
实现方案
越南语维基词典属于MediaWiki架构站点,优先推荐使用官方API拉取数据,比直接爬HTML分页稳定性高、反爬风险低,两种实现方式如下:
方案1:MediaWiki API获取(推荐)
不需要解析HTML分页,直接调用官方接口拉取分类下全量数据,代码如下:
<?php // 基础配置 $apiUrl = 'https://vi.wiktionary.org/w/api.php'; $targetCategory = 'Thể loại:Mục từ tiếng Việt'; $allData = []; $nextPageToken = ''; do { // 组装请求参数 $queryParams = [ 'action' => 'query', 'list' => 'categorymembers', 'cmtitle' => $targetCategory, 'cmlimit' => 'max', // 单次拉取最大条目数,普通用户默认为500 'format' => 'json' ]; // 带上分页标记 if ($nextPageToken) { $queryParams['cmcontinue'] = $nextPageToken; } // 发起请求,必须加合法UA,否则会被MediaWiki拦截 $ch = curl_init($apiUrl . '?' . http_build_query($queryParams)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, '你的应用名称/1.0 (你的联系邮箱)'); $response = curl_exec($ch); curl_close($ch); $result = json_decode($response, true); // 合并当前页数据 if (isset($result['query']['categorymembers'])) { $allData = array_merge($allData, $result['query']['categorymembers']); } // 获取下一页分页标记,无标记则退出循环 $nextPageToken = $result['continue']['cmcontinue'] ?? ''; // 加延时避免请求过频被封IP sleep(1); } while ($nextPageToken); // 所有分类条目数据已存入$allData,可按需处理 print_r($allData); ?>
注意事项:
- 如果需要获取每个词条的正文内容,可额外调用API的
query+revprops参数拉取对应词条的版本内容 - 不要去掉UA和请求延时,否则极易触发站点反爬规则
方案2:HTML分页爬取(不推荐)
如果必须爬原始页面内容,可通过解析分页按钮循环拉取,需要用到DOM解析库避免正则匹配出错,首先安装依赖:composer require symfony/dom-crawler symfony/css-selector
代码如下:
<?php require 'vendor/autoload.php'; use Symfony\Component\DomCrawler\Crawler; $baseDomain = 'https://vi.wiktionary.org'; $currentPageUrl = 'https://vi.wiktionary.org/wiki/Th%E1%BB%83_lo%E1%BA%A1i:M%E1%BB%A5c_t%E1%BB%AB_ti%E1%BA%BFng_Vi%E1%BB%87t'; $allPageHtml = []; do { // 拉取当前页内容 $ch = curl_init($currentPageUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, '你的应用名称/1.0 (你的联系邮箱)'); $html = curl_exec($ch); curl_close($ch); $allPageHtml[] = $html; // 解析下一页链接 $crawler = new Crawler($html); $nextLinkNode = $crawler->filter('a.mw-nextlink'); $hasNextPage = $nextLinkNode->count() > 0; if ($hasNextPage) { $currentPageUrl = $baseDomain . $nextLinkNode->attr('href'); } sleep(1); } while ($hasNextPage); // 所有页面HTML已存入$allPageHtml,可按需解析内容 print_r(count($allPageHtml)); ?>
注意事项:
- 该方案高度依赖站点HTML结构,一旦维基词典改版修改分页按钮的类名、结构,代码就会失效
- 解析词条内容时也建议用DOM工具,不要用正则匹配,稳定性更高
内容的提问来源于stack exchange,提问作者Zet Nguyen
相关产品推荐
相关产品推荐

