Session Pools + Proxy Rotation + Fingerprint Rotation — Multi-Session Scraping #115

Open
opened 2026-06-19 20:55:56 +00:00 by Artur · 0 comments
Owner

Problembeschreibung

Für Scraping mit Proxy-Rotation und großvolumigen Crawls brauchen wir:

  1. Session Pools — Isolierte Cookie-Jars + localStorage pro Session (für Multi-Account-Scraping)
  2. Proxy Rotation — Automatischer Proxy-Wechsel bei Rate-Limiting/Blocking
  3. Browser Fingerprint Rotation — Unterschiedliche User-Agent + Header pro Request

Aktuell: Ein Page = eine Session. Kein Pooling, keine Rotation.

Architektur

flowchart TD
    A[SessionPool] --> B[Session A\nCookies: user1\nProxy: 1.2.3.4\nUA: Chrome 134]
    A --> C[Session B\nCookies: user2\nProxy: 5.6.7.8\nUA: Chrome 135]
    A --> D[Session C\nCookies: user3\nProxy: 9.10.11.12\nUA: Firefox 136]
    
    E[BatchCrawler] --> A
    E --> F[Queue: 10,000 URLs]
    F --> G[Worker 1 → Session A]
    F --> H[Worker 2 → Session B]
    F --> I[Worker 3 → Session C]
    
    G --> J[(Results DB)]
    H --> J
    I --> J

Option A: SessionPool als eigenständige Klasse

class SessionPool {
  constructor(options: {
    size: number;           // Pool-Größe (default: 5)
    browserFingerprints?: BrowserFingerprint[];
    proxyList?: string[];   // Rotierende Proxies
    cookieIsolation?: boolean; // Getrennte Cookie-Jars
  });

  acquire(): Promise<Page>;  // Blockiert bis Page verfügbar
  release(page: Page): void; // Gibt Page zurück in Pool
  rotateProxy(page: Page): void; // Wechselt Proxy für Session
}

Option B: Session mit Proxy-Rotation

class ProxyRotator {
  constructor(proxyList: string[]);
  next(): string;  // Nächsten Proxy holen (round-robin)
  markBad(proxy: string): void;  // Bei Fehler markieren
  markGood(proxy: string): void; // Bei Erfolg markieren
}

Option C: Browser Fingerprint Pool

interface BrowserFingerprint {
  userAgent: string;
  acceptLanguage: string;
  viewport: { width: number; height: number };
  platform: string;
  vendor: string;
  webGLVendor?: string;
  webGLRenderer?: string;
}

Akzeptanzkriterien (Phase 1 — SessionPool)

  • SessionPool Klasse mit acquire() / release()
  • Pool konfigurierbare Größe (default: 5)
  • Cookie-Isolation: Jede Page hat eigenen CookieJar
  • acquire() blockiert wenn alle Pages belegt
  • release() gibt Page zurück, resettet CookieJar nicht
  • Timeout: acquire(5000) wirft Error wenn kein Page frei
  • Test: Pool von 3 Pages → 3 acquires → 4th wirft Timeout
  • Test: release → acquire funktioniert wieder
  • Test: Cookie-Isolation (Cookie A nicht in Page B sichtbar)

Akzeptanzkriterien (Phase 2 — Proxy Rotation)

  • ProxyRotator Klasse
  • Round-Robin: next() gibt nächsten Proxy
  • markBad(proxy) → proxy wird für N Sekunden gesperrt
  • markGood(proxy) → proxy wird bevorzugt
  • PageOptions.proxyPool akzeptiert ProxyRotator
  • Proxy-Wechsel bei HTTP 429/503
  • Test: Round-Robin liefert zyklisch
  • Test: Bad Proxy wird gesperrt
  • Test: Good Proxy wird bevorzugt
  • Test: Proxy-Wechsel bei 429

Akzeptanzkriterien (Phase 3 — Fingerprint Rotation)

  • BrowserFingerprint[] in SessionPool
  • Unterschiedliche User-Agent pro Session
  • Unterschiedliche Accept-Language pro Session
  • Unterschiedliche Viewport-Größe
  • Test: 3 Sessions haben 3 verschiedene Fingerprints
  • Test: Fingerprints sind realistisch (keine Dummy-Werte)

Betroffene Dateien

