Web Scraping

SkillWeb & browsing

Use when "scrape this site at scale", "fetch N thousand pages", "how many workers should this scraper use", "am I hammering this server", "we're getting 429s / blocked / CAPTCHAs", "should we use a proxy", "Zyte", "ScrapingBee", "Web Unlocker", "residential proxy", "rotate proxies", "scrape with Web Unlocker", "query Bright Data", "Bright Data datasets", "Bright Data Web Archive / Wayback alternative", "FINRA BrokerCheck data", "SEC IAPD / adviserinfo data", "Investment Adviser Public Disclosure", "broker/adviser disclosure snapshots", "LinkedIn/Crunchbase/Glassdoor company or people dataset", or any use of the Bright Data API (datasets/list, Web Archive search/dump, Web Unlocker zones).

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Web Scraping skill

What this skill tells your AI

The instructions your AI receives, as published by edwinhu/workflows in skills/web-scraping/SKILL.md and read by ahel’s review.

What this skill carries — grep references/ for any subject the names below miss: !d=${CLAUDE_SKILL_DIR}; command -v skill-toc >/dev/null 2>&1 && exec skill-toc "$d"; s=$HOME/.claude/skills/plugin-utils/bin/skill-toc; [ -x "$s" ] && exec "$s" "$d"; echo "(skill-toc unavailable: references and scripts are NOT listed here — install the plugin-utils plugin, or start a new session so its bin/ reaches PATH)"

Bulk fetching from hosts you do not own: how fast you may go, when a paid transport beats a direct fetch, and how to prove the fallback you are relying on has ever run.

Contents

  • Iron Law: the rate is computed, not chosen
  • Quota vs rate limit
  • Verify the fallback before you rely on it
  • Direct fetch or paid transport
  • Vendor table
  • Facts
  • Red flags — STOP
  • References

Iron Law: the rate is computed, not chosen

workers / sleep_seconds is the policy. A worker count with no arithmetic beside it is not a tuning decision — it is an unreviewed multiplication of load on somebody else's server, usually from an IP the institution owns and cannot swap. Raising 1 worker to 8 to "help the run finish faster" is not helpful if it is the run that gets the university's address throttled: the user then loses the whole corpus, not the hours you saved.

# ceiling: SEC EDGAR publishes 10 req/s and requires a declared User-Agent
# https://www.sec.gov/search-filings/edgar-search-assistance/accessing-edgar-data (read 2026-09-08)
WORKERS, SLEEP_SECONDS = 8, 1.0
EFFECTIVE_RPS = WORKERS / SLEEP_SECONDS          # 8.0 req/s = 80% of the documented ceiling
assert EFFECTIVE_RPS <= 10.0

No published ceiling → say so with the URL and the date you looked, and hold at 1 req/s. "Not documented" is not "unlimited".

Quota vs rate limit

Name which one the target enforces, in a comment next to the worker count. The two have opposite corrections, so a client that has not named one has guessed.

capsmore workers →
Rate limitrequests per unit timehits the cap sooner per second; total budget untouched, throttled requests retry, job still completes
Quotatotal requests per IP/key per perioddoes not reduce total requests — only exhausts the budget sooner

Under a quota, parallelising buys nothing on the binding constraint and brings the wall forward. Under a rate limit, parallelising up to the ceiling is exactly right.

A fact recorded in a module docstring but never connected to the worker count is a fact nobody applied. Put it where the decision is.

Verify the fallback before you rely on it

A declared fallback transport — proxy, unblocker, mirror, secondary API — is unverified until it has executed. Count it; do not read about it.

xan frequency -s transport data/output/manifest.csv
# direct,1538
# proxy,0        <- documented as required; has never once run

Zero uses forces one of three, stated explicitly:

  1. Exercise it — force the fallback on a 5–10 row test, record the result, keep the dependency.
  2. Downgrade the claim — mark it UNVERIFIED — 0 executions as of <date> everywhere it appears.
  3. Delete it — dependency, credentials and docs together.

Leaving a never-run path documented as required is the worst option: it makes an untested branch look like a safety margin, so the run proceeds at a pressure the fallback was supposed to justify.

Direct fetch or paid transport

SituationUse
Public data, documented ceiling, no anti-botDirect fetch at the computed rate. A proxy here buys nothing and bills per request.
Per-IP quota you will exhaustPaid transport — it is the only thing that changes the binding constraint, because it changes the IP. More local workers cannot.
Anti-bot / CAPTCHA / fingerprintingPaid unblocker. Rolling your own is a maintenance treadmill.
Geo-restricted contentProxy with geo-targeting.
Data already collected by a vendorBuy the dataset or archive dump; do not re-crawl.

Vendor table

Every figure below was read from the vendor's own page on 2026-09-08; URLs in References. Pricing and limits move — re-read before quoting them to anyone.

