Randomise browser fingerprint per context to evade bot detection
Add UA rotation (8 real Chrome UAs), random viewport, en-GB locale, Europe/London timezone, stealth browser args to suppress automation signals, and a per-context init script masking navigator.webdriver, plugins, and chrome runtime. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
83b46bee8f
commit
52455328e7
1 changed files with 47 additions and 7 deletions
|
|
@ -20,6 +20,7 @@ Rate plan variants per room type (typical):
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
@ -34,6 +35,34 @@ from services import proxy as proxy_util
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_USER_AGENTS = [
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
|
||||||
|
]
|
||||||
|
|
||||||
|
_VIEWPORTS = [
|
||||||
|
{'width': 1920, 'height': 1080},
|
||||||
|
{'width': 1366, 'height': 768},
|
||||||
|
{'width': 1440, 'height': 900},
|
||||||
|
{'width': 1536, 'height': 864},
|
||||||
|
{'width': 1280, 'height': 800},
|
||||||
|
{'width': 1600, 'height': 900},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Injected into every new context to mask headless/webdriver signals.
|
||||||
|
_STEALTH_SCRIPT = """
|
||||||
|
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
|
||||||
|
Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5]});
|
||||||
|
Object.defineProperty(navigator, 'languages', {get: () => ['en-GB', 'en']});
|
||||||
|
window.chrome = {runtime: {}};
|
||||||
|
"""
|
||||||
|
|
||||||
# JS that extracts all rate plan rows from the room availability table.
|
# JS that extracts all rate plan rows from the room availability table.
|
||||||
# Runs inside the page after the room table has loaded.
|
# Runs inside the page after the room table has loaded.
|
||||||
#
|
#
|
||||||
|
|
@ -179,7 +208,13 @@ class PlaywrightHotelPageBackend(ScraperBackend):
|
||||||
if not self._browser:
|
if not self._browser:
|
||||||
self._browser = await self._pw.chromium.launch(
|
self._browser = await self._pw.chromium.launch(
|
||||||
headless=True,
|
headless=True,
|
||||||
args=['--no-sandbox', '--disable-dev-shm-usage'],
|
args=[
|
||||||
|
'--no-sandbox',
|
||||||
|
'--disable-dev-shm-usage',
|
||||||
|
'--disable-blink-features=AutomationControlled',
|
||||||
|
'--disable-infobars',
|
||||||
|
'--disable-extensions',
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _get_context(self) -> BrowserContext:
|
async def _get_context(self) -> BrowserContext:
|
||||||
|
|
@ -191,16 +226,21 @@ class PlaywrightHotelPageBackend(ScraperBackend):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
session_id = uuid.uuid4().hex[:12] if self._proxy_enabled() else None
|
session_id = uuid.uuid4().hex[:12] if self._proxy_enabled() else None
|
||||||
|
ua = random.choice(_USER_AGENTS)
|
||||||
|
viewport = random.choice(_VIEWPORTS)
|
||||||
self._context = await self._browser.new_context(
|
self._context = await self._browser.new_context(
|
||||||
user_agent=(
|
user_agent=ua,
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
|
viewport=viewport,
|
||||||
'AppleWebKit/537.36 (KHTML, like Gecko) '
|
locale='en-GB',
|
||||||
'Chrome/125.0.0.0 Safari/537.36'
|
timezone_id='Europe/London',
|
||||||
),
|
|
||||||
**self._proxy_kwargs(session_id),
|
**self._proxy_kwargs(session_id),
|
||||||
)
|
)
|
||||||
|
await self._context.add_init_script(_STEALTH_SCRIPT)
|
||||||
self._requests_on_context = 0
|
self._requests_on_context = 0
|
||||||
logger.debug("Opened new browser context" + (f" (proxy session {session_id})" if session_id else ""))
|
logger.debug(
|
||||||
|
f"Opened new browser context ua=…{ua[-30:]} viewport={viewport['width']}x{viewport['height']}"
|
||||||
|
+ (f" proxy_session={session_id}" if session_id else "")
|
||||||
|
)
|
||||||
return self._context
|
return self._context
|
||||||
|
|
||||||
async def _rotate_context(self):
|
async def _rotate_context(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue