使用Langchain Recursive URL Loader爬取Next.js文档页数不一致问题
问题:Recursive URL Loader爬取Next.js文档时页面数量不稳定
使用Langchain的RecursiveUrlLoader爬取Next.js官方文档,预期每次爬取的页面数量保持一致,但实际每次运行后获取的页面数量均不相同。
实现代码
import { RecursiveUrlLoader } from 'langchain/document_loaders/web/recursive_url'; import { compile } from 'html-to-text'; export const handleScrape = async (req, res) => { const { title, url } = req.body; // 从请求体中提取标题和URL const compiledConvert = compile({ wordwrap: 130 }); // 返回(text: string) => string; // if (!url) { // res.status(400).send('No url provided'); // return; // } const loader = new RecursiveUrlLoader(url, { extractor: compiledConvert, maxDepth: 50, // 根据需要调整 }); const docs = await loader.load(); console.log(`从${title}爬取了${docs.length}个文档`); res.send(docs); };
现象
多次执行爬取任务,返回的文档数量存在明显差异(例如某次抓取到123个页面,另一次仅抓取到118个)。
原因分析与解决方案
1. 动态内容渲染导致链接抓取不全
Next.js文档部分页面采用客户端动态渲染,RecursiveUrlLoader默认基于静态HTML解析链接,动态生成的链接可能因加载时机不同,每次爬取时抓取到的数量不一致。
- 解决办法:改用支持动态渲染的加载方案,比如结合
PuppeteerLoader来渲染完整页面后再解析链接;或者自定义extractor函数,确保能捕获动态生成的URL。
2. 目标站点反爬机制拦截请求
Next.js官方文档可能存在临时请求限制,多次快速爬取时部分请求被拦截,导致页面未成功抓取。
- 解决办法:在loader配置中添加请求延迟,同时配置请求头模拟浏览器:
const loader = new RecursiveUrlLoader(url, { extractor: compiledConvert, maxDepth: 50, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' }, delay: 1000 // 每次请求间隔1秒 });
3. 默认链接去重逻辑存在漏洞
RecursiveUrlLoader的默认去重可能未处理URL格式差异(如带锚点、不同顺序的查询参数),导致同一页面被重复计数或漏记。
- 解决办法:自定义
getUrls方法,手动实现严格的URL标准化和去重:const cheerio = require('cheerio'); // 需提前安装cheerio const loader = new RecursiveUrlLoader(url, { extractor: compiledConvert, maxDepth: 50, getUrls: async (html, baseUrl) => { const $ = cheerio.load(html); const urls = []; $('a').each((i, el) => { let href = $(el).attr('href'); if (href) { // 标准化URL:去除锚点、统一查询参数顺序 const parsedUrl = new URL(href, baseUrl); parsedUrl.hash = ''; const params = new URLSearchParams(parsedUrl.search); parsedUrl.search = Array.from(params.entries()).sort().map(([k, v]) => `${k}=${v}`).join('&'); urls.push(parsedUrl.toString()); } }); // 去重 return [...new Set(urls)]; } });
4. 网络波动导致请求失败
爬取过程中网络不稳定,部分请求超时或失败,未被计入最终结果。
- 解决办法:添加请求重试机制,可通过包装loader的请求逻辑,或使用支持重试的HTTP客户端替代默认请求方式。
内容的提问来源于stack exchange,提问作者Olamide Onabiyi
相关产品推荐
相关产品推荐

