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
相关产品推荐
相关产品推荐

