Metadata-Version: 2.4
Name: evomi-client
Version: 1.0.0
Summary: Python client for Evomi web scraping API
Project-URL: Homepage, https://evomi.com
Project-URL: Documentation, https://docs.evomi.com
Author-email: Evomi <support@evomi.com>
Keywords: api client,crawling,evomi,extraction,scraper,web scraping
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# Evomi Python Client

A production-ready Python client for the Evomi web scraping API. Provides both synchronous and asynchronous clients for maximum flexibility.

## Features

- **Async & Sync Support** - Use `EvomiClient` for async or `EvomiClientSync` for synchronous operations
- **Full API Coverage** - All Evomi endpoints supported
- **Type Hints** - Complete type annotations for IDE support
- **Minimal Dependencies** - Only requires `httpx`

## Installation

```bash
pip install evomi-client
```

## Quick Start

### Async Client

```python
import asyncio
from evomi_client import EvomiClient

async def main():
    # Initialize with API key (or set EVOMI_API_KEY env var)
    client = EvomiClient(api_key="your-api-key")
    
    # Scrape a URL
    result = await client.scrape("https://example.com")
    print(result)
    
    # Get markdown output
    result = await client.scrape(
        "https://example.com",
        output="markdown",
        mode="auto"  # auto-detect JS requirement
    )
    
    # AI-powered extraction
    result = await client.scrape(
        "https://example.com/products",
        ai_enhance=True,
        ai_prompt="Extract product names and prices"
    )

asyncio.run(main())
```

### Sync Client

```python
from evomi_client import EvomiClientSync

# Initialize with API key (or set EVOMI_API_KEY env var)
client = EvomiClientSync(api_key="your-api-key")

# Scrape a URL
result = client.scrape("https://example.com")
print(result)
```

## API Reference

### Scraping Operations

#### `scrape(url, ...)`

Scrape a single URL with configurable options.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `url` | str | required | URL to scrape |
| `mode` | str | "auto" | Scraping mode: "request" (fast), "browser" (JS), "auto" (detect) |
| `output` | str | "markdown" | Output format: "html", "markdown", "screenshot", "pdf" |
| `device` | str | "windows" | Device type: "windows", "macos", "android" |
| `proxy_type` | str | "residential" | Proxy type: "datacenter", "residential" |
| `proxy_country` | str | "US" | Two-letter country code |
| `proxy_session_id` | str | None | Proxy session ID (6-8 chars) |
| `wait_until` | str | "domcontentloaded" | Wait condition |
| `ai_enhance` | bool | False | Enable AI enhancement |
| `ai_prompt` | str | None | Prompt for AI extraction |
| `ai_source` | str | None | AI source: "markdown", "screenshot" |
| `js_instructions` | list | None | JS actions: click, wait, fill, wait_for |
| `execute_js` | str | None | Raw JavaScript to execute |
| `screenshot` | bool | False | Capture screenshot |
| `pdf` | bool | False | Capture PDF |
| `wait_seconds` | int | 0 | Seconds to wait after load |
| `excluded_tags` | list | None | HTML tags to remove |
| `excluded_selectors` | list | None | CSS selectors to remove |
| `block_resources` | list | None | Resource types to block |
| `additional_headers` | dict | None | Extra HTTP headers |
| `capture_headers` | bool | False | Capture response headers |
| `network_capture` | list | None | Network capture filters |
| `async_mode` | bool | False | Return immediately with task ID |
| `config_id` | str | None | Saved config ID |
| `scheme_id` | str | None | Saved extraction schema ID |
| `extract_scheme` | list | None | Inline extraction schema |
| `storage_id` | str | None | Storage config ID |
| `use_default_storage` | bool | False | Use default storage |
| `no_html` | bool | False | Exclude HTML from response |

#### `crawl(domain, ...)`

Crawl a website to discover and scrape multiple pages.

```python
result = await client.crawl(
    domain="example.com",
    max_urls=100,
    depth=2,
    url_pattern="/products/.*",  # Regex filter
    async_mode=True  # Returns task_id
)
```

