如何从Chrome扩展程序中获取输入字段的值

16

我正在学习如何构建谷歌浏览器扩展程序。我在一个网页上有一个联系表单,我正在用它进行测试。我试图创建一个扩展程序,可以读取该表单中的输入字段值。目前为止,我拥有:

manifest.json

{
    "manifest_version": 2,

    "name": "Contact Form Friend",
    "description": "This extension gets contact form info.",
    "version": "1.0",

    "browser_action": {
      "default_icon": "icon.png",
      "default_popup": "popup.html"
    },

    "permissions": [
      "activeTab",
      "<all_urls>"
    ]
  }

弹出窗口.html

<!doctype html>
<html>
  <head>
    <title>Getting Started Extension's Popup</title>
    <style type="text/css">
      body {
        margin: 10px;
        white-space: nowrap;
      }

      h1 {
        font-size: 15px;
      }

      #container {
        align-items: center;
        display: flex;
        justify-content: space-between;
      }
    </style>

    <script src="popup.js"></script>
  </head>

    <body>
        <h1>Info</h1>
        <div id="info">

        </div>
    </body>
</html>

弹出框.js

function getHost() {
    return document.documentElement;
}

document.addEventListener('DOMContentLoaded', () => {
    const infoDisplay = document.getElementById('info');    
    const scriptToRun = `(${getHost})()`;

    // Run the script in the context of the tab
    chrome.tabs.executeScript({
      code: scriptToRun 
    }, (result) => {            
      var values = [];

      var inputFields = result.getElementsByTagName('input');
      infoDisplay.innerHTML = 'inputs: ' + inputFields.length;
      for (var i = 0; i < inputFields.length; i++) {
        values.push(inputFields[i].value);
      }

      infoDisplay.innerHTML += '<br />fields: ' + values.length;
    });
});
当我运行此代码时,它似乎无法访问用户所在的网页(而不是扩展程序的网页)中的输入字段。我做错了什么?我缺少权限吗?我不这么认为。然而,它没有起作用,我也不确定原因。
谢谢您的帮助。

你的扩展程序中的代码是否被执行了?还是DOM不是你所期望的那个? - marcofo88
@Zach Templeton,这里是你问题的答案:https://dev59.com/XWIj5IYBdhLWcg3w6JLU - beaver
4个回答

11

根据Gabriel Bleu的报道,你需要一个内容脚本来与Chrome标签内的网页进行交互。

下面是一个Chrome扩展示例,其中内容脚本向popup.js公开了两个“命令”。

请参见代码注释以获取说明。

manifest.json(类似于您的文件)

{
  "name": "My ext",
  "version": "0.1",
  "description": "my desc",
  "permissions": [
    "activeTab",
    "<all_urls>"
  ],
  "icons": {
    "128": "icon-128.png"
  },
  "browser_action": {
      "default_title": "My ext",
      "default_icon": "icon.png",
      "default_popup": "popup.html"
  },
  "manifest_version": 2,
  "content_security_policy": "script-src 'self' https://ajax.googleapis.com object-src 'self'"
}

弹出窗口.html(与您的类似,除了使用jQuery轻松进行DOM操作)

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script type="application/javascript" charset="utf-8" src="popup.js"></script>
</head>
<body class="body-popup">
    <button id="btn_check" class="btn btn-warning">check current tab</button>
    <hr>
    <div id="pg_url"></div>
    <hr>
    <div id="log"></div>
</body>
</html>

弹出框.js

$(function() {
    $('#btn_check').click(function() { checkCurrentTab(); });
});

function checkCurrentTab() {
    chrome.tabs.query({'active': true, 'lastFocusedWindow': true}, function (tabs) {
        var url = tabs[0].url;
        console.log("checkCurrentTab: "+url);
        $(".pg_url").text(url);

        // request content_script to retrieve title element innerHTML from current tab
        chrome.tabs.sendMessage(tabs[0].id, "getHeadTitle", null, function(obj) {
            console.log("getHeadTitle.from content_script:", obj);
            log("from content_script:"+obj);
        });

    });
}

document.addEventListener('DOMContentLoaded', function () {
    chrome.windows.getCurrent(function (currentWindow) {
        chrome.tabs.query({active: true, windowId: currentWindow.id}, function(activeTabs) {
            // inject content_script to current tab
            chrome.tabs.executeScript(activeTabs[0].id, {file: 'content_script.js', allFrames: false});
        });
    });
});

function log(txt) {
    var h = $("#log").html();
    $("#log").html(h+"<br>"+txt);
}

content_script.js

