Chrome插件获取页面请求内容

kyaa111 3月前 ⋅ 476 阅读

先代理xhr/fetch对象

common.js

const shopee_get_product_10045487 = "/api/v4/pdp/get_pc";

const api_category_34a10fd6 = {};

api_category_34a10fd6[shopee_get_product_10045487] = "getProduct";

const rule_api_3ea67778 = {
  shopee: [shopee_get_product_10045487],
};

const site_map_e68a0688 = {
  "shopee.sg": "shopee",
  "shopee.tw": "shopee",
  "shopee.com.my": "shopee",
  "shopee.ph": "shopee",
  "shopee.co.th": "shopee",
  "shopee.vn": "shopee",
  "shopee.com.br": "shopee",
  "shopee.co.id": "shopee",
  "shopee.com.mx": "shopee",
};

page/interceptor.js

let config_2550ac5d = {
  proxy_url: [],
  setUrl: function (site) {
    this.proxy_url = rule_api_3ea67778[site];
  },
  match: function (url) {
    return this.proxy_url.filter((n) => url.indexOf(n) > -1).length > 0;
  },
  get: function (url) {},
};

config_2550ac5d.setUrl(site_map_e68a0688[window.location.hostname]);

function sendEvent(_type, _url, _data) {
  window.postMessage(
    {
      type: "proxy-response",
      text: {
        site: site_map_e68a0688[window.location.hostname],
        data: _data,
        url: _url,
      },
    },
    "*"
  );
}

let proxy_interceptor = {
  originalXHR: window.XMLHttpRequest,
  pluginXHR: function () {
    const xhr = new proxy_interceptor.originalXHR();
    for (let attr in xhr) {
      if (attr === "onreadystatechange") {
        xhr.onreadystatechange = (...args) => {
          this.onreadystatechange && this.onreadystatechange.apply(this, args);
        };
        this.onreadystatechange = null;
        continue;
      } else if (attr === " (...args) => {
          if (config_2550ac5d.match(this.responseURL)) {
            sendEvent("xhr", this.responseURL, this.responseText);
          }
          this. null;
        continue;
      } else if (attr === "open") {
        this.open = (...args) => {
          xhr.open && xhr.open.apply(xhr, args);
        };
        continue;
      } else if (attr === "setRequestHeader") {
        this.setRequestHeader = (...args) => {
          xhr.setRequestHeader && xhr.setRequestHeader.apply(xhr, args);
        };
        continue;
      } else if (attr === "send") {
        this.send = (...args) => {
          xhr.send && xhr.send.apply(xhr, args);
        };
        continue;
      }

      if (typeof xhr[attr] === "function") {
        this[attr] = xhr[attr].bind(xhr);
      } else {
        Object.defineProperty(this, attr, {
          get: () => xhr[attr],
          set: (val) => (xhr[attr] = val),
          enumerable: true,
        });
      }
    }
  },
  originalFetch: window.fetch.bind(window),
  pluginFetch: (url, t) =>
    proxy_interceptor.originalFetch(url, t).then(async (response) => {
      if (config_2550ac5d.match(url)) {
        const data = await response.clone().json();
        sendEvent("fetch", url, data);
      }
      return response;
    }),
};

window.XMLHttpRequest = proxy_interceptor.pluginXHR;
window.fetch = proxy_interceptor.pluginFetch;

content-script.js

const common_script = document.createElement("script");
common_script.setAttribute("type", "text/javascript");
common_script.setAttribute("src", chrome.runtime.getURL("common.js"));
// 注意不能异步加载, 否则interceptor.js注入到页面时, 可能加载不到common.js
common_script.async = false;
document.documentElement.appendChild(common_script);

const interceptor_script = document.createElement("script");
interceptor_script.setAttribute("type", "text/javascript");
interceptor_script.setAttribute(
  "src",
  chrome.runtime.getURL("page/interceptor.js")
);
interceptor_script.async = false;
document.documentElement.appendChild(interceptor_script);

var data_cache = {};

window.addEventListener(
  "message",
  (event) => {
    if (event.source !== window) {
      return;
    }
    if (event.data.type && event.data.type === "proxy-response") {
      
      let temp;
      if (typeof event.data.text === "string") {
        temp = JSON.parse(event.data.text);
      } else {
        temp = event.data.text;
      }
      let key = Object.keys(api_category_34a10fd6).filter((url) => temp.url.indexOf(url) > -1);
      data_cache[api_category_34a10fd6[key]] = event.data.text;
    }
  },
  false
);
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
  if (request.action === "get_title_description") {
    sendResponse(data_cache);
  }
});

service-worker.js


chrome.scripting.getRegisteredContentScripts(
  { ids: ["testing-scripts-gen"] },
  async (scripts) => {
    if (scripts && scripts.length) {
      await chrome.scripting.unregisterContentScripts({
        ids: ["testing-scripts-gen"],
      });
    }
    chrome.scripting.registerContentScripts([
      {
        id: "testing-scripts-gen",
        // 如content-script依赖其他js, 则需要在此写明, 不能使用import等模块关键字
        js: ["./content-script.js", "./common.js"],
        matches: [
          "*://shopee.sg/*",
          "*://shopee.tw/*",
          "*://shopee.com.my/*",
          "*://shopee.ph/*",
          "*://shopee.co.th/*",
          "*://shopee.vn/*",
          "*://shopee.com.br/*",
          "*://shopee.co.id/*",
          "*://shopee.com.mx/*"
        ],
        runAt: "document_start",
        allFrames: true,
      },
    ]);
  }
);

popup.js


chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
    chrome.tabs.sendMessage(
      tabs[0].id,
      {action: "get_title_description"},
      function (data) {
        if (data?.getProduct) {
          parseGetProduct(data.getProduct)
        }
      }
    );
  });

流程

  1. xhr代理对象拦截到指定url的请求后, 将请求内容发送到content-script
  2. content-script接收到内容, 将其缓存起来
  3. popupcontent-script发送消息
  4. content-script响应消息, 将缓存的请求内容返回给popup