# ScrapingAnt's Python client against SpecStream

Date: 2026-11-10. Client: scrapingant-client 2.1.0.

## The one line a user changes

Before:

```
client = ScrapingAntClient(token="...")
```

After:

```
scrapingant_client.client.SCRAPINGANT_API_BASE_URL = "https://api.specstream.ai/scrapingant/v2"
client = ScrapingAntClient(token=KEY)
```

One call is one Extract API page read at $0.0008; a failed page is not charged.
A request with no credits left answers 403, as ScrapingAnt does.

## Request parameters

Honoured means the check in the Measured column passed on the reply. Accepted, not applied means status 200 and the reply has the form of the same call without the parameter. Refused means the vendor's error body and status.

Counts: 5 honoured, 7 accepted, not applied, 3 refused.

| Parameter | Sent | Verdict | Measured |
|---|---|---|---|
| `url (general_request, /extended)` | `https://en.wikipedia.org/wiki/Web_scraping` | honoured | status 200; content is the page's HTML, status_code 200 |
| `x-api-key` | the client's own header | honoured | status 200; answered with the page |
| `url (a page the site does not have)` | a 404 page | honoured | status 200; status_code is the page's 404 |
| `url (a host that does not resolve)` | an unknown host | refused | status 404; ScrapingantSiteNotReachableException |
| `browser` | `False` | accepted, not applied | status 200; the reply is the baseline's page |
| `proxy_type` | `residential` | accepted, not applied | status 200; the reply is the baseline's page |
| `proxy_country` | `DE` | accepted, not applied | status 200; the reply is the baseline's page |
| `wait_for_selector` | `#content` | accepted, not applied | status 200; the reply is the baseline's page |
| `js_snippet` | `document.title` | accepted, not applied | status 200; the reply is the baseline's page |
| `return_page_source` | `True` | accepted, not applied | status 200; the reply is the baseline's page |
| `cookies` | `[]` | accepted, not applied | status 200; the reply is the baseline's page |
| `url (markdown_request, /markdown)` | `https://en.wikipedia.org/wiki/Web_scraping` | honoured | status 200; markdown is the page |
| `url (/general, documented curl)` | the key as the x-api-key parameter | honoured | status 200; the body is the page's HTML |
| `x-api-key (wrong key)` | a key that is not one | refused | status 403; ScrapingantInvalidTokenException |
| `x-api-key (missing)` | no key | refused | status 422; ScrapingAnt's 422 detail |

## Response fields

Present means the field holds a value in the replies to the calls above. Empty means it is there with no value. Absent means it is not in the reply.

Counts: 6 present, 1 empty, 5 absent.

| Field | State | Measured |
|---|---|---|
| `/extended html` | present | every general_request reply |
| `/extended text` | present | every general_request reply |
| `/extended status_code` | present | every general_request reply |
| `/extended cookies` | empty | every general_request reply |
| `/extended headers` | absent | one /extended reply |
| `/extended xhrs` | absent | one /extended reply |
| `/extended iframes` | absent | one /extended reply |
| `/markdown url` | present | the markdown_request reply |
| `/markdown markdown` | present | the markdown_request reply |
| `/general body` | present | the documented curl call |
| `Ant-page-status-code header` | absent | the documented curl call |
| `Ant-credits-cost header` | absent | the documented curl call |
