Расширение Google Chrome. Проблема с доступом к элементам во вложенных фреймах в JavaScript

Рейтинг: 0Ответов: 1Опубликовано: 19.07.2023

подскажите как получить доступ к элементам таблицы во вложенных фреймах из расширения. Вместо значения, я получаю null или undefined. Все вложенные фреймы на странице получают контент с одного домена.

Как я могу получить доступ к элементам таблицы, которая находится внутри вложенного фрейма? Просмотрел множество вопросов схожих с моим, но так и не нашел решение своей проблемы. Возможно, я упускаю что-то в своем коде или существует более эффективный способ достижения этой цели?

Заранее спасибо за помощь!

Вот пример структуры страницы, которую нужно парсить:

<html>
      <head>
        <title>Outer Frame</title>
      </head>
      <body>
        <frame name="mn_mgn">
          <html>
            <head>
              <title>Inner Frame 1</title>
            </head>
            <body>
              <frame name="mn_mgn">
                <html>
                  <head>
                    <title>Inner Frame 2</title>
                  </head>
                  <body>
                    <frame name="mn_total">
                      <html>
                        <head>
                          <title>Inner Frame 3</title>
                        </head>
                        <body>
                          <frame name="mn_center">
                            <html>
                              <head>
                                <title>Inner Frame 4</title>
                              </head>
                              <body>
                              <frame name="other_frame">
                                    <html>
                                    <head>
                                      <title>Other frame</title>
                                    </head>
                                    <body>
                                    </body>
                                  </html>
                               </frame>
                              <frame name="mn_main">
                                  <html>
                                    <head>
                                      <title>Inner Frame 5</title>
                                    </head>
                                    <body>
                                      <form>
                                        <table>
                                          <span>Сюда надо попасть</span>
                                        </table>
                                      </form>
                                    </body>
                                  </html>
                                </frame>
                              </body>
                            </html>
                          </frame>
                        </body>
                      </html>
                    </frame>
                  </body>
                </html>
              </frame>
            </body>
          </html>
        </frame>
      </body>
    </html>

Так выглядит popup.js

document.addEventListener("DOMContentLoaded", function () {
    chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
      var tab = tabs[0];
      var tabId = tab.id;
  
      chrome.scripting.executeScript({
        target: { tabId: tabId },
        function: calculateOnPage
      });
    });
  });
  
  function calculateOnPage() {
    function calculate() {
      
      var outerFrame = document.querySelector("frame[name='mn_mgn']"); 
      outerFrame.onload = function() { 
        var innerFrame1 = outerFrame.contentDocument.body.querySelector("frame[name='mn_mgn']"); 
        innerFrame1.onload = function() { 
          var innerFrame2 = innerFrame1.contentDocument.body.querySelector("frame[name='mn_total']"); 
          innerFrame2.onload = function() { 
              var innerFrame4 = innerFrame2.contentDocument.body.querySelector("frame[name='mn_center']"); 
              innerFrame4.onload = function() { 
                var innerFrame5 = innerFrame4.contentDocument.body.querySelector("frame[name='mn_main']"); 
                innerFrame5.onload = function() { 
                  var val1 = innerFrame5.contentDocument.body.querySelector('html > body > form > table:nth-child(7) > tbody > tr:nth-child(5) > td:nth-child(4)'); 
                  var val2 = innerFrame5.contentDocument.body.querySelector('html > body > form > table:nth-child(7) > tbody > tr:nth-child(6) > td:nth-child(4)'); 
                  var val3 = innerFrame5.contentDocument.body.querySelector('html > body > form > table:nth-child(7) > tbody > tr:nth-child(7) > td:nth-child(4)'); 
                  
                  var result = parseFloat(val1/1000) * parseFloat(val2/1000) * parseFloat(val3/1000); 
 
                  result = result.toFixed(4); 
 
                  chrome.runtime.sendMessage({ action: "displayResult", result: result }); 
 
                  alert(result); 
                }; 
              }; 
            }; 
          }; 
        };
    }
  
    calculate();
  }
  
  chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    if (message.action === "displayResult") {
      var result = message.result;
      
      var resultElement = document.getElementById("result");
      resultElement.textContent = "Результат: " + result;
    }
  });
  
  

Такой manifest.js

{
    "manifest_version": 3,
    "name": "Calculator",
    "version": "1.0",
    "description": "Калькулятор вычисления площади",
    "permissions": [
      "activeTab",
      "scripting",
      "notifications"
    ],
    "action": {
      "default_popup": "popup.html",
      "default_icon": {
        "16": "icon_16.png",
        "48": "icon_48.png",
        "128": "icon_128.png"
      }
    },
    "icons": {
      "16": "icon_16.png",
      "48": "icon_48.png",
      "128": "icon_128.png"
    },
    "background": {
      "service_worker": "background.js"
    }
  }
  

Вот background.js

chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    if (message.action === "displayResult") {
      var result = message.result;
      chrome.notifications.create({
        type: "basic",
        iconUrl: "icon_16.png",
        title: "Результаты подсчетов",
        message: "Результат: " + result
      });
    }
  });
  

Таким образом пытался "достучаться" до нужного фрейма из консоли, работает, но только если выбрать контекст нужного фрейма, в остальных случая возвращает null. Код:

function findInFramesRec(selector, doc) {
  var hit = doc.querySelector(selector);
  if (hit) return hit;
  var frames = Array.from(window.frames);
  for (var i = 0; i < frames.length && !hit; i++) {
    try {
      if (!frames[i] || !frames[i].document) continue;
      hit = findInFramesRec(selector, frames[i].document);
    } catch (e) {}
  }
  return hit;
}

var result = findInFramesRec("table:nth-child(7) > tbody > tr:nth-child(5) > td:nth-child(4)", document);
alert(result);

Ответы

▲ 0

Я не профии может за последнее время что-то поменялось, но:

  • Проверьте, для начала можете ли вы получить доступ к другим(любым) элементам на странице? В чем я сомневаюсь.
  • popup.js изначально, это скрипт, который срабатывает каждый раз, когда у вас открывается окошко(интерфейс) расширения. И он может работать, только с элементами этого интерфейса. А у вас я не вижу, чтобы он хоть куда-то подключался.
  • Вот это: "background": { "service_worker": "background.js" } Это код для работы фоновых скриптов. Обычно подобный фоновый скрипт, кто-то использует для встраивания кода в начало/или конец страницы.
  • Я не вижу у вас в манифесте(может правила и поменялись) правила которое указывает какой скрипт и на какой странице должен отрабатывать?
  • Насколько я помню(могу и ошибаться), общение скрипта, что работает со страницей и интерфейса расширения происходит через сообщения или chrome.storage
  • Когда ваш код будет работать с элементами на странице. То и доступ внутрь iframe вы получите после полного построения dom.
  • Вам необходимо больше почитать про манифест. Скорее всего это ваше первое расширение и вы не совсем понимаете, как оно должно работать.