木偶戏-向下滚动,直到无法播放为止

时间:2018-07-26 00:15:03

标签: javascript node.js puppeteer

我处于向下滚动时会创建新内容的情况。 新内容具有特定的类名称。

我如何继续向下滚动直到所有元素加载完毕? 换句话说,我想到达一个阶段,如果我继续向下滚动,则不会加载任何新内容。

我正在使用代码向下滚动,加上

await page.evaluate( () => {
                window.scrollBy(0, window.innerHeight);
            });
await page.waitForSelector('.class_name');

这种方法的问题是,在所有元素加载完之后,代码继续向下滚动,没有创建新元素,最终出现超时错误。

编辑:这是代码

import os
old_file = os.path.join("directory", "a.txt")
new_file = os.path.join("directory", "b.kml")
os.rename(old_file, new_file)

8 个答案:

答案 0 :(得分:19)

试一下:

RUN apt-get update \
 && DEBIAN_FRONTEND=noninteractive \
    apt-get install --no-install-recommends --assume-yes \
      ca-certificates \
      curl \
      python3

来源:https://github.com/chenxiaochun/blog/issues/38

答案 1 :(得分:3)

此处的许多解决方案均假定页面高度恒定。即使页面高度发生变化(例如,当用户向下滚动时加载新内容),此实现也有效。

Sub GetRowItems()

Dim pf As Range
ThisWorkbook.Worksheets("Sheet2").Activate

Set pt = ActiveSheet.PivotTables(1)

'for "Ramesh" Column number wiil be
x = pt.TableRange1.Rows(2).Find("Ramesh").Column - pt.TableRange1.Column + 1
Debug.Print x
    Set pf = pt.TableRange1.Columns(x)

    ThisWorkbook.Worksheets("Sheet2").ListObjects("Table2"). _
        ListColumns("Column" & x).DataBodyRange.Cells(1, 1). _
        Resize(pf.Rows.Count - 1, pf.Columns.Count).Value = _
        pf.Offset(2, 0).Resize(pf.Rows.Count - 1, 1).Value

End Sub

答案 2 :(得分:2)

基于此url

的答案
await page.evaluate(() => {
  window.scrollBy(0, window.innerHeight);
});

答案 3 :(得分:2)

您需要问自己是否正在滚动到一个需要页面延迟加载数据才能到达此DOM的元素。例如,此丝芙兰页面:https://www.sephora.com/search?keyword=clean%20at%20sephora

如果是这样,那么您需要等到promise加载后才能到达页脚,例如,scrollToElement像上面的解决方案一样,不使用promise不会使您到达元素的结尾。

在这种情况下,您需要在Promise内注入page.evaluate

async function autoScroll(page) {
  await page.evaluate(async () => {
    await new Promise((resolve, reject) => {
      var totalHeight = 0;
      var distance = 100;
      var timer = setInterval(() => {
        var scrollHeight = document.body.scrollHeight;
        window.scrollBy(0, distance);
        totalHeight += distance;

        if (totalHeight >= scrollHeight) {
          clearInterval(timer);
          resolve();
        }
      }, 100);
    });
  });
}
await autoScroll(page);

答案 4 :(得分:2)

您可能只是通过page.keyboard对象使用以下代码:

await page.keyboard.press('ArrowDown');
delay(2000) //wait for 2 seconds
await page.keyboard.press('ArrowUp');
function delay(milliseconds) { //function for waiting
        return new Promise(resolve => {
          setTimeout(() => {
            resolve();
          }, milliseconds);
        });
      }

答案 5 :(得分:1)

向下滚动到页面底部可以通过两种方式完成:

  1. 使用scrollIntoView(滚动到页面的底部可以创建更多内容的部分)和选择器(即document.querySelectorAll('.class_name').length来检查是否生成了更多内容)
  2. 使用scrollBy(以递增方式向下滚动页面)和setTimeoutsetInterval(以递增方式检查我们是否位于页面底部)

这是使用scrollIntoView和选择器(假设.class_name是我们滚动到其中的选择器,以获取更多内容)的实现,并且可以在浏览器中运行纯JavaScript:

方法1:使用scrollIntoView和选择器

const delay = 3000;
const wait = (ms) => new Promise(res => setTimeout(res, ms));
const count = async () => document.querySelectorAll('.class_name').length;
const scrollDown = async () => {
  document.querySelector('.class_name:last-child')
    .scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'end' });
}

