Puppeteer/JQuery:选择器在滚动脚本中不起作用
Posted
技术标签:
【中文标题】Puppeteer/JQuery:选择器在滚动脚本中不起作用【英文标题】:Puppeteer/JQuery: selectors doesn't work in scrolling script 【发布时间】:2019-11-23 18:18:05 【问题描述】:我正在尝试创建一个基本脚本来向下滚动到hacker news 站点的底部。滚动实现取自this so question(kimbaudi 的第二个答案,第一个方法)。
该实现通过在滚动时不断测量元素列表的.length
(由selector
提供)来确定浏览器是否已成功滚动到所述元素列表的底部。
对于我的selector
,我选择了包含有关黑客新闻的每篇文章的 html 元素,tr.athing
,目的是向下滚动到最底部的文章链接。相反,即使 tr.athing
作为 selector
是可打印的(如下面的代码所示),我收到以下错误:
Error: Error: failed to find element matching selector "tr.athing:last-child"
出了什么问题?
const puppeteer = require("puppeteer");
const cheerio = require('cheerio');
const link = 'https://news.ycombinator.com/';
// 2 functions used in scrolling
async function getCount(page)
await console.log(page.$$eval("tr.athing", a => a.length));
return await page.$$eval("tr.athing", a => a.length);
async function scrollDown(page)
await page.$eval("tr.athing:last-child", e =>
e.scrollIntoView( behavior: 'smooth', block: 'end', inline: 'end' );
);
// puppeteer usage as normal
puppeteer.launch( headless: false ).then(async browser =>
const page = await browser.newPage();
const navigationPromise = page.waitForNavigation();
await page.setViewport( width: 1500, height: 800 );
// Loading page
await page.goto(link);
await navigationPromise;
await page.waitFor(1000);
// Using cheerio to inject jquery into page.
const html = await page.content();
const $ = await cheerio.load(html);
// This works
var selection = $('tr.athing').text();
await console.log('\n');
await console.log(selection);
await console.log('\n');
// Error, this does not work for some reason;
// scrolling code starts here.
const delay = 10000;
let preCount = 0;
let postCount = 0;
do
preCount = getCount(page);
scrollDown(page);
page.waitFor(delay);
postCount = getCount(page);
while (postCount > preCount);
page.waitFor(delay);
// await browser.close();
)
【问题讨论】:
【参考方案1】:last-child 选择器不会为您提供最后一个元素,而是其父元素的最后一个元素。
:last-child 选择器匹配其父元素的最后一个子元素。
你可以这样做:
async function scrollDown(page)
await page.$$eval("tr.athing", els =>
els[els.length -1].scrollIntoView( behavior: 'smooth', block: 'end', inline: 'end' );
);
另外请注意,您的代码中缺少许多等待
do
preCount = await getCount(page);
await scrollDown(page);
await page.waitFor(delay);
postCount = await getCount(page);
while (postCount > preCount);
await page.waitFor(delay);
【讨论】:
感谢您至少澄清了我对该方法的理解,last-child
采用last
兄弟,本质上是硬编码!但是,在输入了您的建议后,我现在在我的应用程序中遇到了一个不同的错误(之前的错误假设已被击败):UnhandledPromiseRejectionWarning: Error: Evaluation failed: TypeError: Cannot read property 'scrollIntoView' of undefined
。你也帮我做这个吗?
@Coolio2654 可能在第一个循环中您还没有记录。您可以在调用 scrollIntoView 之前添加一些 if(els.length)
。
好的,我解决了之前代码中的错误,现在它运行了!非常感谢。你能告诉我为什么最初使用:last-child
不起作用吗?在我看来,应该仍然会导致滚动事件发生,即使它不是选择器的最后一个实例(如最初预期的那样),而是其他一些元素。
它不起作用,因为没有带有 athing
类的 TR,如果它的父级是 last-child
。如果您看到 HTML,则父级的最后一个子级(TBODY)是一个没有类的 TR。如果答案对您有帮助,我们将不胜感激:)以上是关于Puppeteer/JQuery:选择器在滚动脚本中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
自定义标签渲染器在 Xamarin iOS 的滚动列表视图中显示错误的文本样式
滚动模式时,bootstrap-datepicker 不滚动