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

Chrome扩展爬取动态页面返回JS代码,如何正确获取可解析HTML?

问题描述

我正在开发一款Chrome扩展,当用户访问站点A时,该扩展会聚合多个站点的信息。我编写了以下代码尝试爬取目标页面并提取元素:

async function fetchHTML(url) {
    const response = await fetch(proxyUrl + url);
    const html = await response.text();
    console.log(html);
    return html;
}

// 从HTML内容中提取total violations元素
function extractTotalViolations(html) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, "text/html");
    const totalViolations = doc.querySelector(".total-violations").textContent;
    return totalViolations;
}

// 要爬取的页面URL
const url = "https://whoownswhat.justfix.org/en/address/MANHATTAN/610/EAST%2020%20STREET";

// 获取HTML内容并提取total violations
fetchHTML(url).then(html => {
    const totalViolations = extractTotalViolations(html);
    console.log(totalViolations);
});

但打印totalViolations时得到NULL,打印获取到的HTML后发现返回的是一段JavaScript代码:

<script>
!function(e){function t(t){for(var n,l,i=t[0],f=t[1],a=t[2],p=0,s=[];p<i.length;p++)l=i[p],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(c&&c(t);s.length;)s.shift()();return u.push.apply(u,a||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,i=1;i<r.length;i++){var f=r[i];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=l(l.s=r[0]))}return e}var n={},o={1:0},u=[];function l(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,l),r.l=!0,r.exports}l.m=e,l.c=n,l.d=function(e,t,r){l.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",
</script>

这段代码和直接访问网站看到的HTML完全不同,我怀疑网站采用了JavaScript渲染或我的HTML获取方式有误,请问如何正确提取HTML以解析DOM并获取所需信息?

解决方案

你遇到的核心问题是目标网站属于JavaScript渲染的单页应用(SPA):直接用fetch请求只会拿到页面的初始骨架(包含打包后的JS代码),实际内容是浏览器加载并执行JS后动态生成的,因此静态解析HTML无法获取到目标元素。

针对Chrome扩展场景,最直接的解决方式是利用Chrome扩展API,在真实浏览器标签页中加载目标页面,再注入脚本提取渲染后的DOM内容,具体步骤如下:

1. 配置扩展权限

首先在manifest.json中添加必要的权限:

{
  "manifest_version": 3,
  "name": "你的扩展名称",
  "version": "1.0",
  "permissions": ["tabs", "scripting"],
  "host_permissions": ["https://whoownswhat.justfix.org/*"]
}

2. 使用Chrome API加载页面并提取内容

替换原有的fetchHTML逻辑,改用chrome.tabs.create创建标签页,再通过chrome.scripting.executeScript注入脚本获取目标元素:

const targetUrl = "https://whoownswhat.justfix.org/en/address/MANHATTAN/610/EAST%2020%20STREET";

// 创建标签页加载目标页面
chrome.tabs.create({ url: targetUrl, active: false }, (tab) => {
  // 监听标签页加载完成事件
  const loadListener = (tabId, changeInfo) => {
    if (tabId === tab.id && changeInfo.status === "complete") {
      // 注入脚本到目标页面上下文,提取元素
      chrome.scripting.executeScript({
        target: { tabId: tab.id },
        func: () => {
          // 此代码在目标页面的浏览器环境中执行
          const totalViolationsEl = document.querySelector(".total-violations");
          return totalViolationsEl ? totalViolationsEl.textContent.trim() : null;
        }
      }, (results) => {
        if (results?.[0]) {
          console.log("Total Violations:", results[0].result);
          // 这里可以处理获取到的数据,比如传递到扩展的popup或背景页
        }
        // 移除监听器并关闭标签页(可选,根据需求调整)
        chrome.tabs.onUpdated.removeListener(loadListener);
        chrome.tabs.remove(tab.id);
      });
    }
  };
  chrome.tabs.onUpdated.addListener(loadListener);
});

额外注意事项

  • 若不想打开新标签页,可结合chrome.webNavigation和scriptingAPI在后台处理,但上述方式更直观易调试。
  • 该方法利用真实浏览器环境执行JS,能绕过大多数基于静态请求的反爬机制。
  • 批量爬取时需控制标签页创建数量,避免触发浏览器性能问题或网站反爬限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:12:28