Перейти к содержимому
Гайды 8 мин чтения 2 просмотров

Парсинг с прокси через Beautiful Soup и requests

Подробное руководство по настройке парсинга веб-данных с использованием прокси-серверов, библиотек Beautiful Soup и requests для обхода блокировок.

Python Парсинг

Парсинг с прокси через Beautiful Soup и requests позволяет извлекать структурированные данные с веб-сайтов, обходя ограничения по IP-адресу, обеспечивая географический таргетинг и повышая анонимность запросов.

Основы requests и Beautiful Soup

Для веб-парсинга на Python широко используются две библиотеки: requests для выполнения HTTP-запросов и Beautiful Soup для анализа (парсинга) полученного HTML- или XML-контента.

Библиотека requests

requests — это HTTP-библиотека для Python, упрощающая отправку HTTP/1.1-запросов. Она абстрагирует сложность работы с HTTP-запросами, позволяя легко отправлять GET, POST и другие типы запросов, обрабатывать куки, сессии и заголовки.

Установка:

pip install requests

Базовый GET-запрос:

import requests

url = "http://example.com"
response = requests.get(url)
print(response.status_code)
print(response.text[:200]) # Вывод первых 200 символов HTML

Библиотека Beautiful Soup

Beautiful Soup (bs4) — это библиотека для парсинга HTML и XML документов. Она создает дерево парсинга из содержимого страницы, что позволяет легко извлекать данные, используя различные методы поиска по тегам, классам, идентификаторам и CSS-селекторам.

Установка:

pip install beautifulsoup4

Базовое использование:

from bs4 import BeautifulSoup
import requests

url = "http://example.com"
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

# Поиск первого заголовка h1
h1_tag = soup.find('h1')
if h1_tag:
    print(f"Заголовок H1: {h1_tag.text}")

# Поиск всех ссылок
links = soup.find_all('a')
for link in links:
    print(f"Ссылка: {link.get('href')}, Текст: {link.text}")

Зачем нужны прокси при парсинге

Использование прокси-серверов при парсинге критически важно для эффективного и масштабируемого сбора данных:

  • Обход блокировок по IP: Многие веб-сайты блокируют IP-адреса, с которых поступает слишком много запросов за короткий период. Прокси позволяют распределить запросы по множеству IP-адресов, снижая вероятность блокировки.
  • Географический таргетинг: Прокси-серверы позволяют отправлять запросы с IP-адресов, расположенных в определенной стране или регионе. Это необходимо для сбора данных, специфичных для конкретной локации (например, цены, доступность товаров).
  • Анонимность: Прокси маскируют реальный IP-адрес клиента, повышая анонимность парсинга и защищая от идентификации.
  • Обход лимитов запросов: Используя пул прокси, можно эффективно увеличить общий объем запросов к целевому ресурсу, оставаясь при этом в рамках лимитов для каждого отдельного IP.

Настройка прокси в requests

Библиотека requests позволяет легко настроить использование прокси через параметр proxies.

Простые прокси

Прокси-серверы указываются в виде словаря, где ключами являются протоколы (http, https), а значениями — адреса прокси.

import requests

url = "http://httpbin.org/ip" # Сервис для проверки IP-адреса
proxies = {
    "http": "http://192.168.1.1:8080", # Пример HTTP прокси
    "https": "http://192.168.1.2:8080", # Пример HTTPS прокси
}

try:
    response = requests.get(url, proxies=proxies, timeout=5)
    print(f"Статус код: {response.status_code}")
    print(f"Ваш IP через прокси: {response.json().get('origin')}")
except requests.exceptions.RequestException as e:
    print(f"Ошибка при запросе через прокси: {e}")

Если прокси-сервер использует протокол SOCKS, его можно указать следующим образом:

proxies_socks = {
    "http": "socks5://user:password@192.168.1.3:9050", # SOCKS5 с аутентификацией
    "https": "socks5://192.168.1.4:9050", # SOCKS5 без аутентификации
}
# requests.get(url, proxies=proxies_socks, timeout=5)

Обратите внимание, что для SOCKS-прокси требуется установка дополнительной библиотеки PySocks:

pip install "requests[socks]"

Прокси с аутентификацией

Многие платные прокси-сервисы требуют аутентификацию по логину и паролю. Их можно включить непосредственно в URL прокси:

import requests

url = "http://httpbin.org/ip"
proxy_user = "your_username"
proxy_pass = "your_password"
proxy_host = "proxy.example.com"
proxy_port = "8000"

proxies_auth = {
    "http": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
    "https": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
}

try:
    response = requests.get(url, proxies=proxies_auth, timeout=10)
    print(f"Статус код: {response.status_code}")
    print(f"Ваш IP через прокси с аутентификацией: {response.json().get('origin')}")
