Repository navigation
Treat a 403 refusal as a block, keep output file modes, validate numeric flags - #8
Merged
Merged
Conversation
- Playwright and pyppeteer pass the navigation's HTTP status to the page classifier, so Rakuten's branded refusal under 403 is a block while the same page under 503 is still waited out as a throttle. Selenium passes None explicitly (WebDriver exposes no status). - pyppeteer no longer crashes with AttributeError on repeated load failures when no proxy pool is configured. - Output files get 0666 minus the umask, and an existing file keeps its mode, instead of always 0600. - Both captcha call sites count attempted purchases against the per-page allowance; the static detector recognises a bare g-recaptcha container or api2/anchor frame. - --pages/--concurrency >= 1 and non-negative delays and block retries are argparse errors in every engine; scraper_api_client validates its own. - --solve-captcha help and exit-code comments describe Rakuten's refusals. - Comments no longer cite private section numbers; a suite guard keeps them out, and the wording scan covers the suite itself. - The canary fails on every non-zero exit, not only on defects. - .gitignore covers page dumps past .page99; one sample-output check in CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jehrr
marked this pull request as ready for review
October 15, 2026 13:53
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.
Fixes from the 2026-10-14 audit of
61212f3(no open PRs at the start, main unchanged since the audit).What changes for a user
goto()'s status into every classify call, and reset it to None after a solve reloads the page. Selenium passesNoneexplicitly because WebDriver exposes no status, so it keeps the documented recoverable reading.puppeteer_scraper.pycalledpool.advance()on a repeated load failure withpool=Noneand raisedAttributeError. It now rotates only for an unusable exit and only when there is a pool, matching Playwright and Selenium..json,.csvand.meta.jsonwere always 0600. A new file is now0666 & ~umask, and a rewrite keeps the existing file's mode.purchaseslist right before calling the solver, so a page with no captcha spends nothing.class="g-recaptcha"+data-sitekey, or only theapi2/anchorframe, was reported as having no captcha. It now yields a v2 (or v2-invisible) challenge. It fires on none of the 14 committed captures.--pages/--concurrencymust be ≥ 1, and--delay/--retry-delay/--proxy-block-retriesmust be ≥ 0. Anything else is an argparse error naming the flag, in all three engines.scraper_api_client.pyvalidates--retries≥ 0,--retry-delay≥ 0 and--timeout≥ 1.--solve-captchahelp in all three engines (an "HTTP/2 stream reset"), theEXIT_BLOCKEDcomment (a different site's hubs and no-results text), and the "394-byte Access Denied / headless" comments in the engines andcaptcha_solver.pyare rewritten for Rakuten's measured refusals: a 43-byte deny under 200, a branded page under 403, and the same page under 503. I also dropped thekeyword=kopidocstring example and reattached theEXIT_PARTIALcomment to its constant.§Nreference (139 lines) and bothCLAUDE.mdmentions in tracked files were removed or restated in the repo's own words. CHANGELOG and release notes v0.1.0/v0.2.0/v0.2.1 had none, so no release was edited. A new suite check scans every tracked text file (site-data fixtures excepted) for section-sign citations and for private-note names. The tokens are assembled from pieces, so the suite file is scanned too.tested=false. Now every non-zero exit is red. The exit-5 message now says "content never obtained, diagnose the transport" instead of "impossible". The job stays scheduled, uncredentialled and ungated. The last 10 scheduled runs really parsed 3×45 rows (2026-10-15 log:Parsed 45 row(s)per page, thencanary OK). Thresholds are unchanged and test the parser: row floor, price coverage, JPY, points, shop_code, page+position uniqueness, rating sentinel..gitignoreused*.page[0-9]/*.page[0-9][0-9], which stopped at.page99; it now uses*.page[0-9]*.requirements-selenium.txtpointed to a nonexistent--chromedriverflag..env.exampleno longer says that Scraping Browser credentials "live about a day".tests.ymldropped its inline duplicate ofci_checks.py --sample-check.BANNED_PHRASESis assembled from pieces, sosmoke_test.pyis no longer exempt from the wording scan.Evidence
browser engines' fetch loop, driven offline with a fake pagegroup loads each browser engine, using a stub driver module when the library is absent, and drives_fetch_one_page. It checks four things:load_failedinstead of raising;block_403fixture under status 403 endsblocked;throttledafter1 + THROTTLE_RETRIESfetches;SOLVES_PER_PAGEtimes.classifycall in every engine passes a status.ci_checks.py --secret-check --help-check --sample-check: ok, 43 files scanned.Controls
All controls ran with
PYTHONDONTWRITEBYTECODE=1and__pycache__removed. In each one I planted the fault, saw the suite go red on the named check, restored it, and saw the suite go green.chmodremoveda new output file is 0666 minus the umaskpuppeteer_scraper: repeated load failures with no proxy pool …(AttributeError)playwright_scraper: the branded page under HTTP 403 …puppeteer_scraper: the branded page under HTTP 403 …a failing solver is asked at most …(2 calls)the static detector finds a v2 widget …§17planted in page_flow.pyno tracked file cites private notes ….gitignorepage patterngit also ignores canary.json.page100--pages type=intselenium_scraper validates its numeric flags …every classify call passes a statusexit 3 is treated as failno shipped file says …No live request, paid call, proxy or credential was used.
Not changed
not_foundstate for a 404 in--mode product. The audit only suggested it as something to consider. A 404 page still classifies as before. Adding it would be a new state, a new stop reason and changed exit codes, so it is left for a separate change.[Unreleased]now carries these behaviour changes on top of Reject --retries 0 instead of fetching nothing #7..env.example'sRAKUTEN_URLstays active. This repo has no URL-builder flags (--categoryis a label only), so an env URL cannot hijack anything. The existing round-trip check asserts that it stays usable.🤖 Generated with Claude Code