簡體   English   中英

如何在Puppeteer中選擇要在其上滾動的DOM元素

[英]How to select a DOM Element to scroll on it in Puppeteer

我對Puppeteer和await / async語法很陌生。 我正在嘗試構建一個機器人來嘗試從Instagram獲取數據。 具體來說,我想獲得給定個人資料的關注者。 一切正常,直到彈出關注者窗口。 我想選擇DOM元素來滾動它,並在每次迭代時將跟隨者推入數組中。 我在論壇上進行了搜索,並嘗試了不同的方法,但始終返回未定義狀態。 我可以獲取ElementHandle(scrollBox3)並獲取諸如scrollHeight的屬性,但不能獲取實際的DOM Element。 以下代碼包含文件不同部分的說明。

任何幫助,將不勝感激 :)

下一部分選擇DOM元素。 CRED文件是我的用戶名和密碼所在的位置。

const puppeteer = require('puppeteer');
const CREDS = require('./creds');

// Dom Elements
const loginPage = 'https://www.instagram.com/accounts/login/';
const usernameInput = 'input[name="username"]';
const passwordInput = 'input[name="password"]';
const submitButton = 'button[type="submit"]';
const userToSearch = 'nicolekidman';
const searchUser = `https://www.instagram.com/${userToSearch}`;
const followers = `a[href='/${userToSearch}/followers/']`;

此部分記錄在數組的scrollBox中可見的關注者。

// Extract followers from a user profile
const extractFollowers = () => {
  let followers = [];
  let elements = document.getElementsByClassName('FPmhX notranslate _0imsa ');
  for (let element of elements)
      followers.push(element.textContent);
  return followers;
}

這是代碼中斷的滾動功能。 基本上,我想循環並在此scrollBox上滾動,但是我無法獲取DOM元素。

// Scrolling Function
async function scrapeInfiniteScrollItems(
  page,
  extractFollowers,
  followersTargetCount,
  scrollDelay = 1000,
) {
  let items = [];
  // Next 2 lines return undefined
  // .isgrP and .PZuss are classes inside this div, PZuss is the one we want to scroll on
  let scrollBox1 = await page.$eval('.isgrP', el => el.querySelector('body > div:nth-child(15) > div > div > div.isgrP > ul > div'));
  let scrollBox2 = await page.$eval('body > div:nth-child(15) > div > div > div.isgrP > ul > div', el => el);

  // Next line returns an ElementHandle
  let scrollBox3 = await page.$('.PZuss');

  console.log(scrollBox3);
  let scrollBoxHeight = await page.$eval('.PZuss', el => el.scrollHeight);
  console.log(scrollBoxHeight);
  try {
    while (items.length < followersTargetCount) {
      items = await page.evaluate(extractFollowers);
      console.log(extractFollowers());
      // await page.evaluate('scrollBox.scrollTo(0, scrollable_popup.scrollHeight)');
      // await page.waitForFunction(`scrollBox.scrollHeight > ${previousHeight}`);
      // await page.waitFor(scrollDelay);
    }
  } catch(e) { }
  return items;
}

這是實際的異步功能,我將在其中進行所有工作以訪問Instagram並調用滾動功能以記錄給定配置文件的關注者。

(async() => {
  // headless false for visual debugging in browser
  const browser = await puppeteer.launch({
    headless: false
  });
  const page = await browser.newPage();
  await page.goto(loginPage, {waitUntil: 'networkidle2'});
  // Type username
  await page.click(usernameInput);
  await page.keyboard.type(CREDS.username);

  // Type password and submit
  await page.click(passwordInput);
  await page.keyboard.type(CREDS.password);
  await page.click(submitButton);
  await page.waitFor(2000);

  // Search User with URL
  await page.goto(searchUser);
  await page.click(followers);
  await page.waitFor(2000);

  const findFollowers = await scrapeInfiniteScrollItems(page, extractFollowers, 100);
  console.log(findFollowers);
  await page.screenshot({ path: '../screenshots/insta.png' });

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

我使用.hover()方法解決了這個問題。 我在每次迭代中選擇div中的最后一個元素,這會觸發滾動到視圖。 這樣,我就能獲得定義為參數的關注者數量。 這樣很方便,功能也更短。 雖然仍然無法選擇DOM元素本身。

async function scrapeInfiniteScrollItems(
  page,
  extractFollowers,
  followersTargetCount
) {
  let items = [];
  // Next line returns undefined
  let x;
  try {
    while (items.length < followersTargetCount) {
      items = await page.evaluate(extractFollowers);
      childToSelect = items.length;
      await page.hover(`div.isgrP > ul > div > li:nth-child(${childToSelect})`);
    }
  } catch(e) { }
  items.length = followersTargetCount;
  return items;
}

是的,我對Instagram不熟悉,但是我將逐步與您合作。 您的代碼一目了然(在我沒有與Instagram簽約的情況下,我無法測試此代碼很不幸),但其中有些地方很突出。

scrapeInfiniteScrollItems函數:

let scrollBox1 = await page.$eval('.isgrP', el => el.querySelector('body > div:nth-child(15) > div > div > div.isgrP > ul > div'));
let scrollBox2 = await page.$eval('body > div:nth-child(15) > div > div > div.isgrP > ul > div', el => el);

您指出,這兩行都返回undefined。 這是因為您沒有正確使用$eval方法。 $eval方法允許您執行的操作是執行querySelector指令來定位特定的DOM元素(該元素與您聲明的CSS選擇器匹配),然后內部函數在該DOM元素上實時執行JavaScript指令。

因此,讓我們看一下第一行:您要它對isgrP類的元素執行querySelector ,然后在該元素上運行進一步的querySelector ,該元素使用以body開頭的CSS選擇器? 這沒有道理。

我還從那個奇怪的選擇器中看到,它以div.isgrP > ul > div結尾,巧合的是,該div的類名與您最初使用$eval方法查詢的那個類名相同。 那么,您是否一直打算在div.isgrP > ul > div上找到該元素?

您可以通過按如下所示重新編寫代碼來直接使用puppeteer訪問DOM元素:

const scrollBox = await page.$eval('div.isgrP > ul > div.PZuss', (uiElement) => {
  return uiElement;
});

這將為您一直在搜索的可滾動框返回DOM元素(不是ElementHandle實例)。

請告訴我是否有幫助,是什么導致您的下一個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM