TypeScript 97.5%
SQL 1.4%
Python 0.8%
1# fetcha — Python SDK23Official Python client for [Fetcha](https://www.fetcha.co), the intelligent web-access API. Standard library only, Python 3.9+.45```bash6pip install fetcha7```89```python10from fetcha import Fetcha1112client = Fetcha(api_key="fch_live_...")1314# Fetch a page — Fetcha picks the network, geography and retries for you15result = client.fetch("https://example.com", country="CA")16print(result.status, result.metadata["network"], result.metadata["mode"], result.metadata["attempts"])17print(result.content[:500])1819# Readable text, Markdown or JSON helpers20text = client.text("https://example.com")21md = client.markdown("https://example.com/article") # main content as Markdown22data = client.json("https://api.example.com/items")2324# Page metadata and links come with every HTML response25r = client.fetch("https://example.com", links=True)26print(r.page["title"], r.page["links_count"], r.links[:3])2728# Managed browser rendering (same network / country / session as a plain fetch)29r = client.render("https://app.example.com/dashboard", wait_for="table.results", screenshot=True)30open("dashboard.png", "wb").write(__import__("base64").b64decode(r.screenshot))31# Blocked HTTP attempts escalate to the browser automatically (browser_fallback=True by default);32# r.mode tells you whether the final attempt was "http" or "browser".3334# Sticky sessions keep the same exit identity across requests35session = client.sessions.create(country="CA", ttl=600)36page1 = client.fetch("https://example.com/login", session=session.id)37page2 = client.fetch("https://example.com/account", session=session.id)3839# Crawl a site into Markdown (asynchronous job)40job = client.crawl.create(url="https://docs.example.com/", max_pages=200, max_depth=3, include_patterns=["/docs/*"])41job = client.crawl.wait(job.id, poll_s=2.0, timeout_s=600) # polls until completed | failed | cancelled42print(job.status, job.stats) # {'discovered': …, 'fetched': …, 'ok': …, 'blocked': …, 'failed': …, 'bytes': …}43for page in client.crawl.iter_pages(job.id, status="success"):44 print(page.url, page.title, len(page.content or ""))45# or page manually: client.crawl.pages(job.id, cursor=None, limit=100).next_cursor46client.crawl.cancel(job.id)4748# Map a site's URLs (sitemap + links) without fetching every page49m = client.map("https://docs.example.com/", search="/docs/*", limit=500)50print(m.count, m.urls[:5], m.sources, m.truncated)51```5253Errors raise `fetcha.FetchaError` with `.code`, `.status`, `.request_id` and `.details`.54