Datei Änderung Aufwand
src/session/pool.ts Neu: SessionPool Klasse ~200 Zeilen
src/session/proxy-rotator.ts Neu: ProxyRotator Klasse ~100 Zeilen
src/session/fingerprints.ts Neu: BrowserFingerprint Pool ~100 Zeilen
src/pages/page.ts Proxy-Wechsel, Fingerprint-Setup ~50 Zeilen
src/runtime-isolation.ts Fingerprint-Config durchreichen ~20 Zeilen
tests/unit/session-pool.test.ts Neu: 20 Tests ~400 Zeilen

Testplan (25 Tests)

# Test Phase
SP01 Pool erstellt N Pages 1
SP02 acquire liefert Page 1
SP03 release gibt Page zurück 1
SP04 acquire blockiert bei vollem Pool 1
SP05 acquire Timeout 1
SP06 Cookie-Isolation zwischen Sessions 1
SP07 Pool-Größe konfigurierbar 1
SP08 Multiple Acquire/Release Zyklen 1
PR01 Round-Robin Proxy Rotation 2
PR02 markBad sperrt Proxy temporär 2
PR03 markGood erhöht Priority 2
PR04 Auto-Rotation bei 429 2
PR05 Auto-Rotation bei 503 2
PR06 Proxy-Liste leer → kein Proxy 2
PR07 Concurrent Proxy-Nutzung 2
FP01 Unterschiedliche UA pro Session 3
FP02 Unterschiedliche Accept-Language 3
FP03 Unterschiedliche Viewport-Größe 3
FP04 Fingerprints sind realistisch 3
FP05 Fingerprints wechseln bei Proxy-Rotation 3

Dependencies

  • Keine externen Dependencies

Performance Impact

SessionPool selbst: ~2ms overhead pro acquire/release.
Proxy Routing: ~0.1ms overhead pro Request.

Risks