Zyte APIBright DataScrapingBee
Throughput modelRate limit, RPM-based — 3,000 RPM standard, 10,000 RPM enterprise, per API key. Not a concurrency cap.Per-zone concurrency + spend caps. Vendor claims no concurrency limit (SERP pricing FAQ); no canonical docs page states a number — treat as unverified.Concurrency cap, per plan — 25 / 50 / 100 / 200 / 400 concurrent requests, Hobby → Business+.
Over-limit behaviourHTTP 429, charged nothing, retry with backoff; official clients retry by default.Per-zone auto-throttling on the target; spend limit is the real guardrail.429/5xx from the target; failed attempts still burn credits unless mode=auto fails entirely (0 credits).
Client concurrency knobAsyncZyteAPI(n_conn=...), CONCURRENT_REQUESTS in Scrapy; docs use ~15 as the worked example.Zone config; raise via support.Whatever your plan's cap is — cap per domain, not just globally.
Billing unitPer successful response; tier depends on target + HTTP vs browser. Screenshots $0.002; auto-extraction $0.0004–$0.0016/type.Per successful request: Unlocker/SERP/Crawl from $1/1k req; Browser API from $5/GB; Web Archive dump ~$0.001/page; datasets from $250/100k rec.Credits: 1 plain, 5 JS render, 10 premium proxy no-JS, 25 premium+JS, 75 stealth. Plans $19–$599/mo for 75k–8M credits.
Entry pricePAYG on signup, $5 free credit, $100/mo spend limit.Free tier on Unlocker/SERP/Scraper APIs.1,000 free credits, no card.
Best atScrapy-native pipelines; explicit published rate limits you can compute against.Breadth — archive corpus, prebuilt datasets, unlocker, all under one token. Already wired for FINRA/IAPD work.Simple REST unblocking with a hard, legible concurrency number per plan.

Do not read the concurrency column as a target. It is the vendor's ceiling on their side; the target site's ceiling is a different number and is the one E7 measures against. ScrapingBee's own docs warn that running at the cap provokes 429/5xx from targets and burns credits on failures.

Facts

  • SEC EDGAR publishes 10 requests/second and requires a declared User-Agent naming a contact address; it explicitly reserves the right to throttle and states it does not allow botnets or automated crawling outside that policy. A scraper that neither declares a UA nor computes its rate is not merely impolite — it is the case the policy names, and the block lands on the shared IP.
  • Rate-limited Zyte requests cost nothing, so retrying with backoff is free; a hand-rolled client that treats 429 as a fatal error throws away a retry the vendor already priced at zero.
  • ScrapingBee credits are not requests. JS rendering is 5×, premium proxy with JS is 25×, stealth is 75×. A 1M-credit plan is 1M pages only if nothing renders JS — sizing a job in "requests" against a credit allowance overstates capacity by up to 75×.
  • Bright Data's "unlimited concurrency" appears in pricing/marketing copy, not in a docs page with a number. Quoting it as a verified limit is an unverified claim presented as fact; if a run depends on it, open a ticket and get the zone provisioned rather than assuming.
  • A per-IP quota is the one case where local concurrency cannot help at all. Parallelising into a quota is the shape of work that looks like a 3× speedup in the log and is a 0× improvement on what the run can actually retrieve.

Red flags — STOP

About toWhy wrongDo instead
Set max_workers=N with no EFFECTIVE_RPS beside itThe load change is unreviewed and unrecordedCompute workers / sleep, name the ceiling and its URL
Raise workers because the job is slowIf the target enforces a quota this buys nothing and exhausts it soonerName quota vs rate limit first; that decides the fix
Treat "no documented rate limit" as permissionAbsence of a published number is not consentHold at 1 req/s and record where you looked
Cite a fallback proxy as the answer to a quotaIt may never have executedxan frequency -s transport on the manifest; zero uses = untested
Quote a vendor concurrency or price figure from memoryThese pages changed within the last yearRe-read the vendor page and date the citation
Size a ScrapingBee job in requests against a credit allowanceCredits are 1–75× per requestMultiply by the tier you will actually use
Call a paid unblocker for public, unprotected pagesBills per request for something a direct fetch does freeDirect fetch at the computed rate
Run a bulk scrape without a 5–10 page test firstRepo rule: test before scalingFetch 5–10, inspect, then scale

References

Read on 2026-09-08:

Local:

  • ${CLAUDE_SKILL_DIR}/../../rules/ds-rate-limit-choice.md — constraint E7, normative.
  • ${CLAUDE_SKILL_DIR}/references/bright-data-api.md — Bright Data API, auth, cost enforcement, endpoints.
  • ${CLAUDE_SKILL_DIR}/references/bright-data-webarchive-api.md — Web Archive filters and parallel-poll harness.
  • ${CLAUDE_SKILL_DIR}/references/bright-data-datasets-catalog.md — the 1,576-dataset marketplace.
  • ${CLAUDE_SKILL_DIR}/references/bright-data-finra-sec-coverage.md — verified FINRA/IAPD coverage and dump costs.
  • The sec-fetch skill owns SEC.gov specifically (declared-UA access that avoids the 403).

Signals

GitHub stars
21
Forks
4
Last commit
Sep 2026

ahel review

  • K2info
    exfiltration (in references/bright-data-api.md)
  • K2info
    exfiltration (in references/bright-data-webarchive-api.md)

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Catalog kind
skill
Gateway key
web-scraping-edwinhu
Source
github.com/edwinhu/workflows