Chrome扩展中用JavaScript获取YouTube视频标题失败求助
问题:Chrome扩展Content Script无法获取YouTube视频标题子元素
我正在学习开发Chrome扩展,想要实现一个能在控制台打印当前YouTube视频标题的简单扩展。页面中YouTube标题的HTML结构如下:
<div id="title" class="style-scope ytd-watch-metadata"> <ytd-badge-supported-renderer class="style-scope ytd-watch-metadata" disable-upgrade="" hidden=""> </ytd-badge-supported-renderer> <h1 class="style-scope ytd-watch-metadata"> <yt-formatted-string force-default-style="" class="style-scope ytd-watch-metadata">Elon’s "based" Grok AI has entered the chat…</yt-formatted-string> </h1> <ytd-badge-supported-renderer class="style-scope ytd-watch-metadata" disable-upgrade="" hidden=""> </ytd-badge-supported-renderer> </div>
我在Content Script中编写了如下代码:
(()=>{ console.log(document.getElementById("title")); console.log(document.querySelector("#title > h1 > yt-formatted-string")); })();
执行后第一行能输出title元素,但第二行获取子元素返回null。在Chrome控制台直接输入该代码能得到正确结果。我尝试过DOMContentLoaded等方法,均无效,manifest.json配置如下:
{ "manifest_version": 3, "name": "FillModule", "description": "Fill test 001", "version": "1.0.0", "permissions": ["storage", "tabs"], "author":"Aniket Vishwakarma", "action": { "default_icon": "assets/doggy.png", "default_title": "Fill", "default_popup": "popup/popup.html" }, "background" : { "service_worker": "background/background.js" }, "content_scripts": [ { "matches": ["https://*.youtube.com/*"], "js": ["content/content.js"] } ] }
原因分析
- YouTube是单页应用(SPA),视频页面的核心内容通过JavaScript动态渲染。Content Script默认在初始DOM加载完成后执行,但此时标题的子元素(
h1和yt-formatted-string)还未被插入到DOM中。 DOMContentLoaded事件仅监听初始DOM树加载完成,无法感知后续通过JS动态插入的内容。- 直接在控制台执行代码时,页面已完全渲染完毕,所有动态内容都已加载,因此能正常获取目标元素。
解决方案
方法1:使用MutationObserver监听DOM变化
通过监听title元素的子节点变化,当目标子元素出现时立即获取并停止监听:
(() => { const titleDiv = document.getElementById('title'); if (!titleDiv) return; const observer = new MutationObserver((mutations) => { const targetElement = titleDiv.querySelector('h1 > yt-formatted-string'); if (targetElement) { console.log('视频标题:', targetElement.textContent); observer.disconnect(); // 获取到元素后停止监听,避免重复触发 } }); // 监听title元素的子节点变化,包括子树内的变化 observer.observe(titleDiv, { childList: true, subtree: true }); })();
方法2:定时检查目标元素
通过定时轮询的方式,直到目标元素出现为止:
(() => { function getVideoTitle() { const titleElement = document.querySelector('#title > h1 > yt-formatted-string'); if (titleElement) { console.log('视频标题:', titleElement.textContent); } else { setTimeout(getVideoTitle, 500); // 每隔500毫秒检查一次 } } getVideoTitle(); })();
方法3:监听YouTube自定义导航事件
YouTube提供了自定义的yt-navigate-finish事件,用于标记SPA页面切换完成,可通过监听该事件重新获取标题:
(() => { function handlePageLoad() { const titleElement = document.querySelector('#title > h1 > yt-formatted-string'); if (titleElement) { console.log('视频标题:', titleElement.textContent); } } // 页面初始加载时执行一次 handlePageLoad(); // 监听SPA页面切换事件,切换视频时重新获取标题 document.addEventListener('yt-navigate-finish', handlePageLoad); })();
内容的提问来源于stack exchange,提问作者Aniket Vishwakarma
相关产品推荐
相关产品推荐