Risk Impact Mitigation
Proxy-Liste leer → kein Fallback Hoch Fallback zu direct connection
Session leak (Page nicht released) Mittel WeakRef + FinalizationRegistry
Cookie-Kontamination Hoch Strict isolation via CookieJar.load/save
Zu viele Sessions = OOM Mittel Hard cap bei pool.maxSize
## Problembeschreibung Für Scraping mit Proxy-Rotation und großvolumigen Crawls brauchen wir: 1. **Session Pools** — Isolierte Cookie-Jars + localStorage pro Session (für Multi-Account-Scraping) 2. **Proxy Rotation** — Automatischer Proxy-Wechsel bei Rate-Limiting/Blocking 3. **Browser Fingerprint Rotation** — Unterschiedliche User-Agent + Header pro Request Aktuell: Ein Page = eine Session. Kein Pooling, keine Rotation. ### Architektur ```mermaid flowchart TD A[SessionPool] --> B[Session A\nCookies: user1\nProxy: 1.2.3.4\nUA: Chrome 134] A --> C[Session B\nCookies: user2\nProxy: 5.6.7.8\nUA: Chrome 135] A --> D[Session C\nCookies: user3\nProxy: 9.10.11.12\nUA: Firefox 136] E[BatchCrawler] --> A E --> F[Queue: 10,000 URLs] F --> G[Worker 1 → Session A] F --> H[Worker 2 → Session B] F --> I[Worker 3 → Session C] G --> J[(Results DB)] H --> J I --> J ``` ### Option A: SessionPool als eigenständige Klasse ```ts class SessionPool { constructor(options: { size: number; // Pool-Größe (default: 5) browserFingerprints?: BrowserFingerprint[]; proxyList?: string[]; // Rotierende Proxies cookieIsolation?: boolean; // Getrennte Cookie-Jars }); acquire(): Promise<Page>; // Blockiert bis Page verfügbar release(page: Page): void; // Gibt Page zurück in Pool rotateProxy(page: Page): void; // Wechselt Proxy für Session } ``` ### Option B: Session mit Proxy-Rotation ```ts class ProxyRotator { constructor(proxyList: string[]); next(): string; // Nächsten Proxy holen (round-robin) markBad(proxy: string): void; // Bei Fehler markieren markGood(proxy: string): void; // Bei Erfolg markieren } ``` ### Option C: Browser Fingerprint Pool ```ts interface BrowserFingerprint { userAgent: string; acceptLanguage: string; viewport: { width: number; height: number }; platform: string; vendor: string; webGLVendor?: string; webGLRenderer?: string; } ``` ## Akzeptanzkriterien (Phase 1 — SessionPool) - [ ] `SessionPool` Klasse mit `acquire()` / `release()` - [ ] Pool konfigurierbare Größe (default: 5) - [ ] Cookie-Isolation: Jede Page hat eigenen CookieJar - [ ] `acquire()` blockiert wenn alle Pages belegt - [ ] `release()` gibt Page zurück, resettet CookieJar nicht - [ ] Timeout: `acquire(5000)` wirft Error wenn kein Page frei - [ ] Test: Pool von 3 Pages → 3 acquires → 4th wirft Timeout - [ ] Test: release → acquire funktioniert wieder - [ ] Test: Cookie-Isolation (Cookie A nicht in Page B sichtbar) ## Akzeptanzkriterien (Phase 2 — Proxy Rotation) - [ ] `ProxyRotator` Klasse - [ ] Round-Robin: `next()` gibt nächsten Proxy - [ ] `markBad(proxy)` → proxy wird für N Sekunden gesperrt - [ ] `markGood(proxy)` → proxy wird bevorzugt - [ ] `PageOptions.proxyPool` akzeptiert ProxyRotator - [ ] Proxy-Wechsel bei HTTP 429/503 - [ ] Test: Round-Robin liefert zyklisch - [ ] Test: Bad Proxy wird gesperrt - [ ] Test: Good Proxy wird bevorzugt - [ ] Test: Proxy-Wechsel bei 429 ## Akzeptanzkriterien (Phase 3 — Fingerprint Rotation) - [ ] `BrowserFingerprint[]` in SessionPool - [ ] Unterschiedliche User-Agent pro Session - [ ] Unterschiedliche `Accept-Language` pro Session - [ ] Unterschiedliche Viewport-Größe - [ ] Test: 3 Sessions haben 3 verschiedene Fingerprints - [ ] Test: Fingerprints sind realistisch (keine Dummy-Werte) ## Betroffene Dateien | Datei | Änderung | Aufwand | |---|---|---| | `src/session/pool.ts` | Neu: SessionPool Klasse | ~200 Zeilen | | `src/session/proxy-rotator.ts` | Neu: ProxyRotator Klasse | ~100 Zeilen | | `src/session/fingerprints.ts` | Neu: BrowserFingerprint Pool | ~100 Zeilen | | `src/pages/page.ts` | Proxy-Wechsel, Fingerprint-Setup | ~50 Zeilen | | `src/runtime-isolation.ts` | Fingerprint-Config durchreichen | ~20 Zeilen | | `tests/unit/session-pool.test.ts` | Neu: 20 Tests | ~400 Zeilen | ## Testplan (25 Tests) | # | Test | Phase | |---|---|---| | SP01 | Pool erstellt N Pages | 1 | | SP02 | acquire liefert Page | 1 | | SP03 | release gibt Page zurück | 1 | | SP04 | acquire blockiert bei vollem Pool | 1 | | SP05 | acquire Timeout | 1 | | SP06 | Cookie-Isolation zwischen Sessions | 1 | | SP07 | Pool-Größe konfigurierbar | 1 | | SP08 | Multiple Acquire/Release Zyklen | 1 | | PR01 | Round-Robin Proxy Rotation | 2 | | PR02 | `markBad` sperrt Proxy temporär | 2 | | PR03 | `markGood` erhöht Priority | 2 | | PR04 | Auto-Rotation bei 429 | 2 | | PR05 | Auto-Rotation bei 503 | 2 | | PR06 | Proxy-Liste leer → kein Proxy | 2 | | PR07 | Concurrent Proxy-Nutzung | 2 | | FP01 | Unterschiedliche UA pro Session | 3 | | FP02 | Unterschiedliche Accept-Language | 3 | | FP03 | Unterschiedliche Viewport-Größe | 3 | | FP04 | Fingerprints sind realistisch | 3 | | FP05 | Fingerprints wechseln bei Proxy-Rotation | 3 | ## Dependencies - **Keine externen Dependencies** ## Performance Impact SessionPool selbst: ~2ms overhead pro acquire/release. Proxy Routing: ~0.1ms overhead pro Request. ## Risks | Risk | Impact | Mitigation | |---|---|---| | Proxy-Liste leer → kein Fallback | Hoch | Fallback zu direct connection | | Session leak (Page nicht released) | Mittel | WeakRef + FinalizationRegistry | | Cookie-Kontamination | Hoch | Strict isolation via CookieJar.load/save | | Zu viele Sessions = OOM | Mittel | Hard cap bei pool.maxSize |
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
glow-all/true-headless-browser#115
No description provided.