如何从无限滚动页面的DOM中持续抓取数据?
滚动抓取网页动态加载内容的解决方案
一、正确获取新插入的DOM节点
你当前的代码存在一处小错误:转换数组时误用了旧的theSearch集合,修正后就能正常获取新节点:
// 滚动后重新查询DOM中所有符合类名的元素 var theSearch2 = document.getElementsByClassName('theID'); // 将新查询到的集合转为数组(注意这里要使用theSearch2) var arr2 = Array.prototype.slice.call(theSearch2); // 合并新元素到原数组,同时去重避免重复添加 arr = [...new Set([...arr, ...arr2])];
注意:直接用push(...arr2)会重复加入已存在的元素,借助Set去重能保证数组内元素唯一。
二、持续抓取直到无新内容加载
由于页面滚动后加载新内容是异步操作,不能立刻查询DOM,需要结合等待与数量检测实现循环抓取,直到元素数量不再变化:
方案1:异步函数+定时等待
async function scrapeAllItems() { let arr = []; let lastItemCount = 0; let noChangeTimes = 0; // 连续无变化次数,避免因加载延迟误判 while (true) { // 获取当前所有目标元素 const currentItems = Array.from(document.getElementsByClassName('theID')); // 去重合并到结果数组 arr = [...new Set([...arr, ...currentItems])]; // 检测元素数量是否变化 if (currentItems.length === lastItemCount) { noChangeTimes++; // 连续3次无变化则停止抓取 if (noChangeTimes >= 3) break; } else { noChangeTimes = 0; lastItemCount = currentItems.length; // 滚动到底部触发新内容加载 window.scrollTo(0, document.body.scrollHeight); } // 等待页面加载新内容,时间可根据页面加载速度调整 await new Promise(resolve => setTimeout(resolve, 1000)); } console.log('抓取完成,总条目数:', arr.length); return arr; } // 启动抓取 scrapeAllItems();
方案2:定时器循环检测
let arr = []; let lastItemCount = 0; let noChangeTimes = 0; // 每隔1秒检测一次 const scrapeInterval = setInterval(() => { const currentItems = Array.from(document.getElementsByClassName('theID')); arr = [...new Set([...arr, ...currentItems])]; if (currentItems.length === lastItemCount) { noChangeTimes++; if (noChangeTimes >= 3) { clearInterval(scrapeInterval); console.log('抓取完成,总条目数:', arr.length); } } else { noChangeTimes = 0; lastItemCount = currentItems.length; window.scrollTo(0, document.body.scrollHeight); } }, 1000);
说明:设置noChangeTimes是为了应对页面加载延迟的情况,连续几次数量不变再停止,避免提前终止抓取。等待时间可根据目标页面的加载速度调整,比如图片较多的页面可设为2000ms。
内容的提问来源于stack exchange,提问作者Chris Norman
相关产品推荐
相关产品推荐

