Beautiful Soup ve requests ile proxy üzerinden scraping, HTML içeriğini Beautiful Soup ile ayrıştırmadan önce requests kütüphanesini web trafiğini belirli bir proxy sunucusu üzerinden yönlendirecek şekilde yapılandırmak demektir; bu sayede IP rotasyonu, coğrafi kısıtlamaların aşılması ve IP engellerinin azaltılması mümkün olur.
Web scraping yaparken tek bir IP adresinden gelen doğrudan istekler rate limit'e, geçici veya kalıcı IP banlarına ya da coğrafi kısıtlı içeriğe yol açabilir. Proxy hizmetleri istekleri farklı IP adresleri üzerinden yönlendirerek bu sorunları çözer ve scraping'i daha sağlam, daha ölçeklenebilir hale getirir.
Bu iş için temel kütüphaneler şunlardır:
* requests: Python için bir HTTP kütüphanesi; HTTP isteği göndermeyi basitleştirir.
* Beautiful Soup: HTML ve XML belgelerini ayrıştıran bir Python kütüphanesi.
requests ile proxy yapılandırma
requests kütüphanesi, istek metotlarındaki proxies parametresi üzerinden proxy yapılandırmasını destekler.
Tek proxy yapılandırması
Tek bir proxy kullanmak için protokolleri (HTTP, HTTPS) proxy URL'sine eşleyen bir sözlük verin.
import requests
proxy_http = "http://your_proxy_ip:port"
proxy_https = "https://your_proxy_ip:port" # Genellikle HTTP ile aynıdır
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}")
Proxy kimlik doğrulama
Kimlik doğrulama gerektiren proxy'ler için kimlik bilgilerini doğrudan proxy URL'sinin içine gömün.
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}")
Rotasyonlu proxy'ler
Büyük ölçekli scraping'de istekleri dağıtmak ve engellenme riskini azaltmak için bir proxy listesi üzerinde rotasyon yapmak şarttır.
import requests
import random
import time
proxy_list = [
"http://user1:[email protected]:8000",
"http://user2:[email protected]:8000",
"http://user3:[email protected]: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)) # Yeni bir proxy ile yeniden denemeden önce bekleme
return None
# Deneme amaçlı bir URL ile örnek kullanım
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}")
Beautiful Soup ile HTML ayrıştırma
Beautiful Soup, bir requests yanıtındaki HTML içeriğini gezinilebilir bir Python nesnesine dönüştürür.
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')
# Öğelere erişim
print("Page Title:", soup.title.string)
# Belirli öğeleri bulma
intro_paragraph = soup.find('p', class_='intro')
print("Intro text:", intro_paragraph.get_text(strip=True))
# class değerine göre tüm öğeleri bulma
product_links = soup.find_all('a', class_='product-link')
for link in product_links:
print(f"Product: {link.get_text()}, URL: {link['href']}")
Proxy'leri Beautiful Soup ile scraping'e entegre etme
Proxy yapılandırmasını Beautiful Soup ayrıştırmasıyla birleştirmek eksiksiz bir scraping akışı sağlar.
import requests
from bs4 import BeautifulSoup
import random
import time
# --- Proxy yapılandırması (daha önce tanımlandığı gibi) ---
proxy_list = [
"http://user1:[email protected]:8000",
"http://user2:[email protected]:8000",
# Servisinizden daha fazla proxy ekleyin
]
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 mantığı ---
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 []
# --- Çalıştırma ---
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]): # Kısalık için ilk 3 tanesini yazdır
print(f" {i+1}. Author: {quote['author']}, Quote: {quote['text'][:50]}...")
else:
print("No data scraped.")
En iyi uygulamalar ve dikkat edilecek noktalar
User-Agent başlıkları
Web sunucuları istemciyi tanımlamak için sık sık User-Agent başlığını inceler. requests kütüphanesinin varsayılan User-Agent değeri bot olduğunuzu ele verebilir. Yaygın bir tarayıcının User-Agent değerini taklit etmek tespit edilme olasılığını düşürür.
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)
İstek gecikmeleri ve throttling
Çok hızlı gönderilen istekler rate limit'leri veya IP banlarını tetikleyebilir. Özellikle proxy rotasyonu yaparken istekler arasına gecikme koyun. Rastgele bir aralıkla kullanılan time.sleep() etkili bir yöntemdir.
import time
import random
# ... birden fazla URL işleyen bir döngünün içinde ...
time.sleep(random.uniform(2, 7)) # 2 ile 7 saniye arasında bekle
response = make_proxied_request(next_url, headers=headers)
Hata yönetimi
Sağlam bir scraping; ağ sorunları, proxy arızaları ve sunucu yanıtları için kapsamlı hata yönetimi gerektirir.
* requests.exceptions.RequestException: requests kaynaklı tüm hataları (bağlantı, timeout, HTTP hataları) yakalar.
* HTTP durum kodları: response.status_code değerini kontrol edin. 403 (Forbidden), 404 (Not Found), 429 (Too Many Requests) veya 5xx (Server Error) gibi kodlar sorun işaretidir.
* Timeout: sonsuz beklemeleri önlemek için requests.get() içinde timeout parametresini ayarlayın.
CAPTCHA'lar ve gelişmiş anti-scraping önlemleri
Bazı siteler CAPTCHA veya JavaScript sınamaları gibi gelişmiş tespit mekanizmaları kullanır. Proxy'ler IP rotasyonunda yardımcı olur ancak bunları doğrudan çözmez. Bu gibi durumlarda headless tarayıcıları (örneğin Selenium, Playwright) veya özel CAPTCHA çözüm servislerini değerlendirin.
Proxy türlerinin karşılaştırması
| Özellik | Veri merkezi proxy'leri | Residential proxy'ler |
|---|---|---|
| IP kaynağı | Ticari sunucular, bulut sağlayıcıları | ISP IP'lerine sahip gerçek kullanıcı cihazları (masaüstü, mobil) |
| Anonimlik | Yüksek, ancak IP'ler çoğu zaman veri merkezi olarak tanınır | Çok yüksek, IP'ler meşru kullanıcı gibi görünür |
| Maliyet | Genellikle daha düşük | Belirgin şekilde daha yüksek |
| Hız | Tipik olarak daha hızlı, gecikme daha düşük | Daha yavaş olabilir, gecikme daha yüksek |
| Tespit riski | Tespit edilme/engellenme riski daha yüksek | Daha düşük risk, sıkı anti-bot önlemlerini aşmak için ideal |
| Kullanım alanları | Genel scraping, açık veriler, daha az korunan siteler | Yüksek değerli hedefler, e-ticaret, sosyal medya, coğrafi hedefleme |
Yasal ve etik hususlar
robots.txt: Sitenin, tarayıcı botları için kuralları belirleyenrobots.txtdosyasına uyun. Dosyayahttp://example.com/robots.txtadresinden erişebilirsiniz.- Kullanım şartları: Sitenin kullanım şartlarını inceleyin. Scraping yasaklanmış olabilir.
- Veri kullanımı: Veri koruma mevzuatına (örneğin GDPR, CCPA) uyum sağlayın.
- Sunucuya etkisi: Hedef sunucuyu istek yağmuruna tutmaktan kaçının. Uygun gecikmeler uygulayın.
