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 不滚动

滚动使用 IB 设置的 UIPickerView 时崩溃

sql 获取批处理信息的脚本(优化器在处理批处理时所发生的优化器事件)

为啥 jQuery 选择器在这里不起作用?

Angular2:配对选择器在@Directive中做了啥