Chrome扩展无法获取网页window.scrollY值的问题求助
问题
我在用JS编写Chrome扩展抓取网页数据,目标网站是https://tellonym.me/tells,需要获取window.scrollY属性,但直接调用它始终返回0。我试了一种方法能在控制台打印正确值,但没法返回结果,没法实际使用:
function getScrollY() { var actualCode = 'console.log(window.scrollY)'; document.documentElement.setAttribute('onreset', actualCode); document.documentElement.dispatchEvent(new CustomEvent('reset')); document.documentElement.removeAttribute('onreset'); }
我的内容脚本TellScrape.js里打印window.scrollY一直是0,但控制台其他输出能看到scrollY是非零值。以下是用到该属性的代码片段:
async function startScraping() { // Keep track of the span elements we've already added const spanElementsProcessed = new Set(); const spanTexts = []; var textCountElement = document.createElement("p"); textCountElement.style.fontSize = "15px"; textCountElement.style.color = "gray"; textCountElement.whiteSpace = "pre"; countElement.appendChild(textCountElement); //this is where the "0" is coming from in the screenshot console.log(window.scrollY); // Keep scrolling until we reach the top of the page while (window.scrollY) { await new Promise(setTimeout); // Find all divs var divs = document.querySelectorAll("div"); textCountElement.textContent = "Current scroll: " + window.scrollY + "\r\nCurrent scraped: " + spanTexts.length + "\r\nCurrent unique: " + [...new Set(spanTexts)].length; //these console.logs will eventually be removed but are here for debugging console.log("Current scroll: " + window.scrollY); console.log("Current scraped: " + spanTexts.length); console.log("Current unique: " + [...new Set(spanTexts)].length); // Check for any "show more" divs and expand them for (var div of divs) { if (div.textContent === 'show more') { div.click(); } } // Get all span elements on the page var spans = document.querySelectorAll("span"); // Loop through the elements and replace newline characters with ¶ for (var i = 0; i < spans.length; i++) { var spanE = spans[i]; spanE.textContent = spanE.textContent.replace(/\n/g, "¶"); } // Now find all the span elements const spanElements = document.querySelectorAll('span'); // Add every new span element's textcontent into spanTexts for (const span of spanElements) { if (!spanElementsProcessed.has(span)) { spanElementsProcessed.add(span); spanTexts.push(span.textContent); } } // Wait 100 milliseconds before continuing the loop await sleep(100); }
解决建议
1. 用chrome.scripting.executeScript获取真实scrollY
内容脚本和页面主执行上下文相互隔离,直接访问window.scrollY拿到的是内容脚本上下文的数值,而非页面真实滚动值。通过Chrome脚本API注入代码到页面主上下文,就能获取正确值并返回:
async function getRealScrollY() { // 若在内容脚本中,可通过chrome.tabs.getCurrent获取当前tabId const currentTab = await chrome.tabs.getCurrent(); const result = await chrome.scripting.executeScript({ target: { tabId: currentTab.id }, func: () => window.scrollY, // 在页面主上下文执行并返回scrollY }); return result[0].result; }
调用时替换原代码中的window.scrollY为await getRealScrollY()即可,注意要在async函数内使用。
2. 定位页面内滚动容器,取其scrollTop属性
很多现代网站不会直接使用window滚动,而是将内容放在带overflow: auto/scroll的容器内实现内部滚动。你可以检查页面DOM结构,找到实际承载滚动内容的容器,获取它的scrollTop:
// 根据页面实际DOM结构调整选择器,比如找带特定类名的容器 const scrollContainer = document.querySelector('div[class*="scroll-content"]'); const currentScroll = scrollContainer ? scrollContainer.scrollTop : window.scrollY;
如果不确定容器,也可以遍历所有带有overflow属性的元素,检查哪个的scrollTop不为0。
3. 改造原有事件触发方法,通过自定义事件传值
你原来的方法能打印正确值,说明代码已在页面主上下文执行,可修改为通过自定义事件将值传回内容脚本:
function getScrollY() { return new Promise(resolve => { // 监听自定义事件接收返回值 window.addEventListener('scrollYResult', function receiveResult(e) { resolve(e.detail); window.removeEventListener('scrollYResult', receiveResult); // 移除监听避免重复触发 }); // 注入代码到页面主上下文,获取scrollY后触发事件传递 const actualCode = ` const scrollVal = window.scrollY; window.dispatchEvent(new CustomEvent('scrollYResult', { detail: scrollVal })); `; document.documentElement.setAttribute('onreset', actualCode); document.documentElement.dispatchEvent(new CustomEvent('reset')); document.documentElement.removeAttribute('onreset'); }); }
调用时用const scrollY = await getScrollY();即可拿到正确值。
4. 调整循环逻辑,不依赖scrollY判断是否到顶
如果上述方法都有问题,可换个思路:记录上次滚动位置,当连续几次位置不变时,判定已滚动到顶部:
let lastScrollPos = -1; let noChangeCount = 0; // 连续3次滚动位置不变则停止循环 while (noChangeCount < 3) { const currentScroll = await getRealScrollY(); // 用上述方法获取真实滚动值 if (currentScroll === lastScrollPos) { noChangeCount++; } else { noChangeCount = 0; lastScrollPos = currentScroll; } // 你的原有业务代码... await sleep(100); }
内容的提问来源于stack exchange,提问作者Novet
相关产品推荐
相关产品推荐