let preCount = 0;
let postCount = 0;
do {
  preCount = await count();
  await scrollDown();
  await wait(delay);
  postCount = await count();
} while (postCount > preCount);
await wait(delay);

在此方法中,我们正在比较{.class_name滚动之前和滚动preCount之后的postCount选择器的数量,以检查我们是否位于页面底部:

if (postCount > precount) {
  // NOT bottom of page
} else {
  // bottom of page
}

以下是在普通JavaScript中使用setTimeoutsetIntervalscrollBy的两种可能的实现方式,我们可以在浏览器控制台中运行它们。

方法2a:结合使用setTimeout和scrollBy

const distance = 100;
const delay = 100;
while (document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight) {
  document.scrollingElement.scrollBy(0, distance);
  await new Promise(resolve => { setTimeout(resolve, delay); });
}

方法2b:结合使用setInterval和scrollBy

const distance = 100;
const delay = 100;
const timer = setInterval(() => {
  document.scrollingElement.scrollBy(0, distance);
  if (document.scrollingElement.scrollTop + window.innerHeight >= document.scrollingElement.scrollHeight) {
    clearInterval(timer);
  }
}, delay);

在这种方法中,我们将document.scrollingElement.scrollTop + window.innerHeightdocument.scrollingElement.scrollHeight进行比较,以检查我们是否位于页面底部:

if (document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight) {
  // NOT bottom of page
} else {
  // bottom of page
}

如果上面的JavaScript代码中的任何一个将页面一直向下滚动到底部,那么我们就知道它正在工作,我们可以使用Puppeteer来自动执行此操作。

以下是示例Puppeteer Node.js脚本,这些脚本将向下滚动到页面底部,并等待几秒钟,然后关闭浏览器。

操纵者方法1:将scrollIntoView与选择器(.class_name)一起使用

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null,
    args: ['--window-size=800,600']
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');

  const delay = 3000;
  let preCount = 0;
  let postCount = 0;
  do {
    preCount = await getCount(page);
    await scrollDown(page);
    await page.waitFor(delay);
    postCount = await getCount(page);
  } while (postCount > preCount);
  await page.waitFor(delay);

  await browser.close();
})();

async function getCount(page) {
  return await page.$$eval('.class_name', a => a.length);
}

async function scrollDown(page) {
  await page.$eval('.class_name:last-child', e => {
    e.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'end' });
  });
}

木偶方法2a:将setTimeout与scrollBy一起使用

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null,
    args: ['--window-size=800,600']
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');

  await scrollToBottom(page);
  await page.waitFor(3000);

  await browser.close();
})();

async function scrollToBottom(page) {
  const distance = 100; // should be less than or equal to window.innerHeight
  const delay = 100;
  while (await page.evaluate(() => document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight)) {
    await page.evaluate((y) => { document.scrollingElement.scrollBy(0, y); }, distance);
    await page.waitFor(delay);
  }
}

操纵者方法2b:将setInterval与scrollBy一起使用

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null,
    args: ['--window-size=800,600']
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');

  await page.evaluate(scrollToBottom);
  await page.waitFor(3000);

  await browser.close();
})();

async function scrollToBottom() {
  await new Promise(resolve => {
    const distance = 100; // should be less than or equal to window.innerHeight
    const delay = 100;
    const timer = setInterval(() => {
      document.scrollingElement.scrollBy(0, distance);
      if (document.scrollingElement.scrollTop + window.innerHeight >= document.scrollingElement.scrollHeight) {
        clearInterval(timer);
        resolve();
      }
    }, delay);
  });
}

答案 6 :(得分:1)

非常简单的解决方案

let lastHeight = await page.evaluate('document.body.scrollHeight');

    while (true) {
        await page.evaluate('window.scrollTo(0, document.body.scrollHeight)');
        await page.waitForTimeout(2000); // sleep a bit
        let newHeight = await page.evaluate('document.body.scrollHeight');
        if (newHeight === lastHeight) {
            break;
        }
        lastHeight = newHeight;
    }

答案 7 :(得分:1)

更容易:

    await page.evaluate(async () => {
      let scrollPosition = 0
      let documentHeight = document.body.scrollHeight

      while (documentHeight > scrollPosition) {
        window.scrollBy(0, documentHeight)
        await new Promise(resolve => {
          setTimeout(resolve, 1000)
        })
        scrollPosition = documentHeight
        documentHeight = document.body.scrollHeight
      }
    })