alterlab 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,375 @@
1
+ Metadata-Version: 2.4
2
+ Name: alterlab
3
+ Version: 2.0.0
4
+ Summary: Official Python SDK for the AlterLab Web Scraping API - Extract data from any website with intelligent anti-bot bypass
5
+ License: MIT
6
+ Keywords: web-scraping,scraping,api,data-extraction,anti-bot,javascript-rendering,headless-browser,proxy,alterlab
7
+ Author: AlterLab
8
+ Author-email: dev@alterlab.io
9
+ Requires-Python: >=3.8,<4.0
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Dist: httpx (>=0.24.0)
26
+ Project-URL: Bug Tracker, https://github.com/alterlab/alterlab-python/issues
27
+ Project-URL: Changelog, https://github.com/alterlab/alterlab-python/releases
28
+ Project-URL: Documentation, https://alterlab.io/docs/sdk/python
29
+ Project-URL: Homepage, https://alterlab.io
30
+ Project-URL: Repository, https://github.com/alterlab/alterlab-python
31
+ Description-Content-Type: text/markdown
32
+
33
+ # AlterLab Python SDK
34
+
35
+ Official Python SDK for the [AlterLab Web Scraping API](https://alterlab.io). Extract data from any website with intelligent anti-bot bypass, JavaScript rendering, and structured extraction.
36
+
37
+ [![PyPI version](https://badge.fury.io/py/alterlab.svg)](https://badge.fury.io/py/alterlab)
38
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
40
+
41
+ ## Features
42
+
43
+ - **Simple API**: 3 lines of code to scrape any website
44
+ - **Intelligent Anti-Bot Bypass**: Automatic tier escalation (curl → HTTP → stealth → browser)
45
+ - **JavaScript Rendering**: Full Playwright browser for JS-heavy sites
46
+ - **Structured Extraction**: JSON Schema, prompts, and pre-built profiles
47
+ - **BYOP Support**: Bring Your Own Proxy for 20% discount
48
+ - **Async Support**: Native asyncio for concurrent scraping
49
+ - **Type Hints**: Full typing support for IDE autocomplete
50
+ - **Cost Controls**: Set budgets, prefer cost/speed, fail-fast options
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install alterlab
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ```python
61
+ from alterlab import AlterLab
62
+
63
+ # Initialize client
64
+ client = AlterLab(api_key="sk_live_...") # or set ALTERLAB_API_KEY env var
65
+
66
+ # Scrape a website
67
+ result = client.scrape("https://example.com")
68
+ print(result.text) # Extracted text
69
+ print(result.json) # Structured JSON (Schema.org, metadata)
70
+ print(result.billing.cost_dollars) # Cost breakdown
71
+ ```
72
+
73
+ ## Pricing
74
+
75
+ Pay-as-you-go pricing with no subscriptions. **$1 = 5,000 scrapes** (Tier 1).
76
+
77
+ | Tier | Name | Price | Per $1 | Use Case |
78
+ |------|------|-------|--------|----------|
79
+ | 1 | Curl | $0.0002 | 5,000 | Static HTML sites |
80
+ | 2 | HTTP | $0.0003 | 3,333 | Sites with TLS fingerprinting |
81
+ | 3 | Stealth | $0.0005 | 2,000 | Sites with browser checks |
82
+ | 4 | Browser | $0.001 | 1,000 | JS-heavy SPAs |
83
+ | 5 | Captcha | $0.02 | 50 | Sites with CAPTCHAs |
84
+
85
+ The API automatically escalates through tiers until successful, charging only for the tier used.
86
+
87
+ ## Usage Examples
88
+
89
+ ### Basic Scraping
90
+
91
+ ```python
92
+ from alterlab import AlterLab
93
+
94
+ client = AlterLab(api_key="sk_live_...")
95
+
96
+ # Auto mode - intelligent tier escalation
97
+ result = client.scrape("https://example.com")
98
+
99
+ # Force HTML-only (fastest, cheapest)
100
+ result = client.scrape_html("https://example.com")
101
+
102
+ # JavaScript rendering
103
+ result = client.scrape_js("https://spa-app.com", screenshot=True)
104
+ print(result.screenshot_url)
105
+ ```
106
+
107
+ ### Structured Extraction
108
+
109
+ ```python
110
+ # Extract specific fields with JSON Schema
111
+ result = client.scrape(
112
+ "https://store.com/product/123",
113
+ extraction_schema={
114
+ "type": "object",
115
+ "properties": {
116
+ "name": {"type": "string"},
117
+ "price": {"type": "number"},
118
+ "in_stock": {"type": "boolean"}
119
+ }
120
+ }
121
+ )
122
+ print(result.json) # {"name": "...", "price": 29.99, "in_stock": true}
123
+
124
+ # Or use a pre-built profile
125
+ result = client.scrape(
126
+ "https://store.com/product/123",
127
+ extraction_profile="product"
128
+ )
129
+ ```
130
+
131
+ ### Cost Controls
132
+
133
+ ```python
134
+ from alterlab import AlterLab, CostControls
135
+
136
+ client = AlterLab(api_key="sk_live_...")
137
+
138
+ # Limit to cheap tiers only
139
+ result = client.scrape(
140
+ "https://example.com",
141
+ cost_controls=CostControls(
142
+ max_tier="2", # Don't go above HTTP tier
143
+ prefer_cost=True, # Optimize for lowest cost
144
+ fail_fast=True # Error instead of escalating
145
+ )
146
+ )
147
+
148
+ # Estimate cost before scraping
149
+ estimate = client.estimate_cost("https://linkedin.com")
150
+ print(f"Estimated: ${estimate.estimated_cost_dollars:.4f}")
151
+ print(f"Confidence: {estimate.confidence}")
152
+ ```
153
+
154
+ ### Advanced Options
155
+
156
+ ```python
157
+ from alterlab import AlterLab, AdvancedOptions
158
+
159
+ client = AlterLab(api_key="sk_live_...")
160
+
161
+ # Full browser with screenshot and PDF
162
+ result = client.scrape(
163
+ "https://example.com",
164
+ mode="js",
165
+ advanced=AdvancedOptions(
166
+ render_js=True,
167
+ screenshot=True,
168
+ generate_pdf=True,
169
+ markdown=True,
170
+ wait_condition="networkidle"
171
+ )
172
+ )
173
+
174
+ print(result.screenshot_url)
175
+ print(result.pdf_url)
176
+ print(result.markdown_content)
177
+ ```
178
+
179
+ ### BYOP (Bring Your Own Proxy)
180
+
181
+ Get 20% discount when using your own proxy:
182
+
183
+ ```python
184
+ from alterlab import AlterLab, AdvancedOptions
185
+
186
+ client = AlterLab(api_key="sk_live_...")
187
+
188
+ # Use your configured proxy integration
189
+ result = client.scrape(
190
+ "https://example.com",
191
+ advanced=AdvancedOptions(
192
+ use_own_proxy=True,
193
+ proxy_country="US" # Optional: request specific geo
194
+ )
195
+ )
196
+
197
+ # Check if BYOP was applied
198
+ if result.billing.byop_applied:
199
+ print(f"Saved {result.billing.byop_discount_percent}%!")
200
+ ```
201
+
202
+ ### Async Support
203
+
204
+ ```python
205
+ import asyncio
206
+ from alterlab import AsyncAlterLab
207
+
208
+ async def main():
209
+ async with AsyncAlterLab(api_key="sk_live_...") as client:
210
+ # Single request
211
+ result = await client.scrape("https://example.com")
212
+
213
+ # Concurrent requests
214
+ urls = [
215
+ "https://example.com/page1",
216
+ "https://example.com/page2",
217
+ "https://example.com/page3",
218
+ ]
219
+ results = await asyncio.gather(*[client.scrape(url) for url in urls])
220
+
221
+ for r in results:
222
+ print(r.title, r.billing.cost_dollars)
223
+
224
+ asyncio.run(main())
225
+ ```
226
+
227
+ ### Caching
228
+
229
+ ```python
230
+ # Enable caching (opt-in)
231
+ result = client.scrape(
232
+ "https://example.com",
233
+ cache=True, # Enable caching
234
+ cache_ttl=3600, # Cache for 1 hour
235
+ )
236
+
237
+ if result.cached:
238
+ print("Cache hit - no credits charged!")
239
+
240
+ # Force refresh
241
+ result = client.scrape(
242
+ "https://example.com",
243
+ cache=True,
244
+ force_refresh=True # Bypass cache
245
+ )
246
+ ```
247
+
248
+ ### PDF and Image Extraction
249
+
250
+ ```python
251
+ # Extract text from PDF
252
+ result = client.scrape_pdf(
253
+ "https://example.com/document.pdf",
254
+ format="markdown"
255
+ )
256
+ print(result.text)
257
+
258
+ # OCR for images
259
+ result = client.scrape_ocr(
260
+ "https://example.com/image.png",
261
+ language="eng"
262
+ )
263
+ print(result.text)
264
+ ```
265
+
266
+ ### Error Handling
267
+
268
+ ```python
269
+ from alterlab import (
270
+ AlterLab,
271
+ AuthenticationError,
272
+ InsufficientCreditsError,
273
+ RateLimitError,
274
+ ScrapeError,
275
+ TimeoutError
276
+ )
277
+
278
+ client = AlterLab(api_key="sk_live_...")
279
+
280
+ try:
281
+ result = client.scrape("https://example.com")
282
+ except AuthenticationError:
283
+ print("Invalid API key")
284
+ except InsufficientCreditsError:
285
+ print("Please top up your balance")
286
+ except RateLimitError as e:
287
+ print(f"Rate limited. Retry after {e.retry_after}s")
288
+ except ScrapeError as e:
289
+ print(f"Scraping failed: {e.message}")
290
+ except TimeoutError:
291
+ print("Request timed out")
292
+ ```
293
+
294
+ ### Check Usage & Balance
295
+
296
+ ```python
297
+ usage = client.get_usage()
298
+ print(f"Balance: ${usage.balance_dollars:.2f}")
299
+ print(f"Used this month: {usage.credits_used_month} credits")
300
+ ```
301
+
302
+ ## API Reference
303
+
304
+ ### AlterLab Client
305
+
306
+ ```python
307
+ AlterLab(
308
+ api_key: str = None, # API key (or ALTERLAB_API_KEY env var)
309
+ base_url: str = None, # Custom API URL
310
+ timeout: int = 120, # Request timeout in seconds
311
+ max_retries: int = 3, # Retry count for transient failures
312
+ retry_delay: float = 1.0 # Initial retry delay (exponential backoff)
313
+ )
314
+ ```
315
+
316
+ ### scrape() Method
317
+
318
+ ```python
319
+ client.scrape(
320
+ url: str, # URL to scrape
321
+ mode: str = "auto", # "auto", "html", "js", "pdf", "ocr"
322
+ sync: bool = True, # Wait for result vs return job ID
323
+ advanced: AdvancedOptions, # Advanced scraping options
324
+ cost_controls: CostControls, # Budget and optimization settings
325
+ cache: bool = False, # Enable response caching
326
+ cache_ttl: int = None, # Cache TTL in seconds (60-86400)
327
+ formats: list = None, # Output formats: ["text", "json", "html", "markdown"]
328
+ extraction_schema: dict, # JSON Schema for structured extraction
329
+ extraction_prompt: str, # Natural language extraction instructions
330
+ extraction_profile: str, # Pre-built profile: "product", "article", etc.
331
+ wait_for: str = None, # CSS selector to wait for (JS mode)
332
+ screenshot: bool = False, # Capture screenshot (JS mode)
333
+ ) -> ScrapeResult
334
+ ```
335
+
336
+ ### ScrapeResult
337
+
338
+ ```python
339
+ result.url # Scraped URL
340
+ result.status_code # HTTP status
341
+ result.text # Extracted text content
342
+ result.html # HTML content
343
+ result.json # Structured JSON content
344
+ result.title # Page title
345
+ result.author # Author (if detected)
346
+ result.billing # BillingDetails object
347
+ result.billing.tier_used # Tier that succeeded
348
+ result.billing.cost_dollars # Final cost in USD
349
+ result.screenshot_url # Screenshot URL (if requested)
350
+ result.pdf_url # PDF URL (if requested)
351
+ result.cached # Whether result was from cache
352
+ ```
353
+
354
+ ## Environment Variables
355
+
356
+ | Variable | Description |
357
+ |----------|-------------|
358
+ | `ALTERLAB_API_KEY` | Your API key (alternative to passing in constructor) |
359
+
360
+ ## Requirements
361
+
362
+ - Python 3.8+
363
+ - httpx >= 0.24.0
364
+
365
+ ## Support
366
+
367
+ - **Documentation**: [https://alterlab.io/docs](https://alterlab.io/docs)
368
+ - **API Status**: [https://status.alterlab.io](https://status.alterlab.io)
369
+ - **Support**: support@alterlab.io
370
+ - **Issues**: [GitHub Issues](https://github.com/alterlab/alterlab-python/issues)
371
+
372
+ ## License
373
+
374
+ MIT License - see [LICENSE](LICENSE) for details.
375
+
@@ -0,0 +1,342 @@
1
+ # AlterLab Python SDK
2
+
3
+ Official Python SDK for the [AlterLab Web Scraping API](https://alterlab.io). Extract data from any website with intelligent anti-bot bypass, JavaScript rendering, and structured extraction.
4
+
5
+ [![PyPI version](https://badge.fury.io/py/alterlab.svg)](https://badge.fury.io/py/alterlab)
6
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ## Features
10
+
11
+ - **Simple API**: 3 lines of code to scrape any website
12
+ - **Intelligent Anti-Bot Bypass**: Automatic tier escalation (curl → HTTP → stealth → browser)
13
+ - **JavaScript Rendering**: Full Playwright browser for JS-heavy sites
14
+ - **Structured Extraction**: JSON Schema, prompts, and pre-built profiles
15
+ - **BYOP Support**: Bring Your Own Proxy for 20% discount
16
+ - **Async Support**: Native asyncio for concurrent scraping
17
+ - **Type Hints**: Full typing support for IDE autocomplete
18
+ - **Cost Controls**: Set budgets, prefer cost/speed, fail-fast options
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install alterlab
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```python
29
+ from alterlab import AlterLab
30
+
31
+ # Initialize client
32
+ client = AlterLab(api_key="sk_live_...") # or set ALTERLAB_API_KEY env var
33
+
34
+ # Scrape a website
35
+ result = client.scrape("https://example.com")
36
+ print(result.text) # Extracted text
37
+ print(result.json) # Structured JSON (Schema.org, metadata)
38
+ print(result.billing.cost_dollars) # Cost breakdown
39
+ ```
40
+
41
+ ## Pricing
42
+
43
+ Pay-as-you-go pricing with no subscriptions. **$1 = 5,000 scrapes** (Tier 1).
44
+
45
+ | Tier | Name | Price | Per $1 | Use Case |
46
+ |------|------|-------|--------|----------|
47
+ | 1 | Curl | $0.0002 | 5,000 | Static HTML sites |
48
+ | 2 | HTTP | $0.0003 | 3,333 | Sites with TLS fingerprinting |
49
+ | 3 | Stealth | $0.0005 | 2,000 | Sites with browser checks |
50
+ | 4 | Browser | $0.001 | 1,000 | JS-heavy SPAs |
51
+ | 5 | Captcha | $0.02 | 50 | Sites with CAPTCHAs |
52
+
53
+ The API automatically escalates through tiers until successful, charging only for the tier used.
54
+
55
+ ## Usage Examples
56
+
57
+ ### Basic Scraping
58
+
59
+ ```python
60
+ from alterlab import AlterLab
61
+
62
+ client = AlterLab(api_key="sk_live_...")
63
+
64
+ # Auto mode - intelligent tier escalation
65
+ result = client.scrape("https://example.com")
66
+
67
+ # Force HTML-only (fastest, cheapest)
68
+ result = client.scrape_html("https://example.com")
69
+
70
+ # JavaScript rendering
71
+ result = client.scrape_js("https://spa-app.com", screenshot=True)
72
+ print(result.screenshot_url)
73
+ ```
74
+
75
+ ### Structured Extraction
76
+
77
+ ```python
78
+ # Extract specific fields with JSON Schema
79
+ result = client.scrape(
80
+ "https://store.com/product/123",
81
+ extraction_schema={
82
+ "type": "object",
83
+ "properties": {
84
+ "name": {"type": "string"},
85
+ "price": {"type": "number"},
86
+ "in_stock": {"type": "boolean"}
87
+ }
88
+ }
89
+ )
90
+ print(result.json) # {"name": "...", "price": 29.99, "in_stock": true}
91
+
92
+ # Or use a pre-built profile
93
+ result = client.scrape(
94
+ "https://store.com/product/123",
95
+ extraction_profile="product"
96
+ )
97
+ ```
98
+
99
+ ### Cost Controls
100
+
101
+ ```python
102
+ from alterlab import AlterLab, CostControls
103
+
104
+ client = AlterLab(api_key="sk_live_...")
105
+
106
+ # Limit to cheap tiers only
107
+ result = client.scrape(
108
+ "https://example.com",
109
+ cost_controls=CostControls(
110
+ max_tier="2", # Don't go above HTTP tier
111
+ prefer_cost=True, # Optimize for lowest cost
112
+ fail_fast=True # Error instead of escalating
113
+ )
114
+ )
115
+
116
+ # Estimate cost before scraping
117
+ estimate = client.estimate_cost("https://linkedin.com")
118
+ print(f"Estimated: ${estimate.estimated_cost_dollars:.4f}")
119
+ print(f"Confidence: {estimate.confidence}")
120
+ ```
121
+
122
+ ### Advanced Options
123
+
124
+ ```python
125
+ from alterlab import AlterLab, AdvancedOptions
126
+
127
+ client = AlterLab(api_key="sk_live_...")
128
+
129
+ # Full browser with screenshot and PDF
130
+ result = client.scrape(
131
+ "https://example.com",
132
+ mode="js",
133
+ advanced=AdvancedOptions(
134
+ render_js=True,
135
+ screenshot=True,
136
+ generate_pdf=True,
137
+ markdown=True,
138
+ wait_condition="networkidle"
139
+ )
140
+ )
141
+
142
+ print(result.screenshot_url)
143
+ print(result.pdf_url)
144
+ print(result.markdown_content)
145
+ ```
146
+
147
+ ### BYOP (Bring Your Own Proxy)
148
+
149
+ Get 20% discount when using your own proxy:
150
+
151
+ ```python
152
+ from alterlab import AlterLab, AdvancedOptions
153
+
154
+ client = AlterLab(api_key="sk_live_...")
155
+
156
+ # Use your configured proxy integration
157
+ result = client.scrape(
158
+ "https://example.com",
159
+ advanced=AdvancedOptions(
160
+ use_own_proxy=True,
161
+ proxy_country="US" # Optional: request specific geo
162
+ )
163
+ )
164
+
165
+ # Check if BYOP was applied
166
+ if result.billing.byop_applied:
167
+ print(f"Saved {result.billing.byop_discount_percent}%!")
168
+ ```
169
+
170
+ ### Async Support
171
+
172
+ ```python
173
+ import asyncio
174
+ from alterlab import AsyncAlterLab
175
+
176
+ async def main():
177
+ async with AsyncAlterLab(api_key="sk_live_...") as client:
178
+ # Single request
179
+ result = await client.scrape("https://example.com")
180
+
181
+ # Concurrent requests
182
+ urls = [
183
+ "https://example.com/page1",
184
+ "https://example.com/page2",
185
+ "https://example.com/page3",
186
+ ]
187
+ results = await asyncio.gather(*[client.scrape(url) for url in urls])
188
+
189
+ for r in results:
190
+ print(r.title, r.billing.cost_dollars)
191
+
192
+ asyncio.run(main())
193
+ ```
194
+
195
+ ### Caching
196
+
197
+ ```python
198
+ # Enable caching (opt-in)
199
+ result = client.scrape(
200
+ "https://example.com",
201
+ cache=True, # Enable caching
202
+ cache_ttl=3600, # Cache for 1 hour
203
+ )
204
+
205
+ if result.cached:
206
+ print("Cache hit - no credits charged!")
207
+
208
+ # Force refresh
209
+ result = client.scrape(
210
+ "https://example.com",
211
+ cache=True,
212
+ force_refresh=True # Bypass cache
213
+ )
214
+ ```
215
+
216
+ ### PDF and Image Extraction
217
+
218
+ ```python
219
+ # Extract text from PDF
220
+ result = client.scrape_pdf(
221
+ "https://example.com/document.pdf",
222
+ format="markdown"
223
+ )
224
+ print(result.text)
225
+
226
+ # OCR for images
227
+ result = client.scrape_ocr(
228
+ "https://example.com/image.png",
229
+ language="eng"
230
+ )
231
+ print(result.text)
232
+ ```
233
+
234
+ ### Error Handling
235
+
236
+ ```python
237
+ from alterlab import (
238
+ AlterLab,
239
+ AuthenticationError,
240
+ InsufficientCreditsError,
241
+ RateLimitError,
242
+ ScrapeError,
243
+ TimeoutError
244
+ )
245
+
246
+ client = AlterLab(api_key="sk_live_...")
247
+
248
+ try:
249
+ result = client.scrape("https://example.com")
250
+ except AuthenticationError:
251
+ print("Invalid API key")
252
+ except InsufficientCreditsError:
253
+ print("Please top up your balance")
254
+ except RateLimitError as e:
255
+ print(f"Rate limited. Retry after {e.retry_after}s")
256
+ except ScrapeError as e:
257
+ print(f"Scraping failed: {e.message}")
258
+ except TimeoutError:
259
+ print("Request timed out")
260
+ ```
261
+
262
+ ### Check Usage & Balance
263
+
264
+ ```python
265
+ usage = client.get_usage()
266
+ print(f"Balance: ${usage.balance_dollars:.2f}")
267
+ print(f"Used this month: {usage.credits_used_month} credits")
268
+ ```
269
+
270
+ ## API Reference
271
+
272
+ ### AlterLab Client
273
+
274
+ ```python
275
+ AlterLab(
276
+ api_key: str = None, # API key (or ALTERLAB_API_KEY env var)
277
+ base_url: str = None, # Custom API URL
278
+ timeout: int = 120, # Request timeout in seconds
279
+ max_retries: int = 3, # Retry count for transient failures
280
+ retry_delay: float = 1.0 # Initial retry delay (exponential backoff)
281
+ )
282
+ ```
283
+
284
+ ### scrape() Method
285
+
286
+ ```python
287
+ client.scrape(
288
+ url: str, # URL to scrape
289
+ mode: str = "auto", # "auto", "html", "js", "pdf", "ocr"
290
+ sync: bool = True, # Wait for result vs return job ID
291
+ advanced: AdvancedOptions, # Advanced scraping options
292
+ cost_controls: CostControls, # Budget and optimization settings
293
+ cache: bool = False, # Enable response caching
294
+ cache_ttl: int = None, # Cache TTL in seconds (60-86400)
295
+ formats: list = None, # Output formats: ["text", "json", "html", "markdown"]
296
+ extraction_schema: dict, # JSON Schema for structured extraction
297
+ extraction_prompt: str, # Natural language extraction instructions
298
+ extraction_profile: str, # Pre-built profile: "product", "article", etc.
299
+ wait_for: str = None, # CSS selector to wait for (JS mode)
300
+ screenshot: bool = False, # Capture screenshot (JS mode)
301
+ ) -> ScrapeResult
302
+ ```
303
+
304
+ ### ScrapeResult
305
+
306
+ ```python
307
+ result.url # Scraped URL
308
+ result.status_code # HTTP status
309
+ result.text # Extracted text content
310
+ result.html # HTML content
311
+ result.json # Structured JSON content
312
+ result.title # Page title
313
+ result.author # Author (if detected)
314
+ result.billing # BillingDetails object
315
+ result.billing.tier_used # Tier that succeeded
316
+ result.billing.cost_dollars # Final cost in USD
317
+ result.screenshot_url # Screenshot URL (if requested)
318
+ result.pdf_url # PDF URL (if requested)
319
+ result.cached # Whether result was from cache
320
+ ```
321
+
322
+ ## Environment Variables
323
+
324
+ | Variable | Description |
325
+ |----------|-------------|
326
+ | `ALTERLAB_API_KEY` | Your API key (alternative to passing in constructor) |
327
+
328
+ ## Requirements
329
+
330
+ - Python 3.8+
331
+ - httpx >= 0.24.0
332
+
333
+ ## Support
334
+
335
+ - **Documentation**: [https://alterlab.io/docs](https://alterlab.io/docs)
336
+ - **API Status**: [https://status.alterlab.io](https://status.alterlab.io)
337
+ - **Support**: support@alterlab.io
338
+ - **Issues**: [GitHub Issues](https://github.com/alterlab/alterlab-python/issues)
339
+
340
+ ## License
341
+
342
+ MIT License - see [LICENSE](LICENSE) for details.