Запуск headless Chrome браузера в Docker, puppeteer и browserless

Здесь пойдет речь про эмуляцию, а точнее про инструменты высоклассной, неотличимой эмуляции браузера, способной до мельчайших деталей повторить/воспроизвести действия реального юзверя — клики, движения мыши и прочую канитель в движке chrome. При парсинге в 99.9% эмуляция такого уровня — абсолютно лишнее, а при автоматизации действий юзверей на сайтах в 80% пожалуй тоже лишнее. Так что, если вам нужен парсинг — забудьте об инструментах, о которых пойдет далее речь, и не страдайте херней. Для эффективного парсинга есть куда более продвинутые и менее ресурсоемкие инструменты. Доводилось мне видеть вывод top процессов на сервере, после баранов, парсящих при помощи selenium(ещё один неплохой инструмент эмуляции), всё что ни попадя.

После того как один из моих автоматизированных сервисов, использующий phantomjs, приказал помереть от эмуляционной недосточности (хера-се я диагноз поставил), стало ясно, что пришло время изучить более современные методы эмуляции браузеров. Phantomjs не поддерживается с 2016 года, не имеет поддержки новых версий ECMAscript, и не даёт всех необходимых возможностей для эмуляции.

Одним из таких первоклассных инструментов является библиотека puppeteer на node.js, в которой уже установлен «безголовый» chromium браузер, причем самой новенькой версии и полностью готовый к работе. Достаточно лишь поставить его командой:

npm install puppeteer

И можно пользоваться. Естественно у вас должен быть предварительно установлен Node.js с npm.

Установка нового стабильного LTS пакета Node.js на debian 8/9/10

Для получения текущих версий указываем нонче — setup_15.x или смотрите на сайте текущие.

О том что такое puppetter и headless браузеры есть хорошая статья тут https://habr.com/ru/company/oleg-bunin/blog/421137/ . Однако, опробовав puppeteer в действии, я был одновременно восхищен всеми возможностями эмуляции, но и разочарован — на старт браузера уходит слишком много времени. На слабой машине выходило до 1 минуты на запуск и отработку node js скрипта.  Это неприемлемо, учитывая что запускаться всё должно у меня много-много раз из bash цикла, на 1 итерацию которого ранее с phantomjs уходило 4-10 сек.

Но, как оказалось, есть отличная штука browserless, с готовым докер контейнером, в котором автоматически происходит распараллеливание и очереди, отслеживается падение и рестарт браузера, организован автоматический сбор мусора и много других замечательных плюшек, о которых можно почитать в документации https://docs.browserless.io/docs/docker.html и в статейке разработчиков на хабре https://habr.com/ru/post/413547/

А из node скрипта нам достаточно лишь подключаться к уже запущенному chromium браузеру при помощи puppeteer.connect, что работает гораздо шустрее и эффективнее. Для начала поставим Docker, качнем browserless и запустим в контейнере:

Установка Docker на Debian Linux

docker pull browserless/chrome
docker run -e "TOKEN=you_token" -e "MAX_CONCURRENT_SESSIONS=5" -e "EXIT_ON_HEALTH_FAILURE=true" -e "WORKSPACE_DELETE_EXPIRED=true" -e "WORKSPACE_EXPIRE_DAYS=0" -e "CONNECTION_TIMEOUT=20000" -p 3000:3000 --restart always -d --name browserless browserless/chrome
docker inspect browserless

После запуска контейнера, мы можем подключиться к web отладчику используя токен: http://192.168.56.100:3000/?token=you_token . Все параметры запуска контейнеров и апи подробно описаны в документации browserless.

Теперь, вместо основного пакета puppeteer с headless браузером внутри, нам достаточно поставить «облегченный» пакет puppeteer-core, который предназначен для подключения к существующему(или удалённому браузеру). И также поставим puppeteer-page-proxy, который позволяет работать с прокси в разных вкладках.

npm i puppeteer-core
npm i puppeteer-page-proxy

У меня есть локальные Tor проксики, попробуем подключиться через них и эмулировать Galaxy S5 landscape таким скриптом

const puppeteer = require('puppeteer-core')
const useProxy = require('puppeteer-page-proxy')
const Galaxy = puppeteer.devices['Galaxy S5 landscape'];

(async () => {
	console.time('start');
	const browser = await puppeteer.connect({
		browserWSEndpoint: 'ws://localhost:3000?token=kqg14wb9-vb5d-s56d-a4bu-yuq5snsu884u'
	});
	const context = await browser.createIncognitoBrowserContext();
	const page = await context.newPage()
	await useProxy(page, 'socks5://127.0.0.1:9060');
	await page.emulate(Galaxy);
	await page.evaluateOnNewDocument(() => {
		Object.defineProperty(navigator, "platform", {
			get: function () {
				return "foo";
			}
		})
	});
	await page.goto('https://yandex.ru/internet/')
	await page.screenshot({
		path: 'example.png',
		fullPage: true
	});

	await browser.disconnect()
	console.timeEnd('start');
})()

 

При запуске docker контейнера, я бы советовал не использовать стандартный порт и указать токен доступа. Или не открывать доступ к сервису извне. Кстати, можно не заморачиваться с docker, а вообще использовать чужие ресурсы, которые нерадивые(или щедрые?) админы, оставили нам отрытыми. Для этого достаточно поискать browserless в Shodan.

 

 

Оставить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *