Dlaczego DrissionPage zmienia zasady gry w web scrapingu
DrissionPage to framework Python, który łączy dwie tradycyjnie oddzielne światy: żądania HTTP w stylu requests i pełną kontrolę przeglądarki Chromium przez Chrome DevTools Protocol (CDP). Zamiast utrzymywać dwa osobne stacki — jeden do prostych zapytań, drugi do stron renderowanych przez JavaScript — otrzymujesz jeden obiekt WebPage, który płynnie przełącza tryby, współdzieląc ciasteczka, sesję i stan.
Dla scraperów to przekłada się na konkretne oszczędności. Uruchomienie headless Chrome zużywa około 150–300 MB RAM na instancję, podczas gdy sesja HTTP zajmuje 5–15 MB. Jeśli 80% Twoich celów nie wymaga renderowania JS, DrissionPage pozwala trzymać przeglądarkę w rezerwie i eskalować tylko wtedy, gdy jest konieczna. To drastycznie obniża koszty infrastruktury i zwiększa przepustowość.
Ważne zastrzeżenie: ten przewodnik dotyczy wyłącznie publicznie dostępnych danych. Przestrzegaj robots.txt, warunków serwisu (ToS) oraz regulacji takich jak RODO (GDPR) i amerykańskiej CFAA. Jeśli strona oferuje oficjalne API, użyj go najpierw.
Model DrissionPage: SessionPage, ChromiumPage i WebPage
DrissionPage oferuje trzy główne klasy, z których każda odpowiada innemu zapotrzebowaniu na interakcję ze stroną.
SessionPage — tryb HTTP
SessionPage działa jak ulepszony requests.Session. Używa biblioteki urllib3 pod spodem, utrzymuje ciasteczka między żądaniami i obsługuje automatyczne dekodowanie treści. Idealny do pobierania statycznego HTML, plików JSON z ukrytych endpointów API oraz stron, które nie wymagają wykonania JavaScript.
from DrissionPage import SessionPage
page = SessionPage()
page.get('https://example.com/products')
title = page.ele('tag:h1').text
print(title)
ChromiumPage — kontrola przeglądarki przez CDP
ChromiumPage komunikuje się bezpośrednio z Chromium przez Chrome DevTools Protocol — bez Selenium, bez WebDriverBinaries. To oznacza szybsze uruchomienie, mniejszy narzut i dostęp do funkcji, których Selenium nie ujawnia: przechwytywanie ruchu sieciowego, wstrzykiwanie skryptów, blokowanie zasobów. Klasa drissionpage chromium jest szczególnie użyteczna dla stron SPA (React, Vue, Angular), gdzie treść ładuje się asynchronicznie.
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions().headless().set_argument('--disable-gpu')
page = ChromiumPage(co)
page.get('https://spa-example.com')
page.wait.eles_displayed('css:.product-card')
cards = page.eles('css:.product-card')
WebPage — płynne przełączanie trybów
WebPage to klasa, która dziedziczy po obu powyższych i pozwala przełączać się między trybem HTTP a trybem przeglądarki bez utraty ciasteczek ani sesji. To jest kluczowa wartość DrissionPage: jeden obiekt, jeden stan, dwa silniki.
from DrissionPage import WebPage
page = WebPage()
# Najpierw szybkie żądanie HTTP
page.get('https://example.com/login')
# Przełącz na tryb przeglądarki dla JS-heavy formularza
page.change_mode() # domyślnie przełącza na ChromiumPage
page.ele('#username').input('myuser')
page.ele('#password').input('mypass')
page.ele('#submit').click()
Dzięki temu nie musisz przenosić ciasteczek ręcznie między requests a Selenium. DrissionPage robi to automatycznie, współdzieląc obiekt sesji.
Idiomatyczne API DrissionPage: ele(), eles() i listen.start()
Lokatory ele() i eles()
DrissionPage używa własnej składni lokatorów, która jest bardziej zwięzła niż XPath czy CSS-selectory w czystej postaci. Podstawowa metoda ele() zwraca pierwszy pasujący element, eles() — listę wszystkich.
page.ele('tag:input')— element po nazwie tagu.page.ele('@class=submit-btn')— element po atrybucie (prefiks@).page.ele('xpath://div[@id="content"]')— pełny XPath, gdy potrzebujesz precyzji.page.ele('css:.product-list > li')— selektor CSS z prefiksemcss:.page.ele('text:Zaloguj się')— dopasowanie po tekście.
Możesz łączyć warunki: page.ele('tag:div@class=card@@text()=Premium') znajdzie div z klasą card, którego tekst to dokładnie „Premium".
ChromiumOptions — konfiguracja przeglądarki
ChromiumOptions to builder konfiguracji dla ChromiumPage. Pozwala ustawić ścieżkę do Chromium, argumenty wiersza poleceń, zmienne środowiskowe, a także proxy.
from DrissionPage import ChromiumOptions
co = ChromiumOptions()
co.set_browser_path('/usr/bin/chromium-browser')
co.headless(True)
co.set_argument('--no-sandbox')
co.set_argument('--disable-dev-shm-usage')
co.set_user_agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...')
co.set_proxy('http://gate.proxyhat.com:8080')
listen.start() — przechwytywanie ruchu XHR/JSON
Jedną z najpotężniejszych funkcji DrissionPage jest listen — wbudowany sniffer ruchu sieciowego na poziomie CDP. Zamiast analizować DOM po załadowaniu, możesz nasłuchiwać żądań XHR i odpowiedzi JSON, które strona wykonuje w tle.
from DrissionPage import ChromiumPage
page = ChromiumPage()
page.listen.start('api/products') # filtruj URL-e zawierające ten fragment
page.get('https://example.com/shop')
for packet in page.listen.steps(count=3):
print(packet.url)
data = packet.response.body # surowe JSON
print(data)
To eliminuje potrzebę parsowania HTML w wielu przypadkach — wystarczy przechwycić odpowiedź API, którą strona i tak pobiera. packet.response.body zwraca już zdekodowany JSON jako słownik Python.
Konfiguracja proxy w DrissionPage
Proxy dla SessionPage — set_proxies()
Tryb HTTP akceptuje standardowy słownik proxy, identyczny jak requests:
from DrissionPage import SessionPage
page = SessionPage()
page.set_proxies({
'http': 'http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080',
'https': 'http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080'
})
page.get('https://httpbin.org/ip')
print(page.ele('tag:pre').text)
Proxy dla ChromiumPage — ChromiumOptions.set_proxy()
Przeglądarka przyjmuje proxy przez ChromiumOptions. Chromium używa flagi --proxy-server pod maską, ale DrissionPage obsługuje to elegancko:
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions()
co.set_proxy('http://gate.proxyhat.com:8080')
page = ChromiumPage(co)
page.get('https://httpbin.org/ip')
Uwaga: proxy w Chromium jest ustawiane na poziomie procesu przeglądarki, nie pojedynczej karty. Jeśli potrzebujesz różnych IP dla różnych kart, uruchom osobne instancje ChromiumPage z różnymi ChromiumOptions.
Dlaczego proxy residential dla trudnych celów
Strony chronione przez Cloudflare, Akamai Bot Manager czy DataDome odrzucają ruch z zakresów IP datacenter z skutecznością sięgającą 90%+. Proxy residential kieruje ruch przez adresy IP przydzielone rzeczywistym dostawcom ISP, co sprawia, że żądanie wygląda jak pochodzące od zwykłego użytkownika domowego. Dla skrapowania SERP czy monitorowania cen e-commerce to często jedyna droga do stabilnych wyników.
Zobacz naszą listę lokalizacji proxy, aby sprawdzić dostępne kraje i miasta.
Przykład end-to-end: WebPage z proxy residential ProxyHat
Poniższy przykład pokazuje pełny potok: start w trybie HTTP przez amerykańskie proxy residential z sesją sticky, a następnie eskalację do trybu przeglądarki dla strony JS-renderowanej. Używamy ProxyHat do budowania nazwy użytkownika z flagami geo i sesji.
from DrissionPage import WebPage, ChromiumOptions
import json, time
# --- Konfiguracja ProxyHat ---
GATE = 'gate.proxyhat.com'
PORT = 8080
PASSWORD = 'twoje_haslo'
def build_username(country='US', session=None, city=None):
parts = [f'country-{country}']
if city:
parts.append(f'city-{city}')
if session:
parts.append(f'session-{session}')
return '-'.join(parts)
username = build_username(country='US', session='abc123')
proxy_url = f'http://{username}:{PASSWORD}@{GATE}:{PORT}'
# --- Krok 1: WebPage w trybie HTTP ---
page = WebPage(mode='session') # start jako SessionPage
page.set_proxies({
'http': proxy_url,
'https': proxy_url,
})
# Pobierz stronę logowania (statyczny HTML)
page.get('https://example.com/login')
csrf_token = page.ele('css:input[name="csrf_token"]').attr('value')
print(f'CSRF token: {csrf_token[:16]}...')
# Wyślij formularz logowania przez HTTP
page.post('https://example.com/api/login', json={
'username': 'myuser',
'password': 'mypass',
'csrf_token': csrf_token,
})
print('Zalogowano w trybie HTTP')
# --- Krok 2: Eskalacja do ChromiumPage ---
# Konfiguruj proxy dla przeglądarki z tą samą sesją
co = ChromiumOptions()
co.set_proxy(proxy_url)
co.headless(True)
co.set_argument('--disable-blink-features=AutomationControlled')
page.change_mode(co=co) # przełącz na tryb przeglądarki, zachowaj ciasteczka
# Nasłuchuj ukrytych wywołań API
page.listen.start('api/dashboard/data')
page.get('https://example.com/dashboard')
# Czekaj na pakiet JSON
packet = page.listen.wait(timeout=15)
if packet:
data = packet.response.body
print(json.dumps(data, indent=2, ensure_ascii=False)[:500])
else:
print('Brak pakietu — sprawdź filtr URL')
page.listen.stop()
Ten wzorzec — szybkie żądanie HTTP, następnie eskalacja do przeglądarki tylko gdy konieczne — jest rdzeniem efektywnego drissionpage web scraping. Sesja sticky (session-abc123) gwarantuje, że ten sam adres IP obsługuje całą sesję, co jest krytyczne dla utrzymania stanu logowania.
Wzorce produkcyjne
Przypinanie proxy do sesji (sticky sessions)
Każda sesja logowania powinna mieć własne, stałe IP. ProxyHat obsługuje to przez flagę session- w nazwie użytkownika. Generuj unikalny identyfikator sesji na instancję scrapera:
import uuid
session_id = uuid.uuid4().hex[:12]
username = f'user-country-US-session-{session_id}'
proxy_url = f'http://{username}:{PASSWORD}@{GATE}:{PORT}'
Dzięki temu każda sesja otrzymuje inny adres IP, ale ten IP pozostaje stały przez całą sesję. Zapobiega to sytuacji, w której serwer docelowy widzi logowanie z IP w Nowym Jorku, a następnie żądanie z IP w Los Angeles — co natychmiast wyzwala flagę bezpieczeństwa.
Retries z backoffem wykładniczym
Nawet z proxy residential, około 2–5% żądań kończy się błędem (timeout, 429, 503). Zawsze implementuj retry z wykładniczym backoffem:
import time, random
def fetch_with_retry(page, url, max_retries=5):
for attempt in range(max_retries):
try:
resp = page.get(url, timeout=20)
if resp.status_code == 200:
return resp
if resp.status_code in (429, 503):
wait = (2 ** attempt) + random.uniform(0, 1)
time.sleep(wait)
# Rotuj sesję proxy przy rate-limit
new_session = uuid.uuid4().hex[:12]
# ... odbuduj proxy_url z nową sesją ...
continue
return resp # inne błędy — nie retry
except Exception as e:
wait = (2 ** attempt) + random.uniform(0, 1)
time.sleep(wait)
raise Exception(f'Max retries exceeded for {url}')
Przechwytywanie pakietów — znajdowanie ukrytych API
Wielu dostawców e-commerce ładuje dane produktów przez wewnętrzne endpointy API, które nie są udokumentowane. listen.start() pozwala je odkryć:
- Załadować stronę w trybie przeglądarki.
- Nasłuchiwać wszystkich żądań XHR.
- Filtrować po typie treści
application/json. - Przeanalizować strukturę odpowiedzi.
- Przełączyć się z powrotem do trybu HTTP i odpytywać endpoint bezpośrednio — 10x szybciej, bez przeglądarki.
To podejście często pozwala zredukować liczbę żądań przez przeglądarkę do jednego (odkrycie API), a resztę wykonywać w trybie HTTP.
Limity współbieżności
DrissionPage nie ma wbudowanego zarządzania pulą współbieżności. Użyj concurrent.futures.ThreadPoolExecutor lub asyncio z własnym limitem:
| Wzorzec | Maks. współbieżność | Zalecane proxy |
|---|---|---|
| SessionPage (HTTP) | 50–100 wątków | Rotacja per-request |
| ChromiumPage (headless) | 5–10 instancji | Sticky session per instancja |
| WebPage (hybrydowy) | 10–20 wątków | Sticky session per wątek |
Każda instancja ChromiumPage zużywa 150–300 MB RAM. Na maszynie z 8 GB RAM bezpiecznie uruchomisz 5–6 instancji headless. Dla większej skali rozważ konteneryzację z Docker i orkiestrację przez Kubernetes.
Konteneryzacja — Docker + headless Chromium
FROM python:3.11-slim
RUN apt-get update && apt-get install -y \
chromium \
chromium-sandbox \
fonts-liberation \
&& rm -rf /var/lib/apt/lists/*
ENV CHROME_PATH=/usr/bin/chromium
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "scraper.py"]
W ChromiumOptions ustaw co.set_browser_path('/usr/bin/chromium') oraz dodaj --no-sandbox i --disable-dev-shm-usage, które są wymagane w kontenerach.
Kiedy NIE eskalować do przeglądarki
Najczęstszym błędem jest uruchamianie ChromiumPage „na wszelki wypadek". Zanim użyjesz przeglądarki, sprawdź:
- Czy treść jest w statycznym HTML? — Użyj
SessionPage. Sprawdź źródło strony (Ctrl+U); jeśli dane są w HTML, przeglądarka jest zbędna. - Czy istnieje ukryte API? — Sprawdź zakładkę Network w DevTools. Wiele stron ładuje dane przez JSON API, które możesz odpytać bezpośrednio.
- Czy strona wymaga logowania? — Zaloguj się w trybie HTTP (SessionPage), a przeglądarkę użyj tylko dla kroków wymagających JS (CAPTCHA, interaktywna mapa).
- Czy potrzebujesz tylko nagłówków/cookies? — Użyj
SessionPagez pełną kontrolą nagłówków.
Eskalacja do przeglądarki powinna być świadomą decyzją, nie domyślną. Każda sekunda spędzona w trybie Chromium kosztuje 10–20x więcej zasobów niż tryb HTTP.
Typowe błędy i przypadki brzegowe
1. Niezgodność ciasteczek między trybami
Podczas change_mode() DrissionPage automatycznie przenosi ciasteczka, ale tylko dla tej samej domeny. Jeśli logowanie odbywa się na auth.example.com, a dashboard na app.example.com, upewnij się, że ciasteczka są ustawione dla domeny nadrzędnej .example.com.
2. Proxy nie działa w ChromiumPage po change_mode
change_mode() tworzy nową instancję ChromiumPage. Musisz przekazać ChromiumOptions z ustawionym proxy w wywołaniu change_mode(co=co). Bez tego przeglądarka uruchomi się bez proxy.
3. listen.start() przechwytuje za dużo pakietów
Zawsze podawaj filtr URL w listen.start('fragment-url'). Bez filtra DrissionPage buforuje wszystkie żądania, co może doprowadzić do wyczerpania pamięci przy długich sesjach.
4. Timeout przy headless na serwerach bez GPU
Dodaj --disable-gpu i --disable-software-rasterizer na serwerach Linux bez GPU. Bez tych flag Chromium może wisieć na renderowaniu.
5. Rate limiting mimo proxy residential
Nawet residential IP może zostać oznaczony, jeśli wysyłasz 100 żądań/sekundę z tej samej sesji. Utrzymuj 1–3 żądania/sekundę na sesję i używaj wielu sesji równolegle. Zobacz nasz przewodnik po SERP tracking dla szczegółów.
Konfiguracja ProxyHat — szczegóły
ProxyHat oferuje proxy residential, mobile i datacenter. Dla DrissionPage zalecamy residential dla trudnych celów i datacenter dla prostych zadań HTTP. Konfiguracja jest identyczna — różnica polega na nazwie użytkownika.
Pełną dokumentację API ProxyHat znajdziesz na docs.proxyhat.com. Cennik dostępny jest na stronie /pl/pricing.
| Typ proxy | Gateway | Port | Format nazwy użytkownika |
|---|---|---|---|
| Residential HTTP | gate.proxyhat.com | 8080 | user-country-US-session-abc123 |
| Residential SOCKS5 | gate.proxyhat.com | 1080 | user-country-DE-city-berlin-session-def456 |
| Datacenter HTTP | gate.proxyhat.com | 8080 | user-country-GB |
SOCKS5 jest dostępny na porcie 1080 i jest użyteczny, gdy potrzebujesz tunelowania UDP lub gdy HTTP proxy jest blokowane przez sieć docelową.
Key Takeaways
- DrissionPage łączy HTTP i Chromium w jednym obiekcie —
WebPageprzełącza tryby bez utraty stanu, co obniża koszty o 80%+ vs. zawsze-przeglądarka. - Używaj SessionPage jako domyślnego trybu — eskaluj do ChromiumPage tylko gdy strona wymaga JS lub interakcji.
- Proxy residential jest konieczny dla celów chronionych anti-bot — datacenter IP jest blokowany w 90%+ przypadków przez Cloudflare/Akamai.
- Sticky sessions przez flagę
session-— przypisz unikalne IP do każdej sesji logowania, aby uniknąć flag bezpieczeństwa. listen.start()odkrywa ukryte API — przechwytuj JSON w tle, a następnie odpytuj endpointy w trybie HTTP.- Limit współbieżności — 50–100 wątków dla HTTP, 5–10 instancji dla Chromium na maszynie 8 GB RAM.
- Etyka przede wszystkim — przestrzegaj robots.txt, ToS, RODO/GDPR i CFAA. Preferuj oficjalne API, gdy dostępne.
Więcej wzorców skrapowania znajdziesz w naszym przewodniku po web scrapingu.