except requests.exceptions.RequestException as e:
    print(f"Ошибка при запросе через прокси с аутентификацией: {e}")

Типы прокси

Прокси-серверы различаются по протоколам и функциональности:

Тип прокси Описание Применение
HTTP Предназначен для HTTP-трафика. Может быть прозрачным, анонимным или элитным. Перехватывает и модифицирует заголовки, что может быть обнаружено. Базовый парсинг HTTP-сайтов, когда анонимность не является критичной или сайт не активно детектирует прокси.
HTTPS Поддерживает зашифрованный HTTPS-трафик. Работает как HTTP-прокси, но устанавливает туннель для HTTPS-соединений, не расшифровывая трафик. Парсинг HTTPS-сайтов. Обеспечивает безопасность соединения между клиентом и прокси. Для сквозного шифрования между клиентом и целевым сервером требуется, чтобы прокси не выполнял MITM-атаку.
SOCKS4 Прокси на уровне сессии. Передает TCP-пакеты без интерпретации содержимого. Не поддерживает UDP и DNS-запросы удаленно (клиент должен разрешать DNS-имена). Когда требуется передача данных без модификации заголовков. Менее распространен для веб-парсинга по сравнению с SOCKS5.
SOCKS5 Более продвинутый прокси, поддерживающий TCP, UDP, аутентификацию и удаленное разрешение DNS-имен. Передает данные без изменения заголовков HTTP/HTTPS, что делает его более "невидимым" для целевого сервера. Наиболее универсальный тип прокси для парсинга, особенно когда требуется высокая анонимность и обход продвинутых систем детектирования прокси. Подходит для различных типов трафика, включая HTTP/HTTPS, FTP и другие. Рекомендуется для большинства задач парсинга, требующих повышенной скрытности.

Комплексный пример: парсинг с прокси и Beautiful Soup

Объединим requests с прокси и Beautiful Soup для извлечения данных.

import requests
from bs4 import BeautifulSoup
import time
import random

def get_html_with_proxy(url, proxy_list, headers=None, timeout=15):
    """
    Выполняет GET-запрос к URL, используя случайный прокси из списка.
    Возвращает объект BeautifulSoup или None в случае ошибки.
    """
    if not proxy_list:
        print("Список прокси пуст.")
        return None

    # Попытка использовать каждый прокси из списка
    for _ in range(len(proxy_list)):
        proxy_url = random.choice(proxy_list)
        proxies = {
            "http": proxy_url,
            "https": proxy_url,
        }

        try:
            print(f"Попытка запроса к {url} через прокси: {proxy_url}")
            response = requests.get(url, proxies=proxies, headers=headers, timeout=timeout)
            response.raise_for_status() # Вызывает исключение для статусов 4xx/5xx
            print(f"Запрос успешен со статусом: {response.status_code}")
            return BeautifulSoup(response.text, 'html.parser')
        except requests.exceptions.ProxyError as e:
            print(f"Ошибка прокси {proxy_url}: {e}")
            # Удалить неработающий прокси из списка для текущей сессии, если нужно
            # proxy_list.remove(proxy_url) # Может привести к ошибкам при итерации, если не скопировать список
        except requests.exceptions.RequestException as e:
            print(f"Ошибка запроса через прокси {proxy_url}: {e}")

        time.sleep(random.uniform(1, 3)) # Задержка перед следующей попыткой

    print(f"Не удалось получить данные с {url} после всех попыток с прокси.")
    return None

# Список прокси (замените на свои рабочие прокси)
# Формат: "http://user:pass@host:port" или "socks5://user:pass@host:port"
my_proxies = [
    "http://user1:pass1@proxy1.example.com:8000",
    "http://user2:pass2@proxy2.example.com:8000",
    "socks5://user3:pass3@proxy3.example.com:9050",
]

# Пользовательские заголовки для имитации браузера
custom_headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
}

target_url = "https://quotes.toscrape.com/" # Пример сайта для парсинга

soup = get_html_with_proxy(target_url, my_proxies, headers=custom_headers)

if soup:
    print("\n--- Найденные цитаты ---")
    quotes = soup.find_all('div', class_='quote')
    for quote in quotes:
        text = quote.find('span', class_='text').text
        author = quote.find('small', class_='author').text
        tags = [tag.text for tag in quote.find('div', class_='tags').find_all('a', class_='tag')]
        print(f"Цитата: {text}")
        print(f"Автор: {author}")
        print(f"Теги: {', '.join(tags)}")
        print("-" * 30)
else:
    print("Не удалось получить или распарсить страницу.")

Продвинутые техники и соображения

Ротация прокси

Использование одного прокси-сервера быстро приводит к его блокировке. Ротация прокси — это практика циклической смены IP-адресов для каждого запроса или группы запросов. Это значительно повышает устойчивость парсера к блокировкам.

