Используем Proxy в Selenium

Привет. Вряд ли эта статья откроет Америку для прожженных разработчиков «парсеров» или тестировщиков, но должна помочь тем, кто работает с Selenium время от времени.

Если вы иногда занимаетесь автоматизированным сбором информации с веб-ресурсов (т.н. веб-скрапинг или парсинг), то однозначно сталкивались с проблемой, что некоторые ресурсы недоступны из некоторых регионов, по разным причинам. Сейчас этой проблемы стало даже чуточку больше. И для преодоления этого препятствия нам помогают прокси-серверы (промежуточные серверы). Однако, если в части библиотек для работы с запросами использование прокси является очевидным решением, идущим из коробки, то такой инструмент как Selenium очевидного встроенного решения или не имеет, или я не смог его обнаружить.

Далее приведу некоторые примеры с использованием Python, но привязки к языку не будет. Решение универсальное, связанное с написанием расширения для веб-драйвера.

В Python для работы с HTTP-запросами любого уровня сложности вполне достаточно встроенной библиотеки Requests. А для использования прокси с библиотекой, достаточно всего лишь передать данные о сервере в качестве аргумента. Например, так:

import requests

proxies = {
    'http': 'http://login:password@ip:port',
    'https': 'http://login:password@ip:port'
}

url = "https://badsite.com/"

response = requests.get(url, proxies=proxies)

Но для работы со многими современными веб-ресурсами этой библиотеки недостаточно. Например, она не поддерживает JS и нужные данные просто не всегда подгружаются, а ответ приходит неполный. В таких случаях и нужна связка с Selenium, который автоматизирует браузер, может обработать любую веб-страницу, обойти защиту от роботов и так далее.

Разумеется, если вы попробуете открыть с помощью Selenium ресурс, который недоступен из вашего региона, ничего не выйдет. Можно придумать много вариантов решения, но как по мне, самый удобный способ настройки прокси в Selenium- это написать прокси-расширение. В моем случае это будет расширение для веб-драйвера Chrome.

Допустим, у вас есть проект с логикой работы Selenium для получения HTML в отдельном файле main.py. Теперь в директории проекта создадим папку proxi_extension и добавим в неё два файла:

  1. manifest.json с таким наполнением:
{
    "version": "1.0.0",
    "manifest_version": 2,
    "name": "Chrome Proxy",
    "permissions": [
        "proxy",
        "tabs",
        "unlimitedStorage",
        "storage",
        "<all_urls>",
        "webRequest",
        "webRequestBlocking"
    ],
    "background": {
        "scripts": ["background.js"]
    },
    "minimum_chrome_version": "22.0.0"
}

2. background.js с таким наполнением:

var config = {
    mode: "fixed_servers",
    rules: {
        singleProxy: {
            scheme: "http",
            host: "ip_address",
            port: parseInt("8000")
        },
        bypassList: ["localhost"]
    }
};

chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});

function callbackFn(details) {
    return {
        authCredentials: {
            username: "login",
            password: "password"
        }
    };
}

chrome.webRequest.onAuthRequired.addListener(
    callbackFn,
    {urls: ["<all_urls>"]},
    ['blocking']
);

В background.js необходимо лишь заменить значения host, port, username и password на нужные.

Далее возвращаемся к файлу main.py и подключаем к веб-драйверу написанное расширение, указав путь к нему в соответствующем аргументе:

from loggers import logger #  уже настроенный логгер
from selenium import webdriver
from selenium.webdriver.chrome.options import Options


def get_html(url: str) -> str:
    """
    Возвращает HTML.
    """
    chrome_options = Options()
    chrome_options.add_argument(f"--load-extension={'/home/username/my_project/proxi_extension'}") #  подключаем расширение с прокси
    driver = webdriver.Chrome(options=chrome_options)
    driver.set_page_load_timeout(5)

    try:
        driver.get(url)
    except Exception as e:
        logger.error(e)

    finally:
        html = driver.page_source
        driver.quit()

        return html

Вот и весь способ. Теперь автоматизированный Chrome будет открывать всё, что не заблокировано в регионе, в котором установлен прокси-сервер.

Надеюсь, что я не побаловал вас диким баяном и кому-то, да помог. Хорошего дня.