Scrapy – мощный фреймворк для веб-скрейпинга на Python, предоставляющий широкий набор инструментов для извлечения данных из веба. Однако, иногда встроенных возможностей Scrapy может быть недостаточно для решения определенных задач. Именно здесь на помощь приходит библиотека requests.
requests — это библиотека Python, предназначенная для отправки HTTP-запросов. Она позволяет вам взаимодействовать с веб-серверами, отправлять данные и получать ответы. Интеграция requests в Scrapy расширяет возможности вашего парсера, позволяя обходить ограничения и извлекать данные, которые не доступны стандартными средствами Scrapy.
Преимущества использования Requests вместо Scrapy Request/Response
Хотя Scrapy предоставляет свои собственные объекты Request и Response, использование requests дает несколько преимуществ:
- Более гибкое управление запросами:
requestsпозволяет более детально контролировать параметры запроса, такие как заголовки, куки и тайм-ауты. - Простота использования: Синтаксис
requestsчасто считается более интуитивным и простым для понимания, особенно для новичков. - Расширенные возможности:
requestsпредлагает расширенные функции, такие как поддержка сессий, аутентификации и прокси.
Когда Requests полезен: динамический контент, API и обход защиты
requests особенно полезен в следующих сценариях:
- Скрапинг сайтов с динамически подгружаемым контентом (JavaScript): Когда контент генерируется на стороне клиента с помощью JavaScript, Scrapy может не увидеть его.
requestsпозволяет выполнить JavaScript код (обычно в связке с Selenium или Puppeteer) и получить итоговый HTML. - Взаимодействие с API: Многие веб-сайты предоставляют API для доступа к данным.
requestsупрощает отправку запросов к API и обработку ответов в формате JSON или XML. - Обход защиты от скрапинга: Некоторые сайты используют сложные методы защиты от скрапинга, такие как капчи, лимиты запросов и блокировка IP-адресов.
requestsпозволяет более гибко управлять заголовками, куками и прокси, что помогает обходить эти защиты.
Установка и настройка: подготовка к работе с Requests
Установка библиотеки Requests
Установите библиотеку requests с помощью pip:
pip install requests
Настройка Scrapy проекта: добавление middleware
Вам не требуется добавлять middleware для использования requests, но это может понадобится для более сложных задач, таких как ротация прокси.
Импорт Requests в ваш Scrapy spider
Импортируйте библиотеку requests в ваш Scrapy spider:
import scrapy
import requests
class MySpider(scrapy.Spider):
name = "myspider"
start_urls = ["http://example.com"]
def parse(self, response):
# Здесь будет код с использованием requests
pass
Реализация: Использование Requests в Scrapy Spider
Отправка GET запросов с помощью Requests
Отправьте GET запрос с помощью requests.get():
import scrapy
import requests
class MySpider(scrapy.Spider):
name = "myspider"
start_urls = ["http://example.com"]
def parse(self, response):
r = requests.get("http://example.com/api/data")
# Дальнейшая обработка ответа
Обработка ответов Requests и извлечение данных
Получите данные из ответа:
r = requests.get("http://example.com/api/data")
if r.status_code == 200:
data = r.json() # Если ответ в формате JSON
# Или
data = r.text # Если ответ в формате HTML или текста
for item in data:
yield {"item": item}
else:
self.logger.error(f"Request failed with status code: {r.status_code}")
Отправка POST запросов с помощью Requests
Отправьте POST запрос с данными:
import scrapy
import requests
import json
class MySpider(scrapy.Spider):
name = "myspider"
start_urls = ["http://example.com"]
def parse(self, response):
payload = {"key1": "value1", "key2": "value2"}
r = requests.post("http://example.com/api/post", data=json.dumps(payload))
if r.status_code == 200:
# Обработка успешного ответа
pass
else:
self.logger.error(f"POST request failed with status code: {r.status_code}")
Передача заголовков и куки (cookies) с Requests
Добавьте заголовки и куки к запросу:
headers = {"User-Agent": "My Scrapy Bot"}
cookies = {"sessionid": "1234567890"}
r = requests.get("http://example.com", headers=headers, cookies=cookies)
Продвинутое использование: Обход ограничений и оптимизация
Использование прокси с Requests для обхода блокировок
Используйте прокси для маскировки вашего IP-адреса:
proxies = {"http": "http://proxy.example.com:8080", "https": "https://proxy.example.com:8080"}
r = requests.get("http://example.com", proxies=proxies)
Обработка ошибок и исключений при работе с Requests
Обрабатывайте возможные ошибки:
try:
r = requests.get("http://example.com", timeout=10) # Добавлен таймаут
r.raise_for_status() # Raises HTTPError for bad responses (4XX, 5XX)
except requests.exceptions.RequestException as e:
self.logger.error(f"Request failed: {e}")
Асинхронные запросы с Requests (библиотека grequests или asyncio)
Для повышения производительности используйте асинхронные запросы (например, с помощью grequests):
import grequests
urls = ["http://example.com", "http://example.org", "http://example.net"]
rs = (grequests.get(u) for u in urls)
responses = grequests.map(rs)
for response in responses:
if response:
print(response.status_code)
else:
print("Request failed")
Примеры и лучшие практики
Пример: Скрапинг сайта с динамически подгружаемым контентом
Предположим, есть сайт, где товары подгружаются при прокрутке страницы. Scrapy может не увидеть все товары сразу. Используйте requests в связке с Selenium для получения полного HTML:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import scrapy
class DynamicSpider(scrapy.Spider):
name = "dynamic_spider"
start_urls = ["http://example.com/dynamic_page"]
def __init__(self):
chrome_options = Options()
chrome_options.add_argument("--headless") # Запуск Chrome в фоновом режиме
self.driver = webdriver.Chrome(options=chrome_options)
super().__init__()
def parse(self, response):
self.driver.get(response.url)
# Прокрутка страницы вниз для загрузки всего контента
for _ in range(3): # Прокрутить 3 раза, можно настроить
self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2) # Подождать пока подгрузится контент
html = self.driver.page_source
self.driver.quit()
# Теперь можно использовать BeautifulSoup или Scrapy для парсинга html
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
# Пример извлечения всех заголовков h2
for h2 in soup.find_all('h2'):
yield {"title": h2.text}
Рекомендации по эффективному использованию Requests в Scrapy
- Избегайте блокировки Scrapy: Не блокируйте цикл обработки Scrapy, выполняя длительные операции синхронно. Используйте асинхронные запросы, где это возможно.
- Управляйте куками и сессиями: Правильно обрабатывайте куки и сессии для поддержания состояния между запросами.
- Обрабатывайте ошибки: Реализуйте надежную обработку ошибок и исключений, чтобы ваш парсер не останавливался при возникновении проблем.
- Используйте прокси и User-Agent: Регулярно меняйте User-Agent и используйте прокси для обхода ограничений и блокировок.
- Оптимизируйте запросы: Старайтесь отправлять только необходимые запросы и минимизируйте размер передаваемых данных.