Scraping за допомогою Beautiful Soup та requests з використанням проксі передбачає налаштування бібліотеки requests для маршрутизації веб-трафіку через вказаний проксі-сервер перед аналізом HTML-вмісту за допомогою Beautiful Soup, що дозволяє обертати IP-адреси, обходити геообмеження та пом'якшувати блокування IP-адрес.
Під час веб-скрейпінгу прямі запити з однієї IP-адреси можуть призвести до обмеження частоти запитів, тимчасових або постійних блокувань IP-адрес або геообмеженого вмісту. Проксі-сервіси вирішують ці проблеми, маршрутизуючи запити через різні IP-адреси, роблячи скрейпінг більш надійним та масштабованим.
Основними бібліотеками для цього завдання є:
* requests: Бібліотека HTTP для Python, що спрощує надсилання HTTP-запитів.
* Beautiful Soup: Бібліотека Python для аналізу HTML та XML документів.
Налаштування проксі за допомогою requests
Бібліотека requests підтримує налаштування проксі через параметр proxies у своїх методах запитів.
Налаштування одного проксі
Щоб використовувати один проксі, надайте словник, що зіставляє протоколи (HTTP, HTTPS) з URL-адресою проксі.
import requests
proxy_http = "http://your_proxy_ip:port"
proxy_https = "https://your_proxy_ip:port" # Often identical to HTTP
proxies = {
"http": proxy_http,
"https": proxy_https,
}
try:
response = requests.get("http://httpbin.org/ip", proxies=proxies, timeout=10)
response.raise_for_status()
print("External IP:", response.json().get('origin'))
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
Автентифікація проксі
Для проксі, що вимагають автентифікації, вбудуйте облікові дані безпосередньо в URL-адресу проксі.
import requests
proxy_user = "your_username"
proxy_pass = "your_password"
proxy_host = "your_proxy_ip"
proxy_port = "port"
authenticated_proxy = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
proxies = {
"http": authenticated_proxy,
"https": authenticated_proxy,
}
try:
response = requests.get("http://httpbin.org/ip", proxies=proxies, timeout=10)
response.raise_for_status()
print("External IP (authenticated):", response.json().get('origin'))
except requests.exceptions.RequestException as e:
print(f"Authenticated request failed: {e}")
Обертання проксі
Для великомасштабного скрейпінгу обертання через список проксі є важливим для розподілу запитів та мінімізації ризику блокування.
import requests
import random
import time
proxy_list = [
"http://user1:pass1@proxy1.example.com:8000",
"http://user2:pass2@proxy2.example.com:8000",
"http://user3:pass3@proxy3.example.com:8000",
]
def get_random_proxy():
return random.choice(proxy_list)
def make_proxied_request(url, headers=None, attempt_limit=3):
for attempt in range(attempt_limit):
proxy_url = get_random_proxy()
proxies = {"http": proxy_url, "https": proxy_url}
try:
print(f"Attempt {attempt + 1}: Using proxy {proxy_url.split('@')[-1]} for {url}")
response = requests.get(url, proxies=proxies, headers=headers, timeout=15)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
print(f"Proxy request failed (attempt {attempt + 1}): {e}")
time.sleep(random.uniform(2, 5)) # Delay before retrying with a new proxy
return None
# Example usage with a dummy URL
try:
target_url = "http://quotes.toscrape.com/"
response = make_proxied_request(target_url)
if response:
print(f"Successfully fetched {target_url} with status code {response.status_code}")
except Exception as e:
print(f"Failed to fetch {target_url} after multiple retries: {e}")
Аналіз HTML за допомогою Beautiful Soup
Beautiful Soup перетворює HTML-вміст з відповіді requests на навігаційний об'єкт Python.
from bs4 import BeautifulSoup
html_doc = """
<html>
<head><title>Example Page</title></head>
<body>
<p class="intro"><b>Welcome!</b></p>
<div id="content">
<a href="/item1" class="product-link">Product A</a>
<a href="/item2" class="product-link">Product B</a>
</div>
</body>
</html>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
# Accessing elements
print("Page Title:", soup.title.string)
# Finding specific elements
intro_paragraph = soup.find('p', class_='intro')
print("Intro text:", intro_paragraph.get_text(strip=True))
# Finding all elements by class
product_links = soup.find_all('a', class_='product-link')
for link in product_links:
print(f"Product: {link.get_text()}, URL: {link['href']}")
Інтеграція проксі зі скрейпінгом Beautiful Soup
Поєднання налаштування проксі з аналізом Beautiful Soup забезпечує повний робочий процес скрейпінгу.
import requests
from bs4 import BeautifulSoup
import random
import time
# --- Proxy Configuration (as defined previously) ---
proxy_list = [
"http://user1:pass1@proxy1.example.com:8000",
"http://user2:pass2@proxy2.example.com:8000",
# Add more proxies from your service
]
def get_random_proxy():
return random.choice(proxy_list)
def make_proxied_request(url, headers=None, attempt_limit=3):
for attempt in range(attempt_limit):
proxy_url = get_random_proxy()
proxies = {"http": proxy_url, "https": proxy_url}
try:
print(f"Attempt {attempt + 1} for {url}: Using proxy {proxy_url.split('@')[-1]}")
response = requests.get(url, proxies=proxies, headers=headers, timeout=15)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
print(f"Request failed (attempt {attempt + 1}): {e}")
time.sleep(random.uniform(2, 5))
return None
# --- Scraping Logic ---
def scrape_quotes(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = make_proxied_request(url, headers=headers)
if response:
soup = BeautifulSoup(response.text, 'html.parser')
quotes = soup.find_all('div', class_='quote')
data = []
for quote in quotes:
text = quote.find('span', class_='text').get_text(strip=True)
author = quote.find('small', class_='author').get_text(strip=True)
tags = [tag.get_text(strip=True) for tag in quote.find_all('a', class_='tag')]
data.append({"text": text, "author": author, "tags": tags})
return data
return []
# --- Execution ---
if __name__ == "__main__":
target_url = "http://quotes.toscrape.com/"
print(f"Starting scrape of {target_url}")
scraped_data = scrape_quotes(target_url)
if scraped_data:
print(f"Scraped {len(scraped_data)} quotes:")
for i, quote in enumerate(scraped_data[:3]): # Print first 3 for brevity
print(f" {i+1}. Author: {quote['author']}, Quote: {quote['text'][:50]}...")
else:
print("No data scraped.")
Найкращі практики та міркування
Заголовки User-Agent
Веб-сервери часто перевіряють заголовок User-Agent для ідентифікації клієнта. За замовчуванням requests User-Agent може вказувати на бота. Імітація поширеного User-Agent браузера зменшує ймовірність виявлення.
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 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/webp,*/*;q=0.8",
"Connection": "keep-alive",
}
response = requests.get(url, proxies=proxies, headers=headers)
Затримки запитів та регулювання
Швидкі запити можуть спричинити обмеження частоти запитів або блокування IP-адрес. Впроваджуйте затримки між запитами, особливо при обертанні проксі. time.sleep() з випадковим діапазоном затримки є ефективним.
import time
import random
# ... inside a loop processing multiple URLs ...
time.sleep(random.uniform(2, 7)) # Wait between 2 and 7 seconds
response = make_proxied_request(next_url, headers=headers)
Обробка помилок
Надійний скрейпінг вимагає комплексної обробки помилок для проблем з мережею, збоїв проксі та відповідей сервера.
* requests.exceptions.RequestException: Перехоплює всі помилки, пов'язані з requests (з'єднання, тайм-аут, HTTP-помилки).
* Коди стану HTTP: Перевіряйте response.status_code. Коди, такі як 403 (Forbidden), 404 (Not Found), 429 (Too Many Requests) або 5xx (Server Error), вказують на проблеми.
* Тайм-аути: Налаштуйте параметр timeout у requests.get(), щоб запобігти нескінченному очікуванню.
CAPTCHA та розширені заходи проти скрейпінгу
Деякі веб-сайти використовують розширені механізми виявлення, такі як CAPTCHA або JavaScript-виклики. Проксі допомагають з обертанням IP-адрес, але не вирішують ці проблеми безпосередньо. Для таких випадків розгляньте безголові браузери (наприклад, Selenium, Playwright) або спеціалізовані сервіси для розв'язання CAPTCHA.
Порівняння типів проксі
| Функція | Проксі датацентрів | Резидентні проксі |
|---|---|---|
| Джерело IP | Комерційні сервери, хмарні провайдери | Реальні пристрої користувачів (настільні, мобільні) з IP-адресами провайдерів |
| Анонімність | Висока, але IP-адреси часто розпізнаються як датацентрові | Дуже висока, IP-адреси виглядають як легітимні користувачі |
| Вартість | Зазвичай нижча | Значно вища |
| Швидкість | Зазвичай швидша, менша затримка | Може бути повільнішою, більша затримка |
| Ризик виявлення | Вищий ризик виявлення/блокування | Нижчий ризик, ідеально підходить для обходу суворих заходів проти ботів |
| Випадки використання | Загальний скрейпінг, публічні дані, менш захищені сайти | Високоцільові об'єкти, електронна комерція, соціальні мережі, геотаргетинг |
Юридичні та етичні міркування
robots.txt: Дотримуйтесь файлуrobots.txtвеб-сайту, який визначає правила для веб-сканерів. Доступ до нього за адресоюhttp://example.com/robots.txt.- Умови використання: Перегляньте умови використання веб-сайту. Скрейпінг може бути заборонений.
- Використання даних: Забезпечте відповідність правилам захисту даних (наприклад, GDPR, CCPA).
- Вплив на сервер: Уникайте перевантаження цільового сервера запитами. Впроваджуйте відповідні затримки.