Как выбрать элемент DOM, чтобы прокрутить его в Puppeteer - PullRequest
0 голосов
/ 14 ноября 2018

Я довольно новичок в Puppeteer и жду / асинхронный синтаксис. Я пытаюсь построить бота, чтобы попытаться получить данные из Instagram. В частности, я хотел бы получить подписчиков для данного профиля. Все работает нормально, пока не появится окно подписчиков. Я хотел бы выбрать элемент DOM, чтобы прокрутить его и помещать последователей в массив на каждой итерации. Я искал по форуму и пробовал разные подходы, но он всегда возвращает неопределенное. Я могу получить ElementHandle (scrollBox3) и получить свойства, такие как scrollHeight, но не фактический элемент DOM. Ниже приведен код с описанием различных частей файла.

Любая помощь будет оценена :)

Следующая часть выбирает элементы 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();
})();

Ответы [ 2 ]

0 голосов
/ 17 ноября 2018

Я решил проблему с помощью метода .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;
}
0 голосов
/ 14 ноября 2018

Да, я не знаком с 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);

Вы указываете, что обе эти строки возвращают неопределенный.Это потому, что вы не совсем правильно используете метод $eval.Метод $eval позволяет вам выполнить команду querySelector, чтобы найти определенный элемент DOM (соответствующий объявленному вами селектору CSS), а затем внутренняя функция выполняет инструкции JavaScript в реальном времени для этого элемента DOM..

Итак, давайте посмотрим на вашу первую строку: вы просите сделать querySelector для элемента с классом isgrP, но затем вы запускаете еще один querySelector для этого элемента, который используетCSS-селектор, который начинается с body?Это не имеет смысла.

Я также вижу из этого странного селектора, что он заканчивается на div.isgrP > ul > div, который, по совпадению, имеет div с тем же именем класса, которое вы изначально запрашивали с помощью $eval метод.Так вы всегда намеревались найти элемент в div.isgrP > ul > div?

Вы можете напрямую получить доступ к элементу DOM, используя puppeteer, переработав ваш код следующим образом:

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

Это вернетваш элемент DOM (не экземпляр ElementHandle) для прокручиваемого блока, который вы искали.

Пожалуйста, дайте мне знать, если это помогает и что вызывает вашу следующую проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...