Puppeteer / Node.js, чтобы нажать кнопку, пока она существует - и когда она больше не существует, начать действие - PullRequest
0 голосов
/ 08 ноября 2018

Существует веб-страница, которая содержит много строк данных, которые постоянно обновляются.

Существует фиксированное количество строк, поэтому старые строки отключаются и нигде не хранятся.

Эта страница разбита кнопкой «Загрузить еще», которая будет отображаться до тех пор, пока все сохраненные строки не отобразятся на странице.

Мне нужно написать скрипт в Puppeteer / Node.js, который нажимает эту кнопку, пока она больше не существует на странице ...

ТО

... читать весь текст на странице. (Я закончил эту часть сценария.)

Я новичок в Puppeteer и не знаю, как это настроить. Любая помощь будет принята с благодарностью.

EDIT:

Я добавил этот блок:

  const cssSelector = await page.evaluate(() => document.cssSelector('.u-field-button Button-button-18U-i'));

  // Click the "load more" button repeatedly until it no longer appears
  const isElementVisible = async (page, cssSelector) => {
    await page.waitForSelector(cssSelector, { visible: true, timeout: 2000 })
    .catch(() => {
      return false;
    });
    return true;
  };

  let loadMoreVisible = await isElementVisible(page, cssSelector);
  while (loadMoreVisible) {
    await page.click(cssSelector);
    loadMoreVisible = await isElementVisible(page, cssSelector);
  }

Но я получаю эту ошибку:

Error: Evaluation failed: TypeError: document.cssSelector is not a function
    at __puppeteer_evaluation_script__:1:17
    at ExecutionContext.evaluateHandle (/Users/reallymemorable/node_modules/puppeteer/lib/ExecutionContext.js:124:13)
    at process.internalTickCallback (internal/process/next_tick.js:77:7)
  -- ASYNC --
    at ExecutionContext.<anonymous> (/Users/reallymemorable/node_modules/puppeteer/lib/helper.js:144:27)
    at ExecutionContext.evaluate (/Users/reallymemorable/node_modules/puppeteer/lib/ExecutionContext.js:58:31)
    at ExecutionContext.<anonymous> (/Users/reallymemorable/node_modules/puppeteer/lib/helper.js:145:23)
    at Frame.evaluate (/Users/reallymemorable/node_modules/puppeteer/lib/FrameManager.js:439:20)
    at process.internalTickCallback (internal/process/next_tick.js:77:7)
  -- ASYNC --
    at Frame.<anonymous> (/Users/reallymemorable/node_modules/puppeteer/lib/helper.js:144:27)
    at Page.evaluate (/Users/reallymemorable/node_modules/puppeteer/lib/Page.js:736:43)
    at Page.<anonymous> (/Users/reallymemorable/node_modules/puppeteer/lib/helper.js:145:23)
    at /Users/reallymemorable/Documents/scripts.scrapers/squarespace.ip.scraper/squarespace5.js:32:34
    at process.internalTickCallback (internal/process/next_tick.js:77:7)
(node:8009) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:8009) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

1 Ответ

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

ОК, это то, что я бы порекомендовал вам сделать, чтобы добиться этого. Я собираюсь игнорировать, что всегда есть фиксированное количество строк для ваших данных (возможно, это изменится в будущем) и вместо этого настроит вас, если есть неизвестное количество строк данных для отображения, непрерывно нажимая на кнопка «загрузить еще».

Итак, первое, что вы хотите сделать, это настроить метод, который решает, отображается ли кнопка «загрузить больше» в пользовательском интерфейсе. Вы хотите сделать это, написав метод следующим образом:

const isElementVisible = async (page, cssSelector) => {
  let visible = true;
  await page
    .waitForSelector(cssSelector, { visible: true, timeout: 2000 })
    .catch(() => {
      visible = false;
    });
  return visible;
};

Как только вы передадите требуемый селектор CSS (в данном случае селектор для вашей кнопки «загрузить больше»), этот метод вернет true, если кнопка отображается, и false, если это не так.

Вы хотите, чтобы время ожидания было 2000, потому что вы хотите постоянно проверять, отображается ли эта кнопка. Если он не отображается, в противном случае время ожидания по умолчанию будет равно 30000, и это слишком долго, чтобы ваш код зависал в ожидании. Поэтому я считаю, что 2000 - хороший компромисс. Цель блока catch - перехватить ошибку, которая будет выдана, когда элемент больше не отображается - вы хотите игнорировать тот факт, что ошибка выдается, поскольку вы пытаетесь добраться до точки, где кнопка не отображается длиннее отображается. Вы знаете, что он не будет отображаться после X количества кликов. Все в порядке. Так что вам нужно catch ошибка, чтобы чисто обойти, когда это произойдет.

Следующий шаг - сделать что-то подобное, чтобы ваш код продолжал нажимать на кнопку «загрузить больше» до тех пор, пока он больше не будет активирован (т.е. отображается):

let loadMoreVisible = await isElementVisible(page, selectorForLoadMoreButton);
while (loadMoreVisible) {
  await page
    .click(selectorForLoadMoreButton)
    .catch(() => {});
  loadMoreVisible = await isElementVisible(page, selectorForLoadMoreButton);
}

Это будет постоянно проверять, видна ли кнопка в вашем пользовательском интерфейсе, щелкните ее, если она отображается, и затем повторяйте процесс, пока кнопка больше не будет отображаться. Это гарантирует, что все строки данных будут отображаться в пользовательском интерфейсе, прежде чем вы продолжите работу с оставшейся частью тестового сценария.

Вам также понадобится блок catch для действия click, как показано выше. Причина этого в том, что режим headless движется очень быстро. Иногда слишком быстро, чтобы пользовательский интерфейс не отставал от него. Обычно на самом последнем отображении кнопки «Показать больше» метод isElementVisible выполняется до обновления пользовательского интерфейса, чтобы исключить присутствие кнопки, поэтому он возвращает true, когда фактически селектор теперь больше не отображается. Тогда это вызывает исключение из запроса click, так как элемент больше не существует. Для меня самый чистый способ обойти это - добавить этот пустой блок catch в инструкцию click, чтобы в этом случае действие click по-прежнему полностью обходилось без провала всего теста.

Обновление 1:

Вы просто неправильно используете селектор css. Ваш селектор должен быть:

const cssSelector = '.u-field-button Button-button-18U-i'; // This is your CSS selector for the element

Для этого вам не нужно использовать evaluate метод.

Обновление 2:

ОК. Я добавил некоторые улучшения, я тщательно протестировал этот код на нескольких разных сайтах и ​​обнаружил, что моя собственная логика была не совсем правильной для подхода «один размер подходит всем» для нажатия на кнопки такого типа. так что, вероятно, именно поэтому вы получаете эти исключения. Я обновил свой оригинальный ответ со всеми внесенными изменениями.

Просто небольшое замечание: я обновил isElementVisible метод и цикл while.

Надеюсь, это поможет!

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