剧作家自动滚动到无限滚动页面的底部

问题描述 投票:0回答:8

我正在尝试使用 Python 和 Playwright 自动抓取具有“无限滚动”功能的网站。

问题是 Playwright 到目前为止还不包含滚动功能,更不用说无限自动滚动功能了。

根据我在网上发现的内容和我的个人测试,我可以使用

page.evaluate()
函数和一些 Javascript 代码自动执行无限或有限滚动。

例如,这有效:

for i in range(20):
    page.evaluate('var div = document.getElementsByClassName("comment-container")[0];div.scrollTop = div.scrollHeight')
    page.wait_for_timeout(500)

这种方法的问题在于,它要么通过指定滚动数量,要么通过告诉它通过

while True
循环永远继续下去来工作。

我需要找到一种方法来告诉它继续滚动,直到加载最终内容。

这是我目前正在尝试的Javascript

page.evaluate()
:

var intervalID = setInterval(function() {
    var scrollingElement = (document.scrollingElement || document.body);
    scrollingElement.scrollTop = scrollingElement.scrollHeight;
    console.log('fail')
}, 1000);
var anotherID = setInterval(function() {
    if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
        clearInterval(intervalID);
    }}, 1000)

这在我的 Firefox 浏览器或 Playwright Firefox 浏览器中都不起作用。它立即返回并且不会间隔执行代码。

如果有人能告诉我如何使用 Playwright 创建一个自动滚动功能,该功能将在到达动态加载网页的底部时检测并停止。

javascript python python-3.x playwright
8个回答
18
投票

所以我找到了一个可行的解决方案。

我所做的是将 Javascript 与 python Playwright 代码结合起来。

我用 200 毫秒的计时器启动 setInterval,用

page.evaluate()
在页面上向下滚动,然后用 python 循环跟踪它,每秒检查页面的总高度(包括滚动)是否已更改。如果发生变化,则继续滚动,如果没有变化,则滚动结束。
这就是它的样子:

page.evaluate(
    """
    var intervalID = setInterval(function () {
        var scrollingElement = (document.scrollingElement || document.body);
        scrollingElement.scrollTop = scrollingElement.scrollHeight;
    }, 200);

    """
)
prev_height = None
while True:
    curr_height = page.evaluate('(window.innerHeight + window.scrollY)')
    if not prev_height:
        prev_height = curr_height
        time.sleep(1)
    elif prev_height == curr_height:
        page.evaluate('clearInterval(intervalID)')
        break
    else:
        prev_height = curr_height
        time.sleep(1)

编辑

使用新的 mouse.wheel(x, y) 功能查看下面的答案,了解使用 playwright 滚动的最新方式。将我的答案与他的答案结合起来,以减少使用 JS 的需要。


16
投票

新的Playwright版本具有滚动功能。它被称为

mouse.wheel(x, y)
。在下面的代码中,我们将尝试滚动浏览具有“无限滚动”的 youtube.com:

from playwright.sync_api import Playwright, sync_playwright
import time


def run(playwright: Playwright) -> None:
    browser = playwright.chromium.launch(headless=False)
    context = browser.new_context()

    # Open new page
    page = context.new_page()

    page.goto('https://www.youtube.com/')

    # page.mouse.wheel(horizontally, vertically(positive is 
    # scrolling down, negative is scrolling up)
    for i in range(5): #make the range as long as needed
        page.mouse.wheel(0, 15000)
        time.sleep(2)
        
    
    time.sleep(15)
    # ---------------------
    context.close()
    browser.close()


with sync_playwright() as playwright:
    run(playwright)

9
投票

其他解决方案对我来说有点冗长和“杀伤力”,而这对我有用。

这是一个两眼线,让我有些偏头痛才过来:)

注意:您必须放入您自己的选择器。这只是一个例子...

    while page.locator("span",has_text="End of results").is_visible() is False:
        page.mouse.wheel(0,100)
        #page.keyboard.down(PageDown) also works

从字面上看,只需继续滚动,直到出现某种唯一的选择器。在这种情况下,当您滚动到底部时,会弹出带有字符串“结果结束”(针对我的用例的上下文)的跨度标记。

我相信你可以翻译这个逻辑以供你自己使用..


7
投票

剧作家有

page.keyboard.down('End')
命令,它会滚动到页面末尾。


0
投票

所以我遇到了类似的问题,但它是一个具有滚动的特定元素,而不是页面本身,我发现如果您单击有问题的元素并将焦点应用于它,page.mouse.wheel将滚动该特定元素。 (在我的例子中,我的元素是 tbody)

async scrollIntoView (locator : Locator) {
        let i = 0;
        while(await locator.isHidden()) {
            await this.page.locator('your locator goes here').click();
            await this.page.mouse.wheel(0, 300);
            i++;
            if (await locator.isVisible()) { return; }
            else if (i >= 5) { return; }
        }
    }

您可以使用

i
删除增量防护,我只是将其放在那里以避免任何无限循环。


0
投票

我创建了这个自动滚动功能来滚动到 Shopee (shopee.sg) 的页面底部。

async function autoScroll(page) {
  const maxScrolls = 100;
  const scrollDelay = 4000;
  let previousHeight = 0;
  let scrollAttempts = 0;

  while (scrollAttempts < maxScrolls) {
    await page.keyboard.down('End');
    await page.waitForTimeout(scrollDelay);
    const currentHeight = await page.evaluate(() => document.body.scrollHeight);
    if (currentHeight === previousHeight) {
      break;
    }
    previousHeight = currentHeight;
    scrollAttempts++;
  }
}

-1
投票

此代码对我有用:

prev_page_height = page.evaluate("$(document).height()") 
print(f'Initial page height {prev_page_height}')

# scroll down
while True:
    page.evaluate("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(2)   # giving some time to load the page
            
    cur_page_height = page.evaluate("$(document).height()")
    print(f'Current page height {cur_page_height}')
            
    if cur_page_height > prev_page_height:
        prev_page_height = cur_page_height
    elif cur_page_height == prev_page_height:
        break

-3
投票

这个话题很老,但对我来说很新。我一直在使用剧作家滚轮,但对我来说,它需要鼠标来控制/聚焦。

因此,如果我碰巧正在打字(通常是这样)并且它滚动,我美丽的文字就会消失,再也不会被看到。

我将继续尝试上面发布的 js 解决方案,看看这是否能让我解决鼠标/焦点问题。

© www.soinside.com 2019 - 2024. All rights reserved.