Repository navigation
python3 env_config.pyprinted the dashboard-form proxy whole. With
AVITO_PROXYwritten ashost:port:login:password— the form 1.1.1 began
accepting — the report that promises "without printing secrets" printed
the login and password. If you ran it with that form and shared the
output, change the proxy password. Found in a manual test, 2026-10-19.What changes for a scheduler or a script. A run that gathered rows and
then lost its connection now exits 6 with those rows written (it was
5 with nothing written).<out>.latest_attempt.meta.jsonnow carries
exit_codeon every ending (it was null except on a transport failure).
diff_runs.pyrefuses two runs capped differently by--max-products
(exit 2).tools/browser_profile_client.py accountsprints one row per
account with anaccount idcolumn instead of every object with an id. A
connect answeredprofile_lockedis retried for up to 30 s before exit 5.
Fixed
env_config.pyhid a value only when it contained@. Credentials
are now hidden by variable name (TWOCAPTCHA_KEY,AVITO_CDP_ENDPOINT,
AVITO_PROXY); for the proxy the report keeps the exit's host and port.- The attempt sidecar's
exit_codewas null on every normal ending.
<out>.latest_attempt.meta.jsonis documented to carry it on every
ending; only a transport failure set it. A complete run, a block (3), an
empty listing (4), a page that failed (5) and a partial run (6) now record
it too. diff_runs.pycompared a full run with one capped by--max-products,
reporting every row the capped run never fetched as removed ("127
removed", 2026-10-19). It now refuses, like a different page count;
--forcestill compares.tools/browser_profile_client.py accountslisted every object with an
id — each account's project (id 1, once per account), proxy account and
default profile — so the number to pass as--account-idwas one row of
21, unmarked. It now prints one row per account with anaccount id
column; passing a profile id is what producedERROR_ACCOUNT_NOT_FOUND.- The proof-of-work log said "cleared" for a page still loading, and a
run's stop line quoted the first response's status as if it were the
final page's. The log now says when the next page is not recognisable
yet, and the stop line labels the status "first response". - A dropped connection after gathered pages threw the pages away. Page 1
gave 50 rows over the Scraping Browser, page 2 died with
ERR_CONNECTION_RESET, and the run exited 5 withproducts: 0and no file
(2026-10-20). Rows gathered and then a transport failure is now a partial
run: exit 6, the rows written, the failed page named. A failure before any
row is still exit 5. profile_lockedright after another run exited 5. A run started just
after another on the same Scraping Browser profile was refused; 30 s later
it passed. That one answer is now retried 3 times, 10 s apart
(page_flow.PROFILE_LOCKED_*); a timeout orproxy_erroris not.- pyppeteer reported a Scraping Browser refusal as a bare
TimeoutError.
It never surfaces the service's answer; the message now says so, names the
likely causes and points to Playwright for the reason. - The canary died on one dropped run. Its endpoint step is the shipped
tools/browser_profile_client.py canary-envinstead of 30 lines of Python
inside the workflow, and a live run that exits 5 is retried once on a
freshly minted session (a block or no rows is not retried). - A captcha that appeared after the proof-of-work was never solved. When
the proof-of-work went, the page in between was not recognisable, and the
captcha arrived during the next wait, the solve rung had already been
passed: the run rotated to a fresh exit instead (twice in three exits,
manual test 2026-10-19). The wall rungs now run once more after that wait. diff_runs.py's refusal advised "re-run the incomplete side" for every
reason, including two complete runs capped differently. The advice now
follows each reason (same--max-products, same listing and--pages,
same--mode, …).- Wording: "not a item page" → "not an item page"; the hint for a proxy
without a login names both gateway hosts (.proxy.2captcha.comand
.proxy.rucaptcha.com), not only the first. .gitignorecovered--dump-htmlcaptures by extension (.html,
.txt,.htm);--dump-html snap.datleftsnap_p1.datunignored. It
now matches the_p<N>.<ext>shape.- The secret scan exempted
smoke_test.pyentirely. It now reads it;
the suite's own credential-shaped samples are assembled from pieces. - The suite's private-citation check walked ignored files, so a
contributor's own notes excluded through.git/info/excludekept it red.
In a git checkout it now reads only what git could commit.
Changed
- README, GeeTest: the "3 of 3 verified" table now carries the later
measurements — local-browser solves refused 0 of 15 (2026-10-14 to 10-20), a
control in whichGeeTestTaskreturned solutions for an unreachable
proxy, and 11 Scraping Browser runs that met no wall (2026-10-19) — and
says to use the Scraping Browser. - CONTRIBUTING: a captcha solve is sent with the browser's exit (what
the code does and a test pins), not "goes through" it (what 2Captcha did
not do, measured); exit 6 covers a transport fault after rows were
gathered. - README:
--mode sellerreads all of a seller's listings through the
feed, and exit 6 there means fewer listings than the profile's counter;
diff_runs's "removed" means "not in these pages any more", not
"delisted".