Прокси в Scrapy-Splash обеспечивают анонимность, обход географических ограничений и блокировок IP-адресов при рендеринге JavaScript-страниц, направляя запросы Splash через промежуточные серверы.
Scrapy-Splash — это комбинация фреймворка Scrapy и легковесного браузера Splash, предназначенная для выполнения запросов к веб-страницам, активно использующим JavaScript. Scrapy управляет логикой обхода и извлечения данных, а Splash выполняет рендеринг страниц в безголовом браузере (на основе Chromium/WebKit), предоставляя Scrapy уже обработанный HTML, скриншоты или данные HAR. Использование прокси-серверов со Scrapy-Splash критически важно для эффективного и устойчивого веб-скрейпинга.
Зачем использовать прокси со Scrapy-Splash
Рендеринг JavaScript-страниц является ресурсоемкой операцией. Без прокси-серверов запросы, исходящие от одного IP-адреса, быстро приводят к следующим проблемам:
- Блокировка IP-адреса: Веб-сайты активно мониторят аномально большое количество запросов с одного IP. Splash, загружая все ресурсы страницы (JS, CSS, изображения), генерирует значительно больше запросов, чем обычный HTTP-скрепер, что ускоряет обнаружение и блокировку.
- Географические ограничения: Некоторые веб-ресурсы отображают различное содержимое или полностью блокируют доступ в зависимости от географического местоположения пользователя. Прокси позволяют эмулировать запросы из нужного региона.
- Ограничение скорости (Rate Limiting): Сайты часто устанавливают лимиты на количество запросов в единицу времени с одного IP. Прокси-ротация позволяет распределить нагрузку между множеством IP-адресов, обходя эти ограничения.
- Анонимность: Прокси скрывают реальный IP-адрес клиента, обеспечивая анонимность при сборе данных.
Как Scrapy-Splash обрабатывает запросы с прокси
Когда Scrapy отправляет запрос в Splash, Splash сам выполняет HTTP-запросы к целевому веб-сайту. Таким образом, прокси должны быть настроены либо для самого сервиса Splash, либо переданы ему Scrapy для конкретного запроса. Splash поддерживает прокси-серверы HTTP, HTTPS и SOCKS5.
Конфигурация прокси в Scrapy-Splash
Существует два основных подхода к настройке прокси: глобальная настройка для Splash и настройка для каждого запроса из Scrapy.
Глобальная настройка прокси для Splash
Этот метод применяется, когда весь трафик Splash должен проходить через один прокси-сервер. Это удобно для простых сценариев или тестирования.
Через переменные окружения:
При запуске контейнера Docker с Splash можно передать переменные окружения:
docker run -p 8050:8050 \
--env HTTP_PROXY=http://user:pass@proxy_ip:port \
--env HTTPS_PROXY=http://user:pass@proxy_ip:port \
--env NO_PROXY="localhost,127.0.0.1" \
scrapinghub/splash
HTTP_PROXYиHTTPS_PROXYуказывают адрес прокси для HTTP и HTTPS трафика соответственно.user:pass— необязательные учетные данные для аутентификации прокси.NO_PROXY— список хостов, для которых прокси не используется.
Через аргументы командной строки Splash:
Если Splash запускается напрямую, можно использовать аргументы --proxy и --proxy-user.
splash --proxy=http://user:pass@proxy_ip:port
Настройка прокси для каждого запроса из Scrapy
Это наиболее гибкий и рекомендуемый подход для сложных задач сбора данных, требующих ротации прокси или использования различных прокси для разных типов запросов. Scrapy передает информацию о прокси в Splash через аргументы запроса.
Для использования Scrapy-Splash, необходимо настроить middlewares в settings.py:
# settings.py
SPLASH_URL = 'http://localhost:8050' # Адрес вашего Splash-сервера
DOWNLOADER_MIDDLEWARES = {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
SPIDER_MIDDLEWARES = {
'scrapy_splash.SplashMiddleware': 100,
}
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'
Далее, в пауке Scrapy, прокси можно указать двумя способами:
1. Использование аргумента proxy в SplashRequest
SplashRequest поддерживает аргумент proxy, который передается в Splash.
import scrapy
from scrapy_splash import SplashRequest
class MySpider(scrapy.Spider):
name = 'js_proxy_spider'
start_urls = ['http://example.com/js-page']
# Список прокси для ротации (пример)
proxy_list = [
'http://user1:pass1@proxy1.example.com:8000',
'http://user2:pass2@proxy2.example.com:8000',
'socks5://user3:pass3@proxy3.example.com:9000',
]
proxy_index = 0
def start_requests(self):
for url in self.start_urls:
yield SplashRequest(
url=url,
callback=self.parse,
endpoint='render.html',
args={'wait': 0.5},
proxy=self.get_next_proxy() # Присваиваем прокси из списка
)
def parse(self, response):
self.logger.info(f"Получена страница {response.url} через прокси {response.request.meta.get('proxy')}")
# Извлечение данных из response.body (отрендеренный HTML)
title = response.css('title::text').get()
self.logger.info(f"Заголовок: {title}")
yield {'title': title}
def get_next_proxy(self):
proxy = self.proxy_list[self.proxy_index]
self.proxy_index = (self.proxy_index + 1) % len(self.proxy_list)
return proxy
В этом примере self.get_next_proxy() возвращает следующий прокси из списка для каждого нового запроса. Splash будет использовать этот прокси для выполнения всех своих внутренних запросов к целевому сайту.
2. Использование Lua-скриптов с splash:set_proxy()
Для более тонкой настройки и динамического выбора прокси внутри Splash можно использовать Lua-скрипты. Функция splash:set_proxy(proxy_address) позволяет установить прокси непосредственно в скрипте.
import scrapy
from scrapy_splash import SplashRequest
lua_script = """
function main(splash, args)
splash:set_proxy{
host = args.proxy_host,
port = args.proxy_port,
username = args.proxy_user,
password = args.proxy_pass,
type = args.proxy_type,
}
assert(splash:go(args.url))
assert(splash:wait(0.5))
return {
html = splash:html(),
url = splash:url(),
}
end
"""
class MyLuaProxySpider(scrapy.Spider):
name = 'lua_proxy_spider'
start_urls = ['http://example.com/js-page']
proxy_configs = [
{'host': 'proxy1.example.com', 'port': 8000, 'user': 'user1', 'pass': 'pass1', 'type': 'HTTP'},
{'host': 'proxy2.example.com', 'port': 8000, 'user': 'user2', 'pass': 'pass2', 'type': 'HTTP'},
{'host': 'proxy3.example.com', 'port': 9000, 'user': 'user3', 'pass': 'pass3', 'type': 'SOCKS5'},
]
proxy_index = 0
def start_requests(self):
for url in self.start_urls:
proxy_conf = self.get_next_proxy_config()
yield SplashRequest(
url=url,
callback=self.parse,
endpoint='execute',
args={
'lua_source': lua_script,
'proxy_host': proxy_conf['host'],
'proxy_port': proxy_conf['port'],
'proxy_user': proxy_conf['user'],
'proxy_pass': proxy_conf['pass'],
'proxy_type': proxy_conf['type'],
}
)
def parse(self, response):
self.logger.info(f"Получена страница {response.url}")
title = response.css('title::text').get()
self.logger.info(f"Заголовок: {title}")
yield {'title': title}
def get_next_proxy_config(self):
proxy_conf = self.proxy_configs[self.proxy_index]
self.proxy_index = (self.proxy_index + 1) % len(self.proxy_configs)
return proxy_conf
Этот метод предоставляет более детальный контроль над тем, как Splash использует прокси, позволяя, например, динамически менять тип прокси или выполнять другие действия в Lua-скрипте до установки прокси.
Типы прокси и их применимость со Scrapy-Splash
Выбор типа прокси зависит от требований к анонимности, скорости и стоимости.
| Тип прокси | Описание | Применимость к Scrapy-Splash