Проксирование в Scrapy

Нашей задачей является расширение способности мимикририровать у Scrapy. Техника проксирования, думается, самый первичный метод, который стоит опробовать. Пользу мимикрии можно извлечь, например, при работе с веб-сайтами, имеющими различное содержимое для разных регионов планеты.

Мы обозрим встроенный функционал и улучшения сторонних разработчиков.

Базовые возможности

Настройки HTTP-прокси задаются на двух уровнях – в исходном коде проекта и в переменных окружения. Причем первый вариант более базовый, поскольку мы указываем только URI в метазначениях каждого запроса, а дальнейшую работу на себя берет Twisted. Во втором же случае, прежде чем запрос уйдет в Twisted, он должен попасть в дополнительно включенный промежуточный слой HttpProxyMiddleware, для которого мы указываем URI в переменной окружения (http_proxy, https_proxy, no_proxy).

Рассмотрим пример для первого случая:

class SomeSpider(Spider):
    name = 'somespider'
    allowed_domains = [ 'www.example.com' ]

    def start_requests(self):
        return Request('http://www.example.com/page.html', meta={'proxy':'http://198.51.100.14:8080'}, callback=self.parse_page)

    def parse_page(self, response):
        pass

Как видим мы добавили аргумент meta={'proxy':'http://198.51.100.14:8080'} во время создания объекта Request, который и указывает, что этот запрос уйдет через конкретный прокси-сервер.

В случае, если нам нужно пройти авторизацию на том самом сервере, стоит изменить метод start_requests следующим образом:

def start_requests(self):
    request = Request('http://www.example.com/page.html', callback=self.parse_page)
    request.meta['proxy'] = 'http://198.51.100.14:8080'
    request.headers['Proxy-Authorization'] = 'Basic ' + base64.encodestring('johndoe:PaSsw0rd')
    return request

Теперь разберем второй вариант с переменными окружения и промежуточным слоем HttpProxyMiddleware.

Для включения HttpProxyMiddleware внесем в файл настроек проекта settings.py строки:

DOWNLOADER_MIDDLEWARES = {
    'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 750
}

Заметим, что на самом деле данную установку мы здесь указали в целях наглядности, в реальности же HttpProxyMiddleware активирована по умолчанию через DOWNLOADER_MIDDLEWARES_BASE в модуле scrapy.settings.default_settings.

Установим переменную:

$ export http_proxy="http://johndoe:PaSsw0rd@198.51.100.14:8080/"

Кроме http_proxy можно установить переменную https_proxy. Рассмотрим подробнее эти переменные. Значение переменных должно быть в виде URI и соответствовать формату scheme://username:password@host:port/, где

scheme
может быть http или https,
username, password
смысл очевиден, необязательные параметры и используются по необходимости,
host
доменное имя или IP-адрес,
port
соответственно порт.

Как видим Scrapy поддерживает HTTP и HTTPS типы прокси-серверов, а также авторизацию на этих серверах.

Третья возможная переменная no_proxy может содержать список доменых имен, IP-адресов, суффиксов доменных имен разделенные запятой, которые доступны без прохождения через прокси-сервера, напрямую. Установим эту переменную:

$ export no_proxy="localhost,127.0.0.1,example.org,.example.net"

Политика взаимодействия рассмотренных вариантов, заключается в том, что если метазначение proxy уже было установлено в объекте запроса, то промежуточный слой HttpProxyMiddleware игнорирует его и передает далее на обработку.

Таким образом мы имеем достаточно простые и гибкие возможности работы с наиболее распространенным типом проксирования “из коробки”.

Промежуточный слой прокси от Aivars Kalvāns

Помимо встроенных возможностей мы можем воспользоваться сторонними расширениями, например, классом RandomProxy от aivarsk.

Эта прослойка обрабатывает запросы, используя случайный прокси-сервер. Сервер выбирается из заранее заданного списка в обычном текстовом файле. Список прокси-серверов можно взять, к примеру, с ресурса http://hidemyass.com/.

Для включения слоя добавим в файл settings.py следующее:

DOWNLOADER_MIDDLEWARES = {
    'scrapy.contrib.downloadermiddleware.retry.RetryMiddleware': 500,
    'yourspider.randomproxy.RandomProxy': 625,
    'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 750,
}

PROXY_LIST = '/path/to/proxy/list.txt'

Здесь yourspider.randomproxy есть путь до рассматриваемого модуля, который нужно предварительно добавить в ваш проект.

Из особенностей стоит отметить три усовершенствования по сравнению со стандартными возможностями Scrapy. Во-первых, используется случайный прокси-сервер из списка для каждого запроса с неустановленным метазначением proxy. Во-вторых, список прокси задается во внешнем тектовом файле, что достаточно гибко, в том смысле, что мы отделяем данные от логики. В-третьих, в случае если возникает исключение при выполнени запроса, то запись о прокси-сервере, через который выполнялось соединение, удаляется из списка в переменной.