You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现复杂网页结构的递归DOM爬取与内容解析?

递归爬取复杂网页DOM的实现思路

先理清楚你要解决的两个核心点:一是静态链接的递归遍历,二是像angular.html这类依赖前端渲染的动态页面的DOM解析,还要避免重复爬取相同链接。下面是具体的实现思路和代码示例:

一、基础静态页面递归爬取框架

先完善你现有的链接收集逻辑,加上递归和去重机制:

// 用Set存储已爬取链接,快速去重
const crawledLinks = new Set();
// 限定爬取范围的基础URI白名单,避免爬到外部网站
const allowedBaseURIs = ['https://website.com/page/', 'https://website.com/page/1'];

// 单页面爬取+DOM处理函数
async function crawlPage(url) {
  // 跳过已爬取或不在白名单内的链接
  if (crawledLinks.has(url) || !isAllowedUrl(url)) return;
  
  crawledLinks.add(url);
  console.log(`正在爬取: ${url}`);
  
  try {
    // 1. 获取页面静态HTML并解析为DOM
    const response = await fetch(url);
    const html = await response.text();
    const domParser = new DOMParser();
    const pageDoc = domParser.parseFromString(html, 'text/html');
    
    // 2. 打印DOM内容(按需调整,比如只打印特定区域或整个body)
    console.log(`页面${url}的DOM内容:\n`, pageDoc.body.innerHTML);
    
    // 3. 收集当前页面所有链接,递归爬取
    const allLinks = Array.from(pageDoc.querySelectorAll('a[href]')).map(link => link.href);
    for (const link of allLinks) {
      await crawlPage(link);
    }
  } catch (error) {
    console.error(`爬取${url}失败:`, error);
  }
}

// 判断链接是否在允许的爬取范围内
function isAllowedUrl(url) {
  return allowedBaseURIs.some(base => url.startsWith(base));
}

// 启动爬取,传入初始入口链接
crawlPage('https://website.com/page/');

二、处理动态加载页面(如angular.html)

上面的fetch只能拿到静态HTML,没法处理Angular渲染的动态内容,得用模拟浏览器加载的方式:
如果是在浏览器控制台或油猴脚本里运行,可以用iframe加载页面,等渲染完成后再解析DOM:

async function crawlDynamicPage(url) {
  if (crawledLinks.has(url) || !isAllowedUrl(url)) return;
  
  crawledLinks.add(url);
  console.log(`正在爬取动态页面: ${url}`);
  
  return new Promise((resolve, reject) => {
    const iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    iframe.src = url;
    
    iframe.onload = async () => {
      try {
        // 等待页面内的JS渲染完成(根据页面实际情况调整等待时间,或监听特定元素)
        await new Promise(resolve => setTimeout(resolve, 2000));
        
        // 获取iframe里的完整DOM
        const pageDoc = iframe.contentDocument || iframe.contentWindow.document;
        console.log(`动态页面${url}的DOM内容:\n`, pageDoc.body.innerHTML);
        
        // 收集链接并递归爬取
        const allLinks = Array.from(pageDoc.querySelectorAll('a[href]')).map(link => link.href);
        for (const link of allLinks) {
          await crawlDynamicPage(link);
        }
        
        document.body.removeChild(iframe);
        resolve();
      } catch (error) {
        reject(error);
      }
    };
    
    iframe.onerror = (error) => {
      console.error(`加载动态页面${url}失败:`, error);
      document.body.removeChild(iframe);
      reject(error);
    };
    
    document.body.appendChild(iframe);
  });
}

// 启动动态页面爬取
crawlDynamicPage('https://website.com/page/1/angular.html');

三、必须注意的几个点

  • 跨域问题:浏览器的同源策略会阻止你加载不同域名的页面,如果目标网站没开跨域权限,建议用Node.js配合Puppeteer(无头浏览器)来爬取,完全规避跨域限制。
  • 爬取频率控制:递归爬取太频繁容易被服务器拦截,建议在每次递归调用前加个延迟,比如await new Promise(resolve => setTimeout(resolve, 1000)),降低请求速率。
  • 动态渲染等待:如果页面加载时间不确定,不要硬写等待时间,可以用MutationObserver监听页面内特定元素的出现,确认渲染完成后再解析DOM。

内容的提问来源于stack exchange,提问作者Paul9002

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 19:20:59