Skip to main content

Python SDK for the Scraping Pros API — web scraping with browser rendering, proxy rotation, and structured data extraction.

Project description

scrapingpros

Production web scraping at scale, without the plumbing. Submit a list of URLs, stream results as the workers finish them, and let the server handle the hard parts — browsers, proxies, retries, anti-bot, soft-block detection. Submit 50,000 URLs in one call, walk away, come back to handled results.

PyPI Python License: MIT

📚 Full docs · 📦 PyPI · 📝 Release notes · 🔧 API status


Install

pip install scrapingpros

Requires Python 3.10+. No signup needed — the demo token below gives you 5,000 credits/month, 30 req/min, all features enabled.

The headline use case — submit_batch() + iter_results()

Streaming async batches are the centerpiece of the SDK. They scale from a handful of URLs up to tens of thousands, with progress, automatic resume, soft-block detection, and per-job traceability via custom_id:

from scrapingpros import SyncClient

client = SyncClient("demo_6x595maoA6GdOdVb")

# Submit 50,000 URLs in one call — the API queues them across the worker pool.
batch = client.submit_batch("daily-products", [
    {"url": product_url, "custom_id": product_id}
    for product_id, product_url in catalog.items()
])

# Stream results as workers finish them. Progress, ETA, and counters are live.
for result in batch.iter_results():
    if result.guidance.success:
        save(product_id=result.custom_id, content=result.content)
    else:
        log_failure(result.custom_id, result.guidance.error_type, result.guidance.next_steps)

    # Live progress — no extra API calls
    print(f"{batch.pct:.1%}  ({batch.success_count}/{batch.total})  ETA {batch.eta_seconds}s")

What you get out of the box:

  • Streaming, not "submit and poll". Results come back the moment each worker finishes — your loop body runs in real time.
  • custom_id round-trips through every layer (request → job → result → webhook). Map results back to your domain objects without depending on order.
  • result.guidance.success is the server's verdict on whether the page produced usable content. It catches soft-blocks (Google CAPTCHA pages with 200 + large body, Amazon "Robot Check") that a naive status_code check would miss.
  • Automatic refunds. Credits are refunded on the spot for any response that doesn't deliver usable content (4xx/5xx, captchas, worker failures, timeouts). You pay for successful content only.
  • Per-job retries with proxy rotation and IP/fingerprint changes. retry_on_block=True handles anti-bot sites without you writing retry logic.
  • Worker-restart resilient. The SDK re-attaches transparently to in-flight runs across transient ConnectionError and worker churn.

When to use sync (client.scrape)

Sync is for one-off requests, exploration, and debugging. It blocks on a single URL and returns the result inline. For anything that involves more than a handful of pages or runs on a schedule, use submit_batch().

result = client.scrape("https://example.com", format="markdown")
print(result.content)            # markdown if available, else html
print(result.guidance.success)   # canonical verdict

Common patterns

Browser-rendered + anti-bot protected sites

result = client.scrape(
    "https://spa-site.com",
    browser=True,            # 5 credits, full JS rendering
    retry_on_block=True,     # auto-retry up to 3x with different IP/fingerprint
)

The API picks the right engine internally per target — you don't configure browser engines.

Structured data extraction (CSS / XPath, no parsing on your side)

result = client.scrape("https://quotes.toscrape.com/", extract={
    "quotes":  {"selector": "css:.text",   "multiple": True},
    "authors": {"selector": "css:.author", "multiple": True},
})
print(result.extracted_data["quotes"])

Form-encoded POST (OAuth2, legacy APIs)

from scrapingpros import MethodPOST

resp = client.scrape(token_url, http_method=MethodPOST(
    payload={"grant_type": "client_credentials"},
    content_type="form",   # since v0.5.0; default is "json"
))

Wait for hidden DOM nodes (<script> tags with embedded JSON)

from scrapingpros import WaitForSelectorAction

result = client.scrape(url, browser=True, actions=[
    WaitForSelectorAction(selector="css:script#__NEXT_DATA__", time=8000, state="attached"),
])

