Обход Incapsula c помощью selenium

Обратился заказчик, с проблемой, что его сборщик не может справиться с защитой "incapsula".
В двух словах, вместо кода страницы возвращается javascript код, при выполнении которого, идет запрос на сервера  инкапсулы, проверяются какие-то параметры браузера и в случае если браузер признан валидным, отдается страница и некоторые cookie.

Подробное описание есть на сайте разработчика (www.imperva.com)

Добавление обработчика javascript, так же как и другие решения, предлагаемые гуглом(например поднять свои сервера), показалось слишком сложными\долгими. Selenium же, как оказалось, прекрасно обходит, данную защиту, но так как данных много и собирать в один поток, (или даже переключаясь между вкладками) не хотелось, а запускать несколько браузеров не хватало ресурсов было решено написать proxy сервер.

Так как нагрузка менялась, в зависимости от времени суток и других условий, было решено сделать масштабируемую веб часть через комбинацию Nginx + uwsgi + flask.  Запускать на каждый, воркер, версию Selenium показалось слишком затратным, поэтому вынести Selenium было решено в отдельный сервис, со связью между блоками через Redis. Чтобы максимально упростить реализацию, запросы выполняются синхронно.

Структура проекта


uwsgi.ini – файл с конфигурацией. Существует куча статей по настройке, поэтому я опущу этот этап. На всякий случай в конце статьи оставлю ссылку по настройке (

Микросервис selenium:
Файл gecko/Sel.py

Класс с sellenium модулем. Реализована инициализация, запуск selenium без гуи, и авторизация на сайте (проект изначально писался под конкретный сайт). Также в цикле обновляется главная страница для получения обновленных cookie и в случае появления сообщения в очереди Redis. Cookie выгружаются и хранятся в общем словаре, в redis. Получение cookie от селениума вынесены в callback функции.

Микросервис API:

Файлы в папке src
Во фласке реализован только базовый функционал, слушающий 1 url:

@app.route('/', methods=['GET', 'POST'])

Сервер ожидает запрос, с параметром url с urlом, который необходимо получать, и с телом запроса в случае post запроса.

Например:

http://127.0.0.1:5000/?url=https://www.example.com/vehicledetails/34313441?RowNumber=0& 

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

В файле request.py реализована следующая логика.
Инициализация параметров для библиотеки requests, такие как хедеры.
Инициализация подключения к Redis, а также Post, Get запросы c помощью библиотеки reqests.
При получении сообщения, происходит обновление cookie, полученных от Selenium сервиса.

Надо понимать, что это лишь заготовка. Такие вопросы как https, настройка сервера, дополнительная обработка ошибок, авторизация и т.д я намеренно оставил за пределами статьи. Дополнительная кастомизация и доработка работы с ресурсом, также остается на стороне пользователя.

Весь проект доступен по ссылке

Настройка uwsgi сервера

@karon
21.01.2021 22:21 UTC
Первоисточник

Комментарии

@Pro-dev-pm
21.01.2021 17:50 UTC
0
Так, а где собственно обход из заголовка, увидел только улучшение (усложнение) архитектуры самого парсера. Или там все элементарно оказалось и задача превратилась из обхода защиты в ускорение парсинга?
@karon
21.01.2021 17:56 UTC
0
Сам обход берет на себя селениум. Получив js код от сервера, он его спокойно выполняет, обращается к серверам защиты, доказывает, что он браузер и получает валидные куки. А валидных кук достаточно, чтобы сборщик, для системы, выглядел как обычный пользователь.
Чего собственно и требовалось добиться.
@Desprit
21.01.2021 18:36 UTC
0
Строго говоря, это не обход. Изначальная версия не имела ведь селениума, верно? Вот если бы она у вас заработала, то был бы обход. А так, как правильно выше уже сказали, это усложнение архитектуры.
Вопрос обхода инкапсулы без селениума – штука интересная, для Scrapy раньше был отдельный плагин для этого, но перестал работать с новыми версиями инкапсулы.
@karon
21.01.2021 19:40 UTC
0
Пожалуй, вы правы. Но надеюсь, такой вариант тоже кому то пригодится.
27.01.2021 18:15 UTC
0
Если вдруг натолкнетесь на работающий с текущими версиями инкапсулы обход силами голого питона, буду очень признателен, если отпишетесь тут!
@neovav
22.01.2021 10:21 UTC
0
Зачем использовать selenium когда существует puppeteer (https://github.com/puppeteer/puppeteer/blob/v5.5.0/docs/api.md)?
@karon
22.01.2021 10:22 UTC
0
Я не сталкивался с этой библиотекой. А Selenium мне уже известен.
22.01.2021 10:30 UTC
0
Это библиотека nodejs которая напрямую работает с браузером. Без всяких webdriver и selenium. Так же есть в ней возможность обходить fingerprint.
22.01.2021 10:48 UTC
0
Спасибо поизучаю. Правда в javascript компетенций очень мало.
@Desprit
27.01.2021 18:12 UTC
0
Доводилось вам сравнивать его с phantomjs? Если да, что можете сказать?
28.01.2021 10:57 UTC
0
phantomjs — проект закрыт. Вначале puppeteer хотели сделать на основе phantomjs, но разработчики пришли к выводу, что это будет не очень. Мне приходилось работать и с phantomjs и с puppeteer. Могу сказать, что phantomjs — это фактически chromium, а puppeteer — можно применять к уже реальному браузеру — chrome. Если phantomjs использовать для подключения к webdriver, то все равно головная боль… (https://github.com/detro/ghostdriver) selenium => phantomjs. Puppeteer в этом случае выглядит более привлекательно: puppeteer(NodeJs) => browser chrome. Как говорится почувствуйте разницу. И кстати puppeteer и chromedriver напрямую соединяется к chrome remote debugger port. Более того, сейчас есть возможность (покрайней мере эксперементально) использовать аналог puppeteer для других браузеров (https://github.com/puppeteer/puppeteer/blob/v5.5.0/docs/api.md#puppeteerlaunchoptions): puppeteer.launch([options])
options
29.01.2021 10:22 UTC
0
Спасибо!