import random

# Предположим, у вас есть большой список прокси
large_proxy_list = [
    "http://proxy1.example.com:8000",
    "http://proxy2.example.com:8000",
    "socks5://proxy3.example.com:9050",
    # ... сотни или тысячи прокси
]

def get_random_proxy(proxy_pool):
    """Выбирает случайный прокси из пула."""
    return random.choice(proxy_pool)

# В цикле парсинга:
# for page_num in range(1, 100):
#     current_proxy = get_random_proxy(large_proxy_list)
#     proxies = {"http": current_proxy, "https": current_proxy}
#     response = requests.get(url_for_page(page_num), proxies=proxies, headers=custom_headers)
#     # ... обработка ответа
#     time.sleep(random.uniform(2, 5)) # Задержка между запросами

Качество прокси

Качество прокси-сервера влияет на успех парсинга:

  • Датацентровые прокси: Дешевле, быстрее, но легко обнаруживаются и блокируются, так как их IP-адреса часто известны как принадлежащие датацентрам. Подходят для сайтов с низкой защитой.
  • Резидентные прокси: Используют реальные IP-адреса домашних пользователей, что делает их гораздо сложнее для обнаружения. Дороже, но обеспечивают высокую степень анонимности и устойчивость к блокировкам. Рекомендуются для сайтов с продвинутой защитой.
  • Мобильные прокси: Используют IP-адреса мобильных операторов. Считаются одними из самых надежных, так как мобильные IP-адреса часто меняются и воспринимаются как легитимный трафик. Самые дорогие.

Управление заголовками и User-Agent

Многие веб-сайты проверяют заголовки HTTP-запросов для идентификации клиента. Отсутствие или некорректные заголовки могут привести к блокировке.

  • User-Agent: Имитация браузера. Рекомендуется использовать актуальные User-Agent строки и ротировать их.
  • Referer: Имитация перехода с другой страницы.
  • Accept-Language, Accept-Encoding: Имитация настроек браузера пользователя.
user_agents = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0",
]

def get_random_headers():
    headers = {
        "User-Agent": random.choice(user_agents),
        "Accept-Language": "en-US,en;q=0.9",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "Connection": "keep-alive",
        "Upgrade-Insecure-Requests": "1",
    }
    return headers

# В запросе:
# response = requests.get(url, proxies=proxies, headers=get_random_headers(), timeout=10)

Сессии requests

Использование requests.Session() позволяет сохранять параметры между запросами, включая куки, заголовки и настройки прокси. Это полезно для парсинга сайтов, требующих авторизации или поддерживающих состояние.

import requests

with requests.Session() as session:
    session.proxies = {
        "http": "http://user:pass@proxy.example.com:8000",
        "https": "http://user:pass@proxy.example.com:8000",
    }
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    })

    # Все последующие запросы через эту сессию будут использовать настроенные прокси и заголовки
    response1 = session.get("http://example.com/login")
    # ... обработка логина, куки сохранятся в сессии
    response2 = session.get("http://example.com/profile")

Распространенные проблемы и их решение

  • IP-блокировка: Даже с прокси, агрессивный парсинг может привести к блокировке. Решение: увеличить пул прокси, использовать более качественные прокси (резидентные, мобильные), замедлить частоту запросов, ротировать User-Agent.
  • CAPTCHA: Некоторые сайты отображают CAPTCHA для подозрительного трафика. Решение: использовать сервисы по обходу CAPTCHA (например, 2Captcha, Anti-Captcha), либо замедлить запросы и улучшить имитацию поведения браузера.
  • JavaScript-рендеринг: Beautiful Soup парсит только статичный HTML. Если контент генерируется JavaScript, он не будет виден. Решение: использовать headless-браузеры (Selenium, Playwright) или библиотеки, такие как requests-html, которые могут выполнять JavaScript.
  • SSL/TLS ошибки: Могут возникать с некоторыми прокси, особенно если прокси-сервер модифицирует SSL-сертификаты. Решение: убедиться, что прокси корректно обрабатывает HTTPS. В крайнем случае, можно временно отключить проверку SSL (verify=False в requests.get), но это не рекомендуется для продакшн-систем из соображений безопасности.
  • Тайм-ауты: Прокси могут быть медленными или недоступными. Устанавливайте адекватные timeout для запросов и реализуйте логику повторных попыток с другими прокси.
  • HTTP-статусы 4xx/5xx: Обрабатывайте ошибки, такие как 403 Forbidden, 404 Not Found, 429 Too Many Requests, 500 Internal Server Error. Для 403/429 это часто признак блокировки или ограничения, требующий смены прокси или User-Agent.
Обновлено: 04.03.2026
Назад к категории

Попробуйте наши прокси

20,000+ прокси в 100+ странах мира