This is an old revision of the document!
Table of Contents
Provenance: programming:crawler
Working notes behind crawler — every query, its population and its denominator, the report script and its unedited output, the folds and their residue, the quotes that were checked, and what could not be established. Corpus-level caveats that apply to every page on this site are on corpus and are not restated here.
Partly reconstructed. The content page was written on 2026-08-06, before this site had a provenance convention. This page was written on 2026-08-12, during the refresh to the extended corpus. Sections marked recorded were produced by the 2026-08-12 run. Sections marked reconstructed were rebuilt afterwards from the report script, its output and the page text. The browser-automation sandbox measurements the content page reports (Selenium/Puppeteer/Playwright/CDP against a local fixture) were made by the original run and are not re-derivable from the corpus; they are reconstructed here from the page and the scripts in sandbox/, not re-measured.
1. What this page is backing
| Item | Value |
|---|---|
| Content page | crawler |
| Report script | scripts/report_crawler.mjs |
| Folds it depends on | scripts/tool_fold.mjs (framework families, browser families) |
| Quote verification | scripts/quote_check.mjs (new on 2026-08-12) |
| Runnable comparison | sandbox/fixture.mjs, sandbox/run_{playwright,puppeteer,cdp,selenium}.mjs, sandbox/compare.sh |
| Data | data/extract/run1/extractions.jsonl, 5,859 papers, 7 venues, 2010–2026 |
| Refreshed | 2026-08-12 |
2. Populations and denominators
Recorded. Two populations, and the page never mixes them without saying so.
| Tag | Definition | N |
|---|---|---|
crawled | crawlConfig !== null OR studyTypes contains automated-web-crawl | 1,120 |
all | every extracted paper — used only for the specialised-crawler mention table, where a tool can be used outside a formal crawl configuration | 5,859 |
crawled ∧ names a framework | ≥1 tools[] tuple with category ∈ {crawler-framework, browser-automation} and usedOrMentioned ∈ {used, produced} | 723 |
crawled ∧ names a browser | ≥1 non-sentinel crawlConfig.browsers entry | 529 |
crawled ∧ has a crawlConfig record at all | crawlConfig !== null | 1,080 |
used and produced both count as driving a crawl: a paper that built its own crawler crawled with it. compared and mentioned do not — that is related work, and it is why the specialised-crawler table has a separate “papers only mentioning” column.
3. Running it
cd /workspace/artifacts/wiki node scripts/report_crawler.mjs # every figure on the page node scripts/report_crawler.mjs --wiki # the same, as DokuWiki tables node scripts/quote_check.mjs --tools 'openwpm|playwright' --show 20 node scripts/check_page_numbers.mjs \ pages/programming_crawler.txt out/new/report_crawler.txt \ '===== Use in Publications =====' '===== Recommendations ====='
check_page_numbers.mjs left four figures unaccounted on 2026-08-12, all deliberate: 100 (“not against 100%”), 19.1 (the crawled share of the corpus, from data/extract/OVERVIEW.md), 53 (the old OpenWPM count, quoted on the page as history), and 93 — which was a stale number from an intermediate run of the quote check and was corrected to 106 before saving. That last one is the guard doing exactly the job it exists for.
4. What the refresh changed
Recorded. Old = 4,322-paper corpus (page as published 2026-08-06). New = 5,859-paper corpus.
| Figure | Old | New |
|---|---|---|
crawled | 859 | 1,120 |
| Names a framework | 544 (63.3%) | 723 (64.6%) |
| Names a browser | 395 (46.0%) | 529 (47.2%) |
| Names neither | 248 (28.9%) | 311 (27.8%) |
| Selenium | 187 (21.8%) | 242 (21.6%) |
| Bespoke, own name | 98 (11.4%) | 184 (16.4%) |
| Bespoke, generic | 130 (15.1%) | 147 (13.1%) |
| Bespoke, union | 221 (25.7%) | 321 (28.7%) |
| …of which named nothing else | 35 | 75 |
| Puppeteer | 54 (6.3%) | 76 (6.8%) |
| OpenWPM | 51 (5.9%) | 58 (5.2%) |
| Playwright | 10 (1.2%) | 34 (3.0%) |
| Direct CDP | 35 (4.1%) | 42 (3.8%) |
| Tracker Radar Collector (folded family) | 5 | 10 |
| Consent-interaction crawlers | 4 | 10 |
| Anti-detection patches | 5 | 9 |
| Chrome / Chromium (of browser-naming) | 225 (57.0%) | 304 (57.5%) |
| Names a library, not a browser | 23 (5.8%) | 49 (9.3%) |
| Safari / WebKit | 10 (2.5%) | 16 (3.0%) |
| Any tool states its version | 63 of 544 (11.6%) | 87 of 723 (12.0%) |
| Distinct tool strings / mentions | 378 / 789 | 501 / 1,075 |
| Unmapped residue | 104 strings / 106 mentions | 204 / 210 |
| Exact string “Selenium” vs folded | 147 vs 187 | 194 vs 242 |
| Artifact share, 2010–2013 → 2022–2024 | 23.6% → 62.1% | 21.6% → 61.2% |
| OpenWPM mentions (all papers) | 53 | 60 |
| Tracker Radar Collector (all papers) | 8 | 21 |
| SAP Project Foxhound (all papers) | 2 | 8 |
| Brave PageGraph (all papers) | 4 | 8 |
| webXray (all papers) | 6 | 7 |
| VisibleV8 (all papers) | 8 | 9 |
| PanoptiChrome (all papers) | 1 | 2 |
Moved by more than a rounding step, and why it matters:
- Playwright, 10 → 34 papers (1.2% → 3.0%), and in the provisional 2025–2026 bucket it overtakes Puppeteer (9.6% against 8.1%). This is the one clear reordering the extended corpus produced. The old page's flat statement “Playwright's first appearance in this corpus is 2022” stays true; the sentence after it was rewritten.
- Tracker Radar Collector 8 → 21 and Foxhound 2 → 8 in the all-papers mention table. The old page's closing sentence for that table already warned that “the 2024 boundary cuts them off mid-growth”. It did, and by a factor of two to four. The sentence was rewritten to say so rather than to warn about it.
- “Names a library, not a browser” 23 → 49, growing about twice as fast as the corpus. The new strings are the reason: 2025–2026 papers write “a Playwright-controlled browser”, “Playwright-derived browser”, “Puppeteer/TRC desktop browser”.
- Bespoke, own name 98 → 184. Corpus growth plus the same effect the README already documents: including
producedin the tool query surfaces one-off names. - Artifact share 23.6% → 21.6% for 2010–2013. A genuine change in the same window, from the newly retrieved IEEE S&P papers landing in the early buckets.
Not changed: the page's prose about how each library works, the sandbox comparison, the WebDriver BiDi section, the recommendations, and every citation.
5. Folds
5.1 Framework families — scripts/tool_fold.mjs
Reconstructed (design), recorded (this run's residue). An ordered list of regexes, specific tools before the generic libraries they wrap, so puppeteer-extra-plugin-stealth lands in Anti-detection patches and not in Puppeteer. Unmatched strings are not discarded: they become the Bespoke crawler, given its own name row, because almost every one of them is one paper's own tool.
Fold accounting for the current corpus (printed by report_crawler.mjs, section “Fold accounting and the artifact trend”, added 2026-08-12 precisely because these three figures were on the page and not in the report):
1075 tool mentions across 501 distinct strings in the 1120 crawling papers. Exact string "Selenium": 194 papers. Folded Selenium family: 242 papers (exact-string counting would undercount by 19.8%). Bespoke: 147 generic + 184 own-name, 10 in both, union 321 of 1120 (28.7%). Papers naming any of Puppeteer, Playwright, Chrome DevTools Protocol (direct), Scrapy, OpenWPM: 215.
The 204-string residue is printed in full at the end of out/new/report_crawler.txt. It is too long to reproduce here and it is genuinely one-name-per-paper; the interesting part is what is new in it, below.
5.2 Browser families — the fold that had gone stale
Recorded. On the 4,322-paper corpus the browser fold left 1 unmapped string (Ghostery). On the 5,859-paper corpus it left 15, and every new one was mappable:
| Residue string | Folded to | Rule added |
|---|---|---|
Playwright-controlled browser, Playwright browser, Playwright-derived browser | Names a library, not a browser | ^playwright (was ^playwright$) |
Puppeteer/TRC desktop browser, Puppeteer/TRC emulated mobile browser | Names a library, not a browser | ^puppeteer (was ^puppeteer$) |
basic HTTP fetcher | Names a library, not a browser | ^basic http fetcher$ |
Foxhound | Firefox | ^foxhound — Foxhound is a Firefox fork |
UC, 360, QQ browser, Xunlei, Instabridge | Other named browser | five anchored alternatives |
default Android browser | Mobile device or WebView | android browser |
local browser | Unnamed or custom browser | ''local '' added to the adjective list |
After the change the residue is back to 1 distinct string, Ghostery — which is an extension, not a browser, and is deliberately left unfolded so it stays visible.
That the residue grew from 1 to 15 without anything breaking is the general lesson: a fold silently ages against a growing corpus, and only a printed residue shows it. Interestingly, all five Chinese-browser strings came from one paper, which is why “Other named browser” stayed at 5 papers while five strings left the residue.
5.3 What is new in the framework residue, and what was deliberately not done with it
Recorded. The 2025–2026 slice introduced a cluster of one-off names that are not bespoke crawlers in the old sense but LLM-agent browser automation: Browser-Use / browser-use (two spellings, two papers), AgentLab, BrowserGym, MCP Server Crawler. A sixth paper, USENIX/2026/the-state-of-passkeys…, drives Playwright through Browser Use.
This was deliberately not folded into a family and not written up on the page. The refresh brief for this run is a mechanical re-derivation, and “does the field now drive browsers with LLM agents” is a new claim needing its own population, its own dating and its own reading of the papers — five or six papers in the thinnest, provisional years of the corpus is not enough to call it current practice. It is logged as a separate work item instead. Anyone picking it up should start from this residue list and from programming:crawler’s Being Detected section, since an agent-driven browser is a different detection surface.
A second, smaller cluster in the same residue: consent-automation tools used as instruments — autoconsent, DuckDuckGo autoconsent, Super Agent-Automatic Cookie Consent, ConsentChk. Those belong to consent rather than here.
6. Quotes checked
Recorded, 2026-08-12. scripts/quote_check.mjs is new; before it, this page's spot-check was done by hand and left no artefact, which is why the old figure (“66 quotes, 44 exact”) cannot be reproduced.
$ node scripts/quote_check.mjs --tools 'openwpm|playwright' --show 20 106 quotes checked: 58 exact, 32 partial (>=60% of 5-word windows), 16 below threshold, 0 with no full text on disk.
All 16 below-threshold quotes were then read by hand against paper.cols.txt with whitespace normalised. All sixteen are present in the paper. None was unsupported. Two representative failures:
PETS/2022/my-cookie-is-a-phoenix…— extraction has “All measurements are performed using the Open-WPM platform on the Firefox browser.”; the paper has “…using the Open-WPM platform [52] on the Firefox browser.” The extraction dropped the citation marker.CCS/2025/in-the-dom-we-trust…— extraction has “we created a Playwright-based crawler to collect snapshots of webpages”; the source reads “we created a Playwrightconstrains the valid child elements, and everything else is moved based [18] crawler to collect snap…”. The column repair spliced the adjacent column mid-word.
The lesson for anyone reusing evidence.quote: a failed exact match on .cols.txt is weak evidence of anything. Check the distinctive noun phrase, not the sentence.
7. External and industry sources
Reconstructed. The content page's tool claims are sourced to primary material and were verified on 2026-08-06 by the original run. Not re-verified on 2026-08-12 — the refresh touched no external claim — so the “checked 2026-08-06” dates on the page are accurate and should be re-checked before anyone leans on them again.
- OpenWPM: repository README,
docs/Configuration.md,scripts/install-firefox.sh, issues #557 and #503. - PageGraph:
pagegraph-crawlREADME and thebrave-browserwiki's own limitations list. - Tracker Radar Collector: repository README (concurrency cap, injected anti-detection script, autoconsent).
- PhantomJS:
ariya/phantomjs#15344, the maintainer's own suspension notice. - webXray: rejected the tool as installable.
api.github.com/repos/timlib/webXray→ 404,api.github.com/users/timlib/repos→ empty,pypi.org/pypi/webxray/json→ not found. The page cites the 2015 paper for the method and says plainly that the tool cannot be installed today. This is the clearest example on the site of an industry check changing what the page says. - Foxhound: its README's “Cite us!” section, which asks for the EuroS&P paper — a venue this corpus does not cover, which is itself the reason the page warns that a tool's paper count here is a lower bound.
Rejected: SEO listicles of “best web scraping tools” were rejected wholesale by the original run; none is cited.
8. What could not be established
- Whether Playwright has actually overtaken Puppeteer. It has in the 2025–2026 bucket, and that bucket is provisional. Two complete venue-years would settle it; they do not exist yet.
- Whether the anti-detection cohort is 9 or 12 papers. The folded framework family (crawling population,
used/produced) gives 9; the all-papers mention table gives 12 using and 2 more only mentioning. Both are on the page, in the two tables whose populations differ. They are not inconsistent, but a reader who reads only one table will get a different number, and there is no single right answer to publish. - Why 40 crawling papers have no
crawlConfigrecord. Same unresolved question as on crawling_location. - The original run's spot-check. “66 quotes, 44 exact” cannot be reproduced;
quote_check.mjsdid not exist. Replaced rather than corrected. - The sandbox measurements were not re-run. The Selenium/Puppeteer/Playwright/CDP comparison, the WebDriver BiDi
responseCompletedfinding and the “two network handlers cross-deliver” bug are from 2026-08-06 againstselenium-webdriver4.46. Library versions have moved since. Nothing in this refresh touched them, and nothing in this refresh verified them.
9. Run log
| Date | 2026-08-12 |
| Corpus at the time | data/extract/run1, 5,859 papers, 2010–2026, IEEE S&P complete at 780/780 |
| Model | Claude Opus 5, no sub-agents used for this page |
| Scope | Mechanical re-derivation. Prose, structure and method selection were not revisited, with two exceptions, both forced by the numbers: the “Playwright overtakes Puppeteer” sentence, and the specialised-crawler table's closing paragraph, whose old text warned of an effect the new data measures. |
| Script changes | lib.mjs (YEAR_BUCKETS gained a starred 2025–2026 bucket), tool_fold.mjs (browser families extended, §5.2), report_crawler.mjs (new “Fold accounting and the artifact trend” section printing figures the page carried but the report did not), quote_check.mjs (new) |
| Caveats deleted | “IEEE S&P is only 43% retrieved (paywall)” — 780 of 780 selected papers are now retrieved. “2010–2024”. |
| Claim weakened on purpose | The old page said the bespoke rows together were “more than used every off-the-shelf library on this page combined”. That was not true of the old numbers either (187+54+35+10 = 286 > 221) and is not true of the new ones. Replaced with the two comparisons the report actually prints: more than Selenium (242), and more than the 215 papers naming any of Puppeteer, Playwright, direct CDP, Scrapy or OpenWPM. |
| Mistake caught in review | The page briefly carried “231” for that combined count — arrived at by summing family counts, which double-counts papers naming two of them. The real union is 215. check_page_numbers.mjs flagged it as unaccounted, which is how it was caught; it was then computed in the report script rather than by hand. |
| Deferred | LLM-agent browser automation in the 2025–2026 residue (§5.3), logged as a separate work item. |
