在youtube页面中获取转换后的实际HTML(chrome扩展)

Getting the actual HTML after a transition accures in a youtube page (chrome extension)

本文关键字:HTML chrome 扩展 youtube 转换 获取      更新时间:2023-09-26

我正在开发一个chrome扩展,它应该在每个youtube观看页面中运行一个脚本(即,https://www.youtube.com/watch?v=YisbVr69r7U)

在这个脚本中,我想获得视频的itag(我可以通过解析yt.config中的"url_encoded_fmt_stream_map"属性从每个youtube视频页面中的脚本中获得)

问题是,我无法通过解析某些页面的(document.body.inerHTML)来找到该属性。

这是我的宣言.json:

{
  "manifest_version": 2,
  "name"            : "Test Extension",
  "version"         : "0.0",
  "background": {
    "scripts": ["background.js"]
  },
  "permissions": [
    "https://www.youtube.com/*", "tabs", "webNavigation"
  ]
}

我知道youtube使用页面之间的转换(例如,如果您单击要观看的视频,然后页面顶部出现红色条,然后显示视频页面),我使用webNavigationonHistoryStateUpdated事件在转换结束后执行页面脚本。

background.js:

const r = /https:'/'/www'.youtube'.com'/watch'?v=(.*?)(&.*)?/;
chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
    if(r.test(details.url))
        chrome.tabs.executeScript(details.tabId,{file:"script.js"});
});

和script.js:

function getURLMap(bodyHTML) {
    var r = /"url_encoded_fmt_stream_map":"(.*?)"/;
    var matches = bodyHTML.match(r);
    return matches[1];
}
function getTags(fmts_info) {
    var tags = [];
    r = /itag=(.*?)''u/;
    console.log(fmts_info[0]);
    for(var i = 0; i < fmts_info.length; i++) {
        matches = fmts_info[i].match(r);
        tags[i] = matches[1];
    }
    return tags;
}
console.log(getTags(getURLMap(document.body.innerHTML).split(',')));

当我直接转到youtube观看页面时,扩展功能做得很好(在chrome上打开一个新标签,然后直接说:https://www.youtube.com/watch?v=YisbVr69r7U),它在控制台中正确显示了该视频的itag。当我通过转换(例如,通过点击视频从youtube索引页面到视频页面)进入youtube观看页面时,问题就来了,在这种情况下,我在控制台中出现了以下错误:

Uncaught TypeError: Cannot read property '1' of null  script.js:4

当我让我的script.js在控制台中显示(document.body)时,我在中找不到"url_encoded_stream_map"

问题似乎出在我如何处理页面中的转换上。

我找了很多方法来解决我的问题,但都没用

我尝试过使用内容脚本,但内容脚本似乎是在页面加载时插入的,而不是在发生转换时插入的。

我想得到页面的实际HTML,里面有itag!

编辑:

这与没有重复

尝试过这个宣言.json:

{
  "manifest_version": 2,
  "name"            : "Test Extension",
  "version"         : "0.0",
  "content_scripts": [{
      "matches": [ "*://*.youtube.com/*" ],
      "js": [ "script.js" ],
      "run_at": "document_start"
  }]
}

script.js:

document.addEventListener("spfdone", process);
document.addEventListener("DOMContentLoaded", process);
function getURLMap(bodyHTML) {
    var r = /"url_encoded_fmt_stream_map":"(.*?)"/;
    var matches = bodyHTML.match(r);
    return matches[1];
}
function getTags(fmts_info) {
    var tags = [];
    r = /itag=(.*?)''u/;
    for(var i = 0; i < fmts_info.length; i++) {
        matches = fmts_info[i].match(r);
        tags[i] = matches[1];
    }
    return tags;
}
function process() {
    if (location.pathname != "/watch") {
        return;
    }
    console.log(getTags(getURLMap(document.body.innerHTML).split(',')));
}

但是问题没有解决!

如果调试脚本,您将看到在站点内导航后,url_encoded_fmt_stream_map没有添加到文档中的任何位置。对JS网站的黑客攻击表明,在这种情况下,ytplayer.config变量是直接更新的。

我们必须将脚本注入页面本身。

在manifest.json:中声明在所有youtube上运行的内容脚本

"content_scripts": [{
  "matches": [ "*://*.youtube.com/*" ],
  "js": [ "content.js" ],
  "run_at": "document_start"
}]

content.js:

function injectedCode() {
    document.addEventListener("spfdone", process);
    document.addEventListener("DOMContentLoaded", process);
    function process() {
        function getTags(fmts_info) {
            var tags = [];
            r = /itag=('d+)/;
            for(var i = 0; i < fmts_info.length; i++) {
                var matches = fmts_info[i].match(r);
                if (matches)
                    tags.push(matches[1]);
            }
            return tags;
        }
        if (location.href.indexOf('watch?') < 0) {
            return;
        }
        var tags = getTags(ytplayer.config.args.url_encoded_fmt_stream_map.split(','));
        console.log(tags);
    }
}
function getFunctionText(f) {
    return f.toString().match(/'{['s'S]*'}$/)[0];
}
document.documentElement.appendChild(document.createElement("script")).text =
    getFunctionText(injectedCode)

若要将结果传递回内容脚本,请使用自定义事件,或外部连接将数据直接发送到扩展的后台页面脚本。