Home/Python SDK
SDK

Python SDK

Python 3.11+PyPIGitHub

Sync and async Python clients for the ScrapingIsNotACrime API, built on httpx, with responses typed as TypedDict.

PyPIRepository

01Install

bash
pip install scrapingisnotacrime

02Quick start

python
from scrapingisnotacrime import ScrapingIsNotACrime

with ScrapingIsNotACrime() as client:
    profile = client.instagram.profile("nasa")
    print(profile["username"], profile["followers"])

Get a key at your dashboard. Keys start with sinac_, and new accounts get 100 free credits.

Both clients read SCRAPINGISNOTACRIME_API_KEY from the environment, or take it as api_key=.

03Configuration

python
ScrapingIsNotACrime(
    api_key="sinac_...",
    base_url="https://api.scrapingisnotacrime.com/v1",
    timeout=30.0,
    max_retries=2,
    http_client=None,
)
OptionDefaultDescription
api_keySCRAPINGISNOTACRIME_API_KEYYour API key. Raises ValueError at construction if missing. Defaults to the SCRAPINGISNOTACRIME_API_KEY environment variable.
base_urlhttps://api.scrapingisnotacrime.com/v1API base URL. Redirects are not followed, so use the final HTTPS URL.
timeout30.0Per attempt, in seconds.
max_retries2Extra attempts for 429, 502 and network errors. 0 disables retries.
http_clienthttpx.ClientBring your own httpx.Client for tests, proxies or connection pooling. Defaults to a new httpx.Client (httpx.AsyncClient for the async client).

AsyncScrapingIsNotACrime takes the same arguments; http_client accepts an httpx.AsyncClient.

04Methods

05Pagination

Paginated methods return a Page (or AsyncPage) with items, has_more, next_cursor or next_page, data and next(). Iterating it fetches further pages lazily.

Each page fetched is one billed request, so bound your loops. Breaking out early stops fetching.

python
page = client.github.followers("torvalds", limit=100)
for count, user in enumerate(page, start=1):
    print(user["username"])
    if count >= 100:
        break  # stop early; no further pages are fetched
async
page = await client.bluesky.posts("bsky.app", limit=25)
count = 0
async for post in page:
    print(post)
    count += 1
    if count >= 100:
        break  # stop early; no further pages are fetched

06Errors

Every failure raises a subclass of ScrapingIsNotACrimeError with status, message and request_id. ConnectionError is the SDK's own class, not the builtin.

TypeStatusRetried
BadRequestError400no
AuthenticationError401no
QuotaExceededError402no
NotFoundError404no
RateLimitError429yes
UpstreamError502yes
ConnectionErrornetwork failure or timeoutyes
APIErrorany other non-2xx, or a 2xx without the JSON envelopeno
python
from scrapingisnotacrime import (
    NotFoundError,
    QuotaExceededError,
    RateLimitError,
    ScrapingIsNotACrime,
)

client = ScrapingIsNotACrime(max_retries=3)

try:
    client.tiktok.profile("this-user-does-not-exist-123")
except NotFoundError:
    print("No such profile.")
except QuotaExceededError as error:
    print("Out of credits:", error.message)
except RateLimitError:
    print("TikTok is rate limiting; try again later.")

07Retries

Rate limits (429), upstream failures (502) and network failures or timeouts are retried automatically, up to 2 extra attempts by default. These failures don't consume credits. The wait honors the Retry-After header; otherwise it is exponential backoff with jitter, starting at 500 ms and capped at 10 seconds.

Set max_retries=0 to disable retries.

08Async client

AsyncScrapingIsNotACrime exposes the same namespaces and methods as awaitable coroutines. It requires asyncio and does not run under trio.

python
import asyncio

from scrapingisnotacrime import AsyncScrapingIsNotACrime


async def main() -> None:
    async with AsyncScrapingIsNotACrime() as client:
        profile = await client.instagram.profile("nasa")
        print(profile["username"], profile["followers"])


asyncio.run(main())

With your consent, we use Google Analytics and non-personalized Google Ads measurement to understand how the site and the dashboard are used and whether our ads work β€” pages visited and actions like creating an API key or testing a request. We never send Google your email, name, account ID, API keys or request content. You can change your mind anytime in Cookie preferences, in the footer.