// you will see this log in console log of current tab in Chrome when the script is injected
console.log("content_script.js");

chrome.runtime.onMessage.addListener(function(cmd, sender, sendResponse) {
    console.log("chrome.runtime.onMessage: "+cmd);
    switch(cmd) {
    case "getHtml":
        // retrieve document HTML and send to popup.js
        sendResponse({title: document.title, url: window.location.href, html: document.documentElement.innerHTML});
        break;
    case "getHeadTitle":
        // retrieve title HTML and send to popup.js
        sendResponse(document.getElementsByTagName("title")[0].innerHTML);
        break;      
    default:
        sendResponse(null);
    }
});

P.S.:显然,jQuery并非必需


3
这个回答并没有帮助到OP想要实现的目标:从网页中读取一些“input”值。没有必要把事情搞得过于复杂化。 - Iván Nokonoko
@beaver,你能看一下我的问题吗?https://stackoverflow.com/questions/63285684/issue-in-website-login-using-chrome-extension - suryavansh
有人可以给我建议吗?我想要识别任何网页上是否存在密码输入。 - Rups

6

您收到的错误信息如下:

Error in response to tabs.executeScript: TypeError: result.getElementsByTagName is not a function
at Object.chrome.tabs.executeScript [as callback] (chrome-extension://lmaefdnejmkjjmgalgfofdbobhapfmoh/popup.js:15:32)
at HTMLDocument.document.addEventListener (chrome-extension://lmaefdnejmkjjmgalgfofdbobhapfmoh/popup.js:10:17)

不要在popup.js中尝试获取当前标签页的DOM,建议使用内容脚本来完成该任务,并将结果作为消息发送给弹出窗口。

manifest.json

{
    "manifest_version": 2,
    "name": "Contact Form Friend",
    "description": "This extension gets contact form info.",
    "version": "1.0",

    "browser_action": {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    },

    "permissions": [
        "activeTab",
        "<all_urls>"
    ],

    "content_scripts": [
        {
            "matches": ["http://*/*", "https://*/*"],
            "js": ["content.js"]
        }
    ]
}

manifest.json 文件中,您必须添加内容脚本并设置要注入脚本的站点的URL。 popup.js
document.addEventListener('DOMContentLoaded', () => {
    const infoDisplay = document.getElementById('info');    

    window.addEventListener('DOMContentLoaded', function () {
        chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
            chrome.tabs.sendMessage(tabs[0].id, {}, function (result) {
                infoDisplay.innerHTML = result
            });
        });
    });

});

popup.js 中向内容脚本发送请求,以获取输入字段的数量,并将响应插入到 div 中。 content.js
chrome.runtime.onMessage.addListener(function (msg, sender, response) {
    var values = [];
    var inputFields = document.getElementsByTagName('input');
    var result = 'inputs: ' + inputFields.length;

    for (var i = 0; i < inputFields.length; i++) {
        values.push(inputFields[i].value);
    }

    result += '<br />fields: ' + values.length;

    response(result)
});

创建一个名为content.js的新文件。该文件将被注入到网页中,监听从popup.js发送的消息。当接收到一条消息时,它会计算响应并将其发送回popup.js。
要了解更多关于内容脚本的信息,请查看文档

2
如果您的扩展需要与网页进行交互,则需要使用内容脚本。内容脚本是一些JavaScript代码,可以在已加载到浏览器中的页面上下文中执行。将内容脚本视为已加载页面的一部分,而不是其父级扩展打包的一部分。详见https://developer.chrome.com/docs/extensions/mv3/content_scripts/

-1
你的方法的主要问题是,你试图通过消息/ sendResponse 将DOM树从内容脚本发送到弹出窗口/后台以便在那里处理它。 无法通过消息/ sendResponse 发送 DOM 树。
更好的方法是在内容脚本中处理 DOM,并将所需信息(在您的情况下为值)发送回弹出窗口/后台页面。
可能的实现方式之一是:

popup.js

document.addEventListener('DOMContentLoaded', () => {
    const infoDisplay = document.getElementById('info');    
    const scriptToRun = `
        var values = [];
        var inputFields = document.getElementsByTagName('input');
        for (var i = 0; i < inputFields.length; i++) {
            values.push(inputFields[i].value);
        }
        values;`;  //all this code will be run on the tab page
                   //and the array "values" will be returned.

    chrome.tabs.executeScript({
      code: scriptToRun 
    }, (result) => {

        infoDisplay.innerHTML = `There are: ${result[0].length} inputs, with these values: <ol><li>${result[0].join("<li>")}`;  
    });
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接