Node.js中如何用for循环迭代URL实现多页HTML批量爬取
最简实现方案
核心逻辑非常直接:把单页爬取逻辑封装为可复用函数,通过for循环按页码生成目标URL,逐页爬取解析后汇总所有结果统一返回即可。注意异步请求必须做等待处理,否则会出现数据未爬完就提前返回响应的问题。
具体修改步骤
- 移除原有写死的单页URL常量,新增基础URL前缀、最大爬取页码两个配置项,方便后续调整
- 把单页的axios请求、cheerio解析逻辑抽成独立异步函数,入参为页码,返回当前页解析出的文章列表
- 在
/results路由的处理函数中加for循环,从页码1开始迭代到设定的最大页码,逐页调用爬取函数,把每一页的结果合并到总结果数组 - 所有页面爬取完成后,再把汇总的总结果返回
- 顺手修复原代码里的变量名冲突问题:原代码中解析文章链接时定义的
url变量和外层URL变量重名,改成articleUrl避免污染
修改后可直接运行的完整代码
const PORT = 8000 const axios = require('axios') const cheerio = require('cheerio') const express = require('express') const app = express() const cors = require('cors') app.use(cors()) // 配置项:按实际需求修改即可 const BASE_URL = 'https://www.example.com/' const MAX_PAGE = 10 // 要爬取的最大页码 const REQUEST_INTERVAL = 500 // 每页爬取间隔(毫秒),避免请求太频繁被拦截 // 单页爬取解析逻辑封装 async function crawlSinglePage(pageNum) { try { const response = await axios(`${BASE_URL}${pageNum}`) const html = response.data const $ = cheerio.load(html) const pageArticles = [] $('.fc-item__title', html).each(function () { const title = $(this).text().trim() const articleUrl = $(this).find('a').attr('href') pageArticles.push({ title, url: articleUrl, page: pageNum // 可选:标记内容来源页码,不需要可以删掉 }) }) return pageArticles } catch (err) { console.log(`第${pageNum}页爬取失败:`, err.message) return [] // 单页出错不中断整体任务,返回空数组跳过该页 } } app.get('/', function (req, res) { res.json('This is my parser') }) app.get('/results', async (req, res) => { const allArticles = [] // 逐页循环爬取 for (let currentPage = 1; currentPage <= MAX_PAGE; currentPage++) { const pageData = await crawlSinglePage(currentPage) allArticles.push(...pageData) // 爬完一页等待指定间隔再爬下一页 await new Promise(resolve => setTimeout(resolve, REQUEST_INTERVAL)) } res.json(allArticles) }) app.listen(PORT, () => console.log(`server running on PORT ${PORT}`))
可选扩展:自动识别终止页
如果你不想提前固定最大页码,想要爬到没有内容的页面就自动停止,只需要在循环内部加个判断即可:
for (let currentPage = 1; ; currentPage++) { // 不设循环上限 const pageData = await crawlSinglePage(currentPage) // 当前页没有爬到内容,直接跳出循环终止爬取 if (pageData.length === 0) break allArticles.push(...pageData) await new Promise(resolve => setTimeout(resolve, REQUEST_INTERVAL)) }
注意:如果追求爬取速度,可以把串行for循环改成
Promise.all并发请求,但一定要控制并发数,否则短时间请求量过大很容易被目标站点封禁IP,新手直接用串行方案最稳定。
内容的提问来源于stack exchange,提问作者user15255713
相关产品推荐
相关产品推荐

