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

Chrome扩展:获取当前Tab中<div>元素并打印的问题排查

Chrome扩展问题排查:无法获取Greenhouse类网页内容并显示

问题现象

点击弹窗的Fetch Job Requirements按钮无反应,控制台报错:Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'matchedRequirements'),预期是将活跃Tab中id="content"的<div>内的<p>和<li>内容显示在弹窗的matchedRequirements区域。

自我推测问题点

  • 元素选择器使用不当:document.querySelector("#content").querySelectorAll("p, ul > li")可能因<div>内存在其他元素(如<hr>)导致异常
  • <div>内容处理错误:NodeList转文本数组的方式有误
  • 异步通信逻辑错误:popup.js、content.js与background.js间的chrome.runtime.sendMessage通信存在问题
  • Tab信息传递错误:未正确向content.js传递Tab信息

现有代码文件

manifest.json

已添加run_at": "document_end"尝试解决时机问题

{
"manifest_version": 3,
"name": "Experience Tracker",
"version": "1.0",
"description": "Track your work experiences and match with job requirements.",
"permissions": [
  "activeTab"
],
"background": {
  "service_worker": "background.js"
},
"content_scripts": [
  {
    "matches": ["<all_urls>"],
    "js": ["content.js"],
    "run_at": "document_end"
  }
],
"action": {
  "default_popup": "popup.html",
  "default_icon": {
    "16": "images/icon16.png",
    "48": "images/icon48.png",
    "128": "images/icon128.png"
  }
}
}
<!DOCTYPE html>
<html>
<head>
  <title>Experience Tracker</title>
  <script src="popup.js"></script>
</head>
<body>
  <!-- 触发获取职位要求的按钮 -->
  <button id="fetchRequirements">Fetch Job Requirements</button>
  <hr>
  <h2>Matched Requirements</h2>
  <!-- 用于显示活跃Tab中<div id="content">内容的段落 -->
  <p id="matchedRequirements"></p>
</body>
</html>

点击按钮时向后台发送请求,期望获取响应后渲染内容

const fetchRequirements = async () => {
    const request = {
    action: "fetchRequirements"
    };
    
    const response = await chrome.runtime.sendMessage(request);
    
    if (response.matchedRequirements) {
        const requirementsHtml = response.matchedRequirements.map(requirement => {
          return `<div>${requirement}</div><br>`;
        }).join("");
        document.getElementById("matchedRequirements").innerHTML = requirementsHtml;
      }
    };
     
    document.addEventListener("DOMContentLoaded", function() {
        const fetchRequirementsButton = document.getElementById("fetchRequirements");
        const matchedRequirementsList = document.getElementById("matchedRequirements");
    
        fetchRequirementsButton.addEventListener("click", async () => {
            await fetchRequirements();
        });
    });

content.js

负责提取网页中id="content"内的<p>和<li>文本

function fetchRequirements() {
    const requirements = [];
    const contentElements = document.querySelector("#content").querySelectorAll("p, ul > li");
    for (const contentElement of contentElements) {
      requirements.push(contentElement.textContent);
    }
  
    chrome.runtime.sendMessage({
      action: "fetchRequirements",
      matchedRequirements: requirements
    });
  }

background.js

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.requirements) {
      chrome.storage.local.set({ matchedRequirements: request.requirements });
    }
  });

核心错误分析与修正方案

1. 通信逻辑完全错误

当前流程是popup给后台发消息,但后台既没处理这个请求,也没转发给content脚本;content脚本的fetchRequirements函数也从未被调用,导致popup收不到任何响应,才会出现response为undefined的报错。

正确流程应该是:popup点击按钮后,直接向活跃Tab的content脚本发送消息,触发内容提取,content脚本提取完成后直接回复popup,不需要经过background(除非需要持久化存储,当前需求不需要)。

2. 元素选择器容错不足

如果页面中不存在id="content"的元素,document.querySelector("#content")会返回null,调用querySelectorAll会直接报错,需要增加判断。

修正后的代码

popup.js

const fetchRequirements = async () => {
  try {
    // 获取当前活跃Tab,向其content脚本发送消息
    const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true });
    if (!activeTab.id) return;

    // 向content脚本发送请求,触发内容提取
    const response = await chrome.tabs.sendMessage(activeTab.id, { action: "fetchRequirements" });
    
    if (response?.matchedRequirements) {
      const requirementsHtml = response.matchedRequirements
        .filter(req => req.trim()) // 过滤空文本
        .map(requirement => `<div>${requirement}</div><br>`)
        .join("");
      document.getElementById("matchedRequirements").innerHTML = requirementsHtml;
    } else {
      document.getElementById("matchedRequirements").textContent = "未找到匹配的内容";
    }
  } catch (err) {
    document.getElementById("matchedRequirements").textContent = `提取失败:${err.message}`;
    console.error(err);
  }
};

document.addEventListener("DOMContentLoaded", function() {
  const fetchRequirementsButton = document.getElementById("fetchRequirements");
  fetchRequirementsButton.addEventListener("click", fetchRequirements);
});

content.js

// 监听来自popup的消息,触发内容提取
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "fetchRequirements") {
    const requirements = [];
    // 先判断content元素是否存在
    const contentDiv = document.querySelector("#content");
    if (!contentDiv) {
      sendResponse({ matchedRequirements: [] });
      return;
    }
    // 获取目标元素
    const contentElements = contentDiv.querySelectorAll("p, ul > li");
    for (const el of contentElements) {
      const text = el.textContent.trim();
      if (text) requirements.push(text); // 只保留非空文本
    }
    // 向popup返回结果
    sendResponse({ matchedRequirements: requirements });
  }
  // 标记异步响应(兼容潜在异步场景)
  return true;
});

background.js

当前需求无需后台逻辑,可留空:

// 当前需求无后台逻辑,可留空

manifest.json

无需修改,保持原配置即可。

测试验证

  1. 重新加载扩展
  2. 打开Greenhouse类网页(确保存在id="content"的div)
  3. 点击扩展弹窗的按钮,即可看到提取的内容显示在弹窗中

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 04:17:33