Некоторые сайты блокируют Chrome в headless-режиме, и мы рассмотрим, как обойти эту блокировку.
Диагностика это ключ ко всем аспектам компьютеров и программирования. Эта статья начинается с того, как самостоятельно разобраться с этой проблемой блокировки. Если вам это не интересно, то можете сразу перейти к пункту Решение в конце статьи.
При возникновении проблем с headless-режимом, не забывайте делать скриншот через page.screenshot(), чтобы видеть, что происходит. Это, как минимум, позволит узнать, имеете ли вы дело с тем же видимым контентом, который отображается в обычном (управляемом) режиме браузера, а также узнать, не застряли ли вы на месте из-за сломанного скрипта, ничего не понимая.
В данном примере сам сервер даже не отправил соответствующую веб-страницу.
Первоначальный ответ страница Доступ запрещен, и это все, что можно получить при работе Chrome в headless-режиме. Чего вовсе не происходит в управляемом режиме.
В процессе диагностики важно определить, что мы знаем, и чего мы не знаем. Без этого шага невозможно придерживаться плана действий, направленного на то, чего мы не знаем, и при этом включающего в себя только необходимые пункты. Это может показаться элементарным, но если вы не понимаете, зачем это нужно, то прийти к этому не так уж легко. Иногда диагностику понимают как проход по списку пунктов, но это работает только в том случае, когда с ошибкой уже сталкивались ранее.
Что мы знаем? Мы знаем, что браузер сделал единичный запрос, и мы получили ответ, сообщивший, что доступ запрещен. Исходная страница не была отрисована, и браузер не отправил какие-либо другие запросы. Это означает, что сервер обратился куда-то, строго основываясь на том, что мы отправили в том первом запросе, и что наша блокировка не имеет никакого отношения к контенту страницы. Это исключает из диагностики все, что имеет место быть после отрисовки страницы, и сужает размах диагностики исключительно до запроса. Сам по себе запрос набор битов и байтов, отправленных по интернету и принятых сервером.
Сравнение заголовков HTTP-запроса
Поскольку есть (должна быть) небольшая разница между Chrome, запущенном в headless-режиме, и Chrome, запущенном в обычном режиме, логично предположить, что основной сетевой стек один и тот же, и нет никакой разницы, как браузер передает запросы на уровне пакетов. Это говорит о том, что нужно заострить внимание только на содержимом запроса. Можно воспользоваться сервисом, который возвращает нам же наши HTTP-запросы (эхо-сервисом), чтобы найти отличия между запросом, сделанным в headless-режиме, и запросом, сделанным в обычном режиме. Скрипт ниже использует http://scooterlabs.com/echo.json для получения JSON-ответа, который представляет запрос, полученный сервером.
const puppeteer = require('puppeteer');(async() => { const browser = await puppeteer.launch({ }); const page = (await browser.pages())[0]; const response = await page.goto('http://scooterlabs.com/echo.json'); console.log(await response.json()); await browser.close();})()
Запуская его как в headless-режиме (по умолчанию), так и в обычном режиме (с помощью добавления headless:false в параметры запуска), можно сравнить вывод в консоли, чтобы найти отличия, если таковые присутствуют.
time_utc это время, в которое мы сделали запрос. Оно различается, но маловероятно, что это единственный источник блокировки, если только сайт не блокирует все запросы в определенное время суток.
Заголовок Accept-Language отсутствует в случае headless-режима. На самом деле это хороший сигнал того, что кто-то использует нестандартный браузер (или режим браузера), и что браузер мог бы использовать отсутствие этого заголовка для того, чтобы блокировать нас. Это могло бы быть моей первой догадкой, если бы у нас также не было последнего отличающегося заголовка User-Agent.
User-Agent явно выделяется. Это отличие выявляет важную деталь, при этом с помощью этого заголовка headless-режим выдает себя:
Заголовок для управляемого человеком Chrome по большей части такой же, если убрать Headless. User-Agent долгое время был основным, бесхитростным способом блокировки нежелательного трафика. Это хорошее отправная точка для получения ответа на вопрос, получаем ли мы то, что нам нужно.
Блокировка по User-Agent в наше время считается простой и редко используемой мерой противодействия из-за простоты ее обхода. В действительности для сайта было бы полезнее использовать ее не для блокировки, а для распознавания нежелательного трафика, поскольку визуальная доступность лучше отсутствия таковой.
Решение (много текста, не читал)
Решить проблему блокировки так же просто, как и поменять заголовок User-Agent. Его можно переопределить на постраничном уровне методом page.setUserAgent(). Вы можете установить пользовательский агент на агент для Chrome в обычном режиме, который, на момент написания этой статьи, выглядит так: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36.
Это все, что требуется сделать. Вот почему сам подход диагностики важнее, чем это решение. Эти разного рода препятствия все время всплывают при попытках автоматизировать сайты и зачастую в интернете не найти конкретные ответы, поэтому вам придется разбираться с ними своими силами. Удачи, и не стесняйтесь связываться со мной по любым вопросам!