Capture response bodies (auth tokens, GraphQL payloads)

from scrapingpros import NetworkCaptureConfig

result = client.scrape(url, browser=True, network_capture=NetworkCaptureConfig(
    resource_types=["xhr", "fetch"],
    url_pattern="*identitytoolkit.googleapis.com*",   # captures matching response bodies (≤64 KB)
))
for entry in result.network_requests or []:
    if "body" in entry:
        token = parse_token(entry["body"])

Async/await client

from scrapingpros import AsyncClient

async with AsyncClient("demo_6x595maoA6GdOdVb") as client:
    result = await client.scrape("https://example.com", format="markdown")
    # Same surface as SyncClient, including submit_batch() / iter_results()

Note on naming. Switching from SyncClient to AsyncClient only changes the local I/O loop — both classes can call every endpoint (sync and Collections) and neither is faster on its own. To scale to many URLs, the lever is submit_batch() / batch_scrape(), not which client class you instantiate. See Choosing the right method.

List return instead of streaming — batch_scrape()

Same server-side scaling as submit_batch(), simpler signature. Drop-in replacement for the deprecated scrape_many():

results = client.batch_scrape([
    {"url": u, "custom_id": product_id, "browser": True}
    for product_id, u in catalog.items()
])
for r in results:
    if r.guidance.success:
        save(r.custom_id, r.content)

Pricing — pay only for usable content

Plan Price Credits/mo Rate Concurrent
Demo (public) Free 5,000 30/min 5
Free $0 1,000 30/min 5
Starter $29 25,000 30/min 10
Growth $69 100,000 60/min 20
Pro $199 500,000 120/min 50
Scale $499 2,500,000 200/min 100
Enterprise Custom Unlimited 2,000/min Custom

1 simple request = 1 credit, 1 browser request = 5 credits. Credits are refunded automatically on failures (is_success=false). Anti-bot, proxy rotation, and per-country routing are included on every plan.

Check your usage at any time:

client.scrape(url)
print(client.quota_remaining, "credits left")
print(client.billing())

Error handling

from scrapingpros import SyncClient, AuthenticationError, RateLimitError, QuotaExceededError

try:
    result = client.scrape(url)
except AuthenticationError:
    print("Invalid token — use demo_6x595maoA6GdOdVb for testing")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except QuotaExceededError:
    print("Monthly quota exceeded — upgrade your plan for more requests")

All SDK exceptions inherit from ScrapingProsError.

Configuration

client = SyncClient(
    "demo_6x595maoA6GdOdVb",            # or your dedicated token / SP_TOKEN env var
    base_url="https://api.scrapingpros.com",   # default
    timeout=120.0,                       # request timeout in seconds
    max_retries=3,                       # auto-retry on 429
)

More

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scrapingpros-0.5.1.tar.gz (173.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scrapingpros-0.5.1-py3-none-any.whl (49.4 kB view details)

Uploaded Python 3

File details

Details for the file scrapingpros-0.5.1.tar.gz.

File metadata

  • Download URL: scrapingpros-0.5.1.tar.gz
  • Upload date:
  • Size: 173.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for scrapingpros-0.5.1.tar.gz
Algorithm Hash digest
SHA256 90fbc4f203e2865e79e396e06ba0e1c1946ce7819f87e1079d044f5c6677aa29
MD5 98f864b804a7d2ded2ef6268ca0e7571
BLAKE2b-256 6ada92113df012f5c1cfbdc8c796b21f687a49e0c0bc3dbc6cf49bbdb0ddb337

See more details on using hashes here.

File details

Details for the file scrapingpros-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: scrapingpros-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 49.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for scrapingpros-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cfd44c519ffc14d735c413608eb8c81d1501ceb8fd69fbc7feea1efe2d0675c4
MD5 a102ae5f2b21d478ce50ac9dcfce01da
BLAKE2b-256 4f478df7f10a8d234fb9304f6a4e5ede5c9adbf7d3e60a199403bfece75f9265

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page