diff --git a/Dockerfile b/Dockerfile index f599772..50e8678 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,6 +42,7 @@ ENV PATH="/app/.venv/bin:$PATH" \ PYTHONDONTWRITEBYTECODE=1 \ # Tell undetected-chromedriver where Chrome lives CHROME_BINARY=/usr/bin/google-chrome-stable \ + CHROMEDRIVER_PATH=/app/drivers/chromedriver \ # Always run headless inside Docker HEADLESS=true @@ -51,7 +52,9 @@ COPY . . # Copy this after the application so a host venv can never replace it. COPY --from=builder /app/.venv /app/.venv -RUN mkdir -p data logs +# Download and patch the matching driver at build time. Runtime jobs must not +# depend on undetected-chromedriver's network downloader. +RUN PYTHONPATH=. python scripts/patch_driver.py && mkdir -p data logs # Non-root user for safety RUN useradd -m -u 1001 seed && chown -R seed:seed /app diff --git a/scripts/patch_driver.py b/scripts/patch_driver.py index 0a21454..0215ecd 100644 --- a/scripts/patch_driver.py +++ b/scripts/patch_driver.py @@ -22,6 +22,13 @@ from logger import get_logger log = get_logger(__name__) +_DOWNLOAD_HEADERS = { + "User-Agent": ( + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " + "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" + ) +} + def _get_chrome_full_version() -> tuple[int, str]: candidates = ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"] @@ -49,7 +56,8 @@ def _get_chrome_full_version() -> tuple[int, str]: def _latest_chromedriver_version(major: int) -> str: url = f"https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_{major}" try: - with urllib.request.urlopen(url, timeout=15) as resp: + request = urllib.request.Request(url, headers=_DOWNLOAD_HEADERS) + with urllib.request.urlopen(request, timeout=15) as resp: version = resp.read().decode().strip() log.info("Latest ChromeDriver for Chrome %d: %s", major, version) return version @@ -65,7 +73,8 @@ def _download_chromedriver(version: str, dest: Path) -> None: ) log.info("Downloading ChromeDriver %s …", version) try: - with urllib.request.urlopen(zip_url, timeout=60) as resp: + request = urllib.request.Request(zip_url, headers=_DOWNLOAD_HEADERS) + with urllib.request.urlopen(request, timeout=60) as resp: data = resp.read() except Exception as exc: log.critical("Download failed: %s", exc)