Anton
ясно, спасибо
Andrey
вы про puppeteer-cluster ?
Anton
да
Bogdan
в докер контейнере кстати headfull нормально запускается?
Roman
в докер контейнере кстати headfull нормально запускается?
У меня не запускались, пока я не прокинул установку пакетов графической эмуляции
Roman
есть пример?
Чуть позже
Bogdan
Чуть позже
спасибо
Roman
спасибо
Уверен, можно оптимизировать все пакеты. Образ тяжелый получается. Подключаться к контейнеру можно через VNC viewer
Bogdan
спасибо) попробую собрать попозже
Andrey
может на нем lazyLoad был, и пока он во viewport не попадал - не прогружался
Bogdan
а ктонибудь сталкивался с тем что evaluateHandle не правильно как-то грузит аргументы если это elementHandle.evaluateHandle вот пример const menuElement = await page.$('.menu') const pendingButton = await getButtonByText(menuElement, 'Pending'); const getButtonByText = async (pageOrElem, text) => { const jsHandle = await pageOrElem.evaluateHandle((text) => { const buttons = [ ...Array.from(document.querySelectorAll('button')), ...Array.from(document.querySelectorAll('a')), ]; return buttons.find( (b) => b.innerText.trim().toLowerCase() === text.toLowerCase() ); }, text); const asElement = jsHandle.asElement(); return asElement; }; в output получаю, что text.toLowerCase is not a function…
Bogdan
при этом если через page гружу как-то так то работает const getButtonByText = async (pageOrElem, text, rootSelector = null) => { const jsHandle = await pageOrElem.evaluateHandle( (text, rootSelector) => { const selectRootElement = rootSelector ? document.querySelector(rootSelector) : document; const buttons = [ ...Array.from(selectRootElement.querySelectorAll('button')), ...Array.from(selectRootElement.querySelectorAll('a')), ]; return buttons.find( (b) => b.innerText.trim().toLowerCase() === text.toLowerCase() ); }, text, rootSelector );
Bogdan
ага понятно…он тогда передает element как первый аргумент
Bogdan
херово что тогда он не отдает весь документ как первый аргумент если грузить через page.evaluateHandle
Bogdan
получается костыль какой-то нужно городить чтобы он работал как pageOrElem.evaluateHandle
Bogdan
const getButtonByText = async (pageOrElem, text) => { const jsRootHandle = await pageOrElem.evaluateHandle((mbRootHandle) => { if (mbRootHandle) { return mbRootHandle; } else { return document; } }); const rootElement = jsRootHandle.asElement(); const jsHandle = await selectRootHandle.evaluateHandle((rootHandle, text) => { const buttons = [ ...Array.from(rootHandle.querySelectorAll('button')), ...Array.from(rootHandle.querySelectorAll('a')), ]; return buttons.find( (b) => b.innerText.trim().toLowerCase() === text.toLowerCase() ); }, text); const asElement = jsHandle.asElement(); return asElement; }; вот так сделал, хотя мне кажется так по дефолту должно быть было
Bogdan
в доке при том не было информации что в случае если это elementHandle.evaluateHandle первый аргумент будет элемент.
🦋noteee
+
Появилась новая ошибка, но через curl сайт пингуется. Прокси не использую Запускаю с такими аргументами: args: ['--no-sandbox', '--ignore-certificate-errors', '--disable-dev-shm-usage'] С моей машины все нормально, проблема только на сервере в безголовом режиме. Использую user-agent
🦋noteee
Прокси не используются. Ошибка только в безголовом режиме. По http тоже ошибка. В интернете решение таких проблем идет заменой https на http
Alhimik
Появилась новая ошибка, но через curl сайт пингуется. Прокси не использую Запускаю с такими аргументами: args: ['--no-sandbox', '--ignore-certificate-errors', '--disable-dev-shm-usage'] С моей машины все нормально, проблема только на сервере в безголовом режиме. Использую user-agent
NET::ERR_FAILED никакой конкретики не даёт. Предположу, что, как и в прошлый раз, сайт видит автоматизацию и просто обрывает соединение. Ищи отличия в запросах в обоих режимах и пытайся в хэдлесе повторить заголовки из хэдфул режима.
Alhimik
Понял. Запросы снифать отдельным софтом по типу fiddler/http analyzer ?
Как тебе удобнее, можно так https://t.me/puppeteer_ru/6438.
🦋noteee
Как тебе удобнее, можно так https://t.me/puppeteer_ru/6438.
Вот так даже удобнее. Мне смотреть исключительно на отличия в заголовках или ещё на что то?
🦋noteee
Ну да, скорей всего в них дело будет.
Понял. Спасибо за информацию, о результатах отпишусь через пару дней
In77
есть несколько xpath для одной переменной, прогоняю по ним в цикле, как сделать, чтобы первый найденный елемент waitForXPath возвращался, остальные не нужно
In77
Это не то
In77
У меня несколько абсолютно разных xpath
In77
А тут первый элемент из одного xpath
Pavel
У меня несколько абсолютно разных xpath
попробуй waitForXPath(`${XPath1} | ${XPath2}`)
Bogdan
У меня несколько абсолютно разных xpath
const maybeGetXpathElement = async (page) => { const someXpath = await page.$x("someXpath"); const someXpath2 = await page.$x("someXpath2"); if (someXpath || someXpath2) { return [someXpath, someXpath2].filter(x => x)[0] } else { await delay(1500) return await maybeGetXpathElement(page) } } можешь так сделать например.
Pavel
так он ждет чтобы оба someXpath загрузились, хотя автору виднее
Bogdan
вроде написал чтобы первый найденый, но в любом случае можно рекурсию подкрутить и будет оба загружать
Pavel
посмотрим, что In77 скажет. Вообще непонятно, вдруг у него там динамически подгружается html
Bogdan
``` const maybeGetXpathElements = async (page) => { const xPaths = [await page.$x('someXpath'), await page.$x('someXpath2')]; const filteredXPaths = xPaths.filter((x) => x); const xPathsLength = xPaths.length; const filteredXpathsLength = filteredXPaths.length; if (xPathsLength == filteredXpathsLength) { return filteredXPaths; } else { await delay(1500); return await maybeGetXpathElements(page); } }; ```
Bogdan
если все то так можно
In77
Спасибо попробую
Pavel
In77 получилось?
In77
еще не пробовал
Bogdan
для nodejs есть какой-нибудь worker pool нормальный?
In77
pm2 вроде
1
Подскажите, почему скриншот элемента делает некорректно, другую область: const el = await page.$('#logo'); await el.screenshot({path: 'pic.png'}); приходится извращаться с координатами const rect = await page.evaluate((header) => { const {top, left, bottom, right} = header.getBoundingClientRect(); return {top, left}; }, el); await page.screenshot({ path: 'pic.png', clip: {x: rect.left, y: rect.top, width: 200, height: 70}});
1
Куда кэшируются картинки? Возможно при открытии сайта вытянуть картинку из кэша?
Andrew
Всем привет, есть такой вот код, но присутствуют глюк if (boundingBox.height == "0"){ await link1.click(); await GLOBAL.page.waitForTimeout(3000); await link3.click(); } else { await link3.click(); } в блоке > 10 "кнопок" 1. начиная с 6 кнопки судя по визуальной работе сценария, всегда срабатывает НЕ await link3.click(); А await link1.click(); повторно, потому как блок открывается таймаут 3 секуды блок закрывается 2. так же есть такой глюк, берут из сценария выше кейс где надо нажать на кнопку 5 в списке. Так из 10 запусков, не все успешны, в некоторые случаи почему то открывается вообще другой блок. может сталкивался кто с таким ?
Bogdan
Или вы код не весь выложили?
Andrew
да, link1 это блок, link2 это кнопка из блока
Andrew
Andrew
Bogdan
в if напиши if(link2) вместо boundingBox
Bogdan
и матчить кнопки лучше через текст а не по xpath или css
Bogdan
const getButtonByText = async (pageOrElem, text) => { const jsRootHandle = await pageOrElem.evaluateHandle((mbRootHandle) => { if (mbRootHandle) { return mbRootHandle; } else { return document; } }); const rootElement = jsRootHandle.asElement(); const jsHandle = await rootElement.evaluateHandle((rootHandle, text) => { const buttons = [ ...Array.from(rootHandle.querySelectorAll('button')), ...Array.from(rootHandle.querySelectorAll('span')), ...Array.from(rootHandle.querySelectorAll('div')), ...Array.from(rootHandle.querySelectorAll('a')), ]; return buttons.find( (b) => b.innerText.trim().toLowerCase() === text.toLowerCase() ); }, text); const asElement = jsHandle.asElement(); return asElement; }; я через такую функцию получаю нужную кнопку.
Andrew
спасибо
Дмитрий 🌝
привет, кто-то пытался обойти фингерпринтинг через puppeteer?
Pavel
Пару приемов обсуждали
1
❓ После динамического изменения контента на странице неправильно определяет координаты элемента по вертикали, как решить проблему? await el.boundingBox()
Bogdan
❓ После динамического изменения контента на странице неправильно определяет координаты элемента по вертикали, как решить проблему? await el.boundingBox()
вероятно тебе нужно в начале установить viewPort относительно которой ты будешь определять координаты элемента await page.setViewport(viewPort);
Bogdan
так как деталей ты дал очень мало другого ничего в голову не приходит почему они “неправильно” могут определятся
Bogdan
не вивпорт ссори
Bogdan
el.scrollIntoView();
Bogdan
и после const coordinates = el.getBoundingClientRect();
1
вероятно тебе нужно в начале установить viewPort относительно которой ты будешь определять координаты элемента await page.setViewport(viewPort);
На странице в верхней части появляется сообщение и после этого неправильно определяет положение по вертикали. Изначально устанавливаю await page.setViewport({ width: 0, height: 0}) Сейчас попробую с el.scrollIntoView();
Bogdan
Bogdan
скажи потом что поможет)
1
скажи потом что поможет)
По вертикали стало отрабатывать правильно без scrollIntoView(), но по горизонтали началось смещение. На сайте пытаюсь сделать скриншот капчи. Когда капчу вводишь неверно, то появляется сообщение об ошибке и после этого координаты сбиваются. Может есть другой способ сохранить картинку? Сохранить картинку по URL не получается, сохраняется другая.
Bogdan
видимо ты скриншот делаешь в fullpage моде
Bogdan
либо вставь координаты из viewPort в скриншот
Bogdan
ну он меняеет разрешение окна когда делает скриншот в фул пейдж моде
Bogdan
на какое-то время
Bogdan
попробуй поставь в скриншот координаты такие же как в viewPort
1
попробуй поставь в скриншот координаты такие же как в viewPort
Помогло добавление в скриншот это fullPage: false, captureBeyondViewport: false
1
супер
Спасибо, уже замучился искать решение.
Pavel
пробовал кто нибудь сразу 104 вкладки открывать?:D