Repository navigation
Stop on a refused proxy before starting a browser, and skip media behind a proxy - #24
Merged
Merged
Conversation
…ind a proxy The three browser engines send one HEAD for the start host's robots.txt through --proxy/--proxy-file before launching a local browser; a gateway 407 or 402 ends the run with exit 5 and stop_reason proxy_auth_failed in <out>.latest_attempt.meta.json, leaving the data and <out>.meta.json alone. Behind a local proxy they abort images, video/audio and web fonts (--load-media opts out); nothing changes over --cdp-endpoint or with no proxy. The canary's proxy preflight classifies 407/402 with the same code and wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A run through a paid residential proxy could start a whole browser on a proxy that refuses every request (a gateway
407or402), and then spend its retries and block-retries on that. Once a browser was running behind the proxy, it also downloaded every image, video and web font through the metered proxy, and no parser here reads any of them.What changes
Proxy pre-check (all three browser engines). Before launching a local browser behind
--proxy/--proxy-file,playwright_scraper.py,puppeteer_scraper.pyandselenium_scraper.pysend ONEHEAD https://<start host>/robots.txtthrough the proxy. The shared logic is inpage_flow.proxy_precheck, and the helpers are inproxy_pool.py.407: exit 5, with the messagethe gateway refused the credential (or the traffic balance is exhausted).402: exit 5, with the messageproxy traffic/balance exhausted.MEDIAMARKT_PROXYand never prints its value. The repo had no attempt sidecar, so a minimaloutput_writer.write_failed_attemptwas added. It writes only<out>.latest_attempt.meta.json(status: failed,stop_reason: proxy_auth_failed,data_updated: false), and the data and<out>.meta.jsonare left as they were. If even that file cannot be written, the run still exits 5 rather than crashing.--cdp-endpointor with no proxy.--proxy-file, the first exit of the pool is checked. The pre-check is one request and is never retried or rotated.Existing proxy check unified, not duplicated.
.github/canary_preflight.pyalready asked the canary's proxy for the page before the browser run. That request is unchanged. Its407handling now uses the same classification and wording as the engines (proxy_pool's status regex,PROXY_PRECHECK_STATUSESandprecheck_message). It also recognises a402, and a407/402answered to a plainhttp://request.Media blocking. With a local browser behind a proxy, images, media and fonts are aborted:
context.routebyresource_type, installed in_launch_local, so every relaunch and concurrency worker gets it.Fetch.enablewith resource-type patterns. This engine opens no other Fetch interception, because it authenticates withpage.authenticate.Network.setBlockedURLsby file extension, so an image served without an extension still loads. If the CDP command fails, the engine warns and loads the media.--load-mediaopts out. A hidden--force-block-mediaturns blocking on without a proxy, for measurement.<out>.meta.jsonrecordsmedia_blocked.env_config.ENV_KEYSmaps only credentials and URLs.Evidence
Offline suite,
python smoke_test.py:pytest -q,ci_checks.py --secret-checkandenv_config.pyare green, and every engine's--helpshows--load-mediaand hides--force-block-media.New
test_proxy_traffic_saverschecks use a local stub proxy that answers every request, CONNECT included, with a fixed status:407and402: exit 5 after exactly oneCONNECT www.mediamarkt.de:443. The message names the variable and does not print the credential. The attempt sidecar reads failed/proxy_auth_failed. Earlier.json/.csv/.meta.jsonfiles keep their bytes, and nothing else is written.scrape(), with its browser launch patched to raise, which shows the browser is never started.403, the browser does start. A proxy that cannot be reached is not treated as a failure.--cdp-endpoint.failRequeston a fake CDP session.should_block_mediaplus its blocker and recordsmedia_blocked.canary_preflight.pyrun against the stub for407/402overhttpsandhttp.The real CLIs against the stub proxy (
--proxy http://user:…@127.0.0.1:<stub>): Playwright, pyppeteer and Selenium each gave rc=5 for both 407 and 402. The stub saw one CONNECT, the secret did not appear in the output, and onlyr.latest_attempt.meta.jsonwas written.Each real engine session class (
_BrowserSession/_Session) was driven against a local page containing png/jpg/woff2/mp4/js:--force-block-media/and/app.jsonly, and the JS still ran/,/app.jsand the browser's own/favicon.ico/and/app.jsonlyLive comparison on 2026-10-20, Playwright, no proxy, one category page, with and without
--force-block-media: not possible. Both runs got MediaMarkt's403refusal page (exit 3) in about 0.25 s, the same datacentre refusal the README documents. Instead, the parser was read for anything that depends on loaded media.image_urlcomes from JSON-LD or from the tile'ssrc/data-srcattribute, and the asset-host block signal counts references in the markup. Nothing reads image bytes, dimensions or load events. Debug screenshots taken behind a proxy will show no images, and the README says so.Planted-fault controls, each restored afterwards and green again:
page_flow.proxy_precheckturns 15 checks red: the 407/402 checks and the per-engineexits 5 before a browser is started.selenium_scraper.scrapeturns 5 checks red, includingselenium_scraper: a proxy 407 exits 5 before a browser is started.playwright_media_routecontinue every request turnsmedia: playwright image/media/font -> abortred.context.routefrom_launch_localturnsmedia: playwright_scraper applies the policyred.media: puppeteer_scraper applies the policyred.No paid calls, no proxy and no credentials were used.
Not changed
HEADforrobots.txt(no body). The preflight's page request is what names a timeout or a dead tunnel, which the pre-check deliberately does not judge..github/ci_checks.py: the stub credentialsuser:S3cretPw@127.0.0.1andu:p@127.0.0.1were added to the secret scan's allowlist.🤖 Generated with Claude Code
https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8