#### `map_website(domain, ...)`

Discover URLs from a website.

```python
result = await client.map_website(
    domain="example.com",
    sources=["sitemap", "commoncrawl"],
    max_urls=500
)
```

#### `search_domains(query, ...)`

Find domains by searching the web.

```python
result = await client.search_domains(
    query="best e-commerce sites",
    max_urls=20,
    region="us-en"
)
```

#### `agent_request(message)`

Send a natural language request to the AI agent.

```python
result = await client.agent_request(
    "Scrape example.com and extract all product prices"
)
```

#### `get_task_status(task_id, task_type)`

Check the status of an async task.

```python
result = await client.get_task_status(
    task_id="abc123",
    task_type="scrape"  # or "crawl", "map", "config_generate", "schema"
)
```

### Config Management

```python
# List configs
configs = await client.list_configs()

# Create config
config = await client.create_config(
    name="My Scraper",
    config={"mode": "browser", "output": "markdown"}
)

# Get config
config = await client.get_config("cfg_abc123")

# Update config
config = await client.update_config("cfg_abc123", name="New Name")

# Delete config
await client.delete_config("cfg_abc123")

# Generate config from natural language
config = await client.generate_config(
    name="Amazon Scraper",
    prompt="Scrape product title, price, and reviews from Amazon"
)
```

### Schema Management

```python
# List schemas
schemas = await client.list_schemas()

# Create schema with extraction rules
schema = await client.create_schema(
    name="Product Schema",
    config={
        "url": "https://example.com/product",
        "extract_scheme": [
            {"label": "title", "type": "content", "selector": "h1"},
            {"label": "price", "type": "content", "selector": ".price"}
        ]
    },
    test=True  # Test the schema
)

# Get schema status (for async testing)
status = await client.get_schema_status("sch_abc123")
```

### Schedule Management

```python
# Create a scheduled job
schedule = await client.create_schedule(
    name="Daily Price Check",
    config_id="cfg_abc123",
    interval_minutes=1440,  # Daily
    start_time="09:00"  # UTC
)

# List schedules
schedules = await client.list_schedules(active_only=True)

# Toggle schedule
await client.toggle_schedule("sched_abc123")

# Get execution history
runs = await client.list_schedule_runs("sched_abc123")
```

### Storage Management

```python
# Create S3 storage config
storage = await client.create_storage_config(
    name="My S3",
    storage_type="s3_compatible",
    config={
        "bucket": "my-bucket",
        "region": "us-east-1",
        "access_key": "...",
        "secret_key": "..."
    },
    set_as_default=True
)

# List storage configs
configs = await client.list_storage_configs()
```

### Account Info

```python
info = await client.get_account_info()
print(f"Credits remaining: {info.get('credits', 'N/A')}")
```

## Pricing & Credits

All operations consume credits:

- **Base cost**: 1 credit per request
- **Browser mode**: 5x multiplier
- **Residential proxy**: 2x multiplier
- **AI enhancement**: +30 credits
- **Screenshot/PDF**: +1 credit each

Credit information is returned in response headers and in `_credits_used`, `_credits_remaining` fields.

## Error Handling

```python
from evomi_client import EvomiClient

client = EvomiClient(api_key="your-key")

try:
    result = await client.scrape("https://example.com")
except httpx.HTTPStatusError as e:
    print(f"HTTP error: {e.response.status_code}")
    print(f"Response: {e.response.text}")
except httpx.RequestError as e:
    print(f"Request error: {e}")
```

## Configuration

Set your API key via environment variable:

```bash
export EVOMI_API_KEY="your-api-key"
```

Or pass it directly:

```python
client = EvomiClient(api_key="your-api-key")
```

Custom base URL (for testing):

```python
client = EvomiClient(
    api_key="your-api-key",
    base_url="https://custom.evomi.com"
)
```

## Links

- [Evomi Website](https://evomi.com)
- [Evomi Dashboard](https://dashboard.evomi.com)
- [API Documentation](https://docs.evomi.com)

## License

MIT License - see LICENSE file for details.