firecrawl 3.4.0__py3-none-any.whl → 4.1.0__py3-none-any.whl
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.
Potentially problematic release.
This version of firecrawl might be problematic. Click here for more details.
- firecrawl/__init__.py +1 -1
- firecrawl/__tests__/e2e/v2/test_crawl.py +1 -1
- firecrawl/__tests__/unit/v2/methods/test_pagination.py +602 -0
- firecrawl/v2/client.py +27 -7
- firecrawl/v2/client_async.py +21 -4
- firecrawl/v2/methods/aio/batch.py +107 -8
- firecrawl/v2/methods/aio/crawl.py +172 -3
- firecrawl/v2/methods/batch.py +90 -5
- firecrawl/v2/methods/crawl.py +95 -6
- firecrawl/v2/types.py +34 -2
- firecrawl/v2/utils/http_client.py +26 -3
- firecrawl/v2/utils/validation.py +15 -1
- {firecrawl-3.4.0.dist-info → firecrawl-4.1.0.dist-info}/METADATA +1 -1
- {firecrawl-3.4.0.dist-info → firecrawl-4.1.0.dist-info}/RECORD +17 -16
- {firecrawl-3.4.0.dist-info → firecrawl-4.1.0.dist-info}/WHEEL +0 -0
- {firecrawl-3.4.0.dist-info → firecrawl-4.1.0.dist-info}/licenses/LICENSE +0 -0
- {firecrawl-3.4.0.dist-info → firecrawl-4.1.0.dist-info}/top_level.txt +0 -0
firecrawl/v2/methods/crawl.py
CHANGED
|
@@ -3,12 +3,12 @@ Crawling functionality for Firecrawl v2 API.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import time
|
|
6
|
-
from typing import Optional, Dict, Any
|
|
6
|
+
from typing import Optional, Dict, Any, List
|
|
7
7
|
from ..types import (
|
|
8
8
|
CrawlRequest,
|
|
9
9
|
CrawlJob,
|
|
10
10
|
CrawlResponse, Document, CrawlParamsRequest, CrawlParamsResponse, CrawlParamsData,
|
|
11
|
-
WebhookConfig, CrawlErrorsResponse, ActiveCrawlsResponse, ActiveCrawl
|
|
11
|
+
WebhookConfig, CrawlErrorsResponse, ActiveCrawlsResponse, ActiveCrawl, PaginationConfig
|
|
12
12
|
)
|
|
13
13
|
from ..utils import HttpClient, handle_response_error, validate_scrape_options, prepare_scrape_options
|
|
14
14
|
from ..utils.normalize import normalize_document_input
|
|
@@ -138,13 +138,18 @@ def start_crawl(client: HttpClient, request: CrawlRequest) -> CrawlResponse:
|
|
|
138
138
|
raise Exception(response_data.get("error", "Unknown error occurred"))
|
|
139
139
|
|
|
140
140
|
|
|
141
|
-
def get_crawl_status(
|
|
141
|
+
def get_crawl_status(
|
|
142
|
+
client: HttpClient,
|
|
143
|
+
job_id: str,
|
|
144
|
+
pagination_config: Optional[PaginationConfig] = None
|
|
145
|
+
) -> CrawlJob:
|
|
142
146
|
"""
|
|
143
147
|
Get the status of a crawl job.
|
|
144
148
|
|
|
145
149
|
Args:
|
|
146
150
|
client: HTTP client instance
|
|
147
151
|
job_id: ID of the crawl job
|
|
152
|
+
pagination_config: Optional configuration for pagination behavior
|
|
148
153
|
|
|
149
154
|
Returns:
|
|
150
155
|
CrawlJob with current status and data
|
|
@@ -176,6 +181,16 @@ def get_crawl_status(client: HttpClient, job_id: str) -> CrawlJob:
|
|
|
176
181
|
else:
|
|
177
182
|
documents.append(Document(**normalize_document_input(doc_data)))
|
|
178
183
|
|
|
184
|
+
# Handle pagination if requested
|
|
185
|
+
auto_paginate = pagination_config.auto_paginate if pagination_config else True
|
|
186
|
+
if auto_paginate and response_data.get("next") and not (pagination_config and pagination_config.max_results is not None and len(documents) >= pagination_config.max_results):
|
|
187
|
+
documents = _fetch_all_pages(
|
|
188
|
+
client,
|
|
189
|
+
response_data.get("next"),
|
|
190
|
+
documents,
|
|
191
|
+
pagination_config
|
|
192
|
+
)
|
|
193
|
+
|
|
179
194
|
# Create CrawlJob with current status and data
|
|
180
195
|
return CrawlJob(
|
|
181
196
|
status=response_data.get("status"),
|
|
@@ -183,13 +198,87 @@ def get_crawl_status(client: HttpClient, job_id: str) -> CrawlJob:
|
|
|
183
198
|
total=response_data.get("total", 0),
|
|
184
199
|
credits_used=response_data.get("creditsUsed", 0),
|
|
185
200
|
expires_at=response_data.get("expiresAt"),
|
|
186
|
-
next=response_data.get("next", None),
|
|
201
|
+
next=response_data.get("next", None) if not auto_paginate else None,
|
|
187
202
|
data=documents
|
|
188
203
|
)
|
|
189
204
|
else:
|
|
190
205
|
raise Exception(response_data.get("error", "Unknown error occurred"))
|
|
191
206
|
|
|
192
207
|
|
|
208
|
+
def _fetch_all_pages(
|
|
209
|
+
client: HttpClient,
|
|
210
|
+
next_url: str,
|
|
211
|
+
initial_documents: List[Document],
|
|
212
|
+
pagination_config: Optional[PaginationConfig] = None
|
|
213
|
+
) -> List[Document]:
|
|
214
|
+
"""
|
|
215
|
+
Fetch all pages of crawl results.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
client: HTTP client instance
|
|
219
|
+
next_url: URL for the next page
|
|
220
|
+
initial_documents: Documents from the first page
|
|
221
|
+
pagination_config: Optional configuration for pagination limits
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
List of all documents from all pages
|
|
225
|
+
"""
|
|
226
|
+
documents = initial_documents.copy()
|
|
227
|
+
current_url = next_url
|
|
228
|
+
page_count = 0
|
|
229
|
+
|
|
230
|
+
# Apply pagination limits
|
|
231
|
+
max_pages = pagination_config.max_pages if pagination_config else None
|
|
232
|
+
max_results = pagination_config.max_results if pagination_config else None
|
|
233
|
+
max_wait_time = pagination_config.max_wait_time if pagination_config else None
|
|
234
|
+
|
|
235
|
+
start_time = time.monotonic()
|
|
236
|
+
|
|
237
|
+
while current_url:
|
|
238
|
+
# Check pagination limits (treat 0 as a valid limit)
|
|
239
|
+
if (max_pages is not None) and page_count >= max_pages:
|
|
240
|
+
break
|
|
241
|
+
|
|
242
|
+
if (max_wait_time is not None) and (time.monotonic() - start_time) > max_wait_time:
|
|
243
|
+
break
|
|
244
|
+
|
|
245
|
+
# Fetch next page
|
|
246
|
+
response = client.get(current_url)
|
|
247
|
+
|
|
248
|
+
if not response.ok:
|
|
249
|
+
# Log error but continue with what we have
|
|
250
|
+
import logging
|
|
251
|
+
logger = logging.getLogger("firecrawl")
|
|
252
|
+
logger.warning("Failed to fetch next page", extra={"status_code": response.status_code})
|
|
253
|
+
break
|
|
254
|
+
|
|
255
|
+
page_data = response.json()
|
|
256
|
+
|
|
257
|
+
if not page_data.get("success"):
|
|
258
|
+
break
|
|
259
|
+
|
|
260
|
+
# Add documents from this page
|
|
261
|
+
data_list = page_data.get("data", [])
|
|
262
|
+
for doc_data in data_list:
|
|
263
|
+
if isinstance(doc_data, str):
|
|
264
|
+
continue
|
|
265
|
+
else:
|
|
266
|
+
# Check max_results limit BEFORE adding each document
|
|
267
|
+
if max_results is not None and len(documents) >= max_results:
|
|
268
|
+
break
|
|
269
|
+
documents.append(Document(**normalize_document_input(doc_data)))
|
|
270
|
+
|
|
271
|
+
# Check if we hit max_results limit
|
|
272
|
+
if max_results is not None and len(documents) >= max_results:
|
|
273
|
+
break
|
|
274
|
+
|
|
275
|
+
# Get next URL
|
|
276
|
+
current_url = page_data.get("next")
|
|
277
|
+
page_count += 1
|
|
278
|
+
|
|
279
|
+
return documents
|
|
280
|
+
|
|
281
|
+
|
|
193
282
|
def cancel_crawl(client: HttpClient, job_id: str) -> bool:
|
|
194
283
|
"""
|
|
195
284
|
Cancel a running crawl job.
|
|
@@ -235,7 +324,7 @@ def wait_for_crawl_completion(
|
|
|
235
324
|
Exception: If the job fails
|
|
236
325
|
TimeoutError: If timeout is reached
|
|
237
326
|
"""
|
|
238
|
-
start_time = time.
|
|
327
|
+
start_time = time.monotonic()
|
|
239
328
|
|
|
240
329
|
while True:
|
|
241
330
|
crawl_job = get_crawl_status(client, job_id)
|
|
@@ -245,7 +334,7 @@ def wait_for_crawl_completion(
|
|
|
245
334
|
return crawl_job
|
|
246
335
|
|
|
247
336
|
# Check timeout
|
|
248
|
-
if timeout and (time.
|
|
337
|
+
if timeout is not None and (time.monotonic() - start_time) > timeout:
|
|
249
338
|
raise TimeoutError(f"Crawl job {job_id} did not complete within {timeout} seconds")
|
|
250
339
|
|
|
251
340
|
# Wait before next poll
|
firecrawl/v2/types.py
CHANGED
|
@@ -278,7 +278,7 @@ class ScrapeOptions(BaseModel):
|
|
|
278
278
|
timeout: Optional[int] = None
|
|
279
279
|
wait_for: Optional[int] = None
|
|
280
280
|
mobile: Optional[bool] = None
|
|
281
|
-
parsers: Optional[List[str]] = None
|
|
281
|
+
parsers: Optional[Union[List[str], List[Union[str, 'PDFParser']]]] = None
|
|
282
282
|
actions: Optional[List[Union['WaitAction', 'ScreenshotAction', 'ClickAction', 'WriteAction', 'PressAction', 'ScrollAction', 'ScrapeAction', 'ExecuteJavascriptAction', 'PDFAction']]] = None
|
|
283
283
|
location: Optional['Location'] = None
|
|
284
284
|
skip_tls_verification: Optional[bool] = None
|
|
@@ -536,6 +536,11 @@ class PDFAction(BaseModel):
|
|
|
536
536
|
landscape: Optional[bool] = None
|
|
537
537
|
scale: Optional[float] = None
|
|
538
538
|
|
|
539
|
+
class PDFParser(BaseModel):
|
|
540
|
+
"""PDF parser configuration with optional page limit."""
|
|
541
|
+
type: Literal["pdf"] = "pdf"
|
|
542
|
+
max_pages: Optional[int] = None
|
|
543
|
+
|
|
539
544
|
# Location types
|
|
540
545
|
class Location(BaseModel):
|
|
541
546
|
"""Location configuration for scraping."""
|
|
@@ -594,6 +599,26 @@ class SearchRequest(BaseModel):
|
|
|
594
599
|
|
|
595
600
|
return normalized_categories
|
|
596
601
|
|
|
602
|
+
@field_validator('parsers')
|
|
603
|
+
@classmethod
|
|
604
|
+
def validate_parsers(cls, v):
|
|
605
|
+
"""Validate and normalize parsers input."""
|
|
606
|
+
if v is None:
|
|
607
|
+
return v
|
|
608
|
+
|
|
609
|
+
normalized_parsers = []
|
|
610
|
+
for parser in v:
|
|
611
|
+
if isinstance(parser, str):
|
|
612
|
+
normalized_parsers.append(parser)
|
|
613
|
+
elif isinstance(parser, dict):
|
|
614
|
+
normalized_parsers.append(PDFParser(**parser))
|
|
615
|
+
elif isinstance(parser, PDFParser):
|
|
616
|
+
normalized_parsers.append(parser)
|
|
617
|
+
else:
|
|
618
|
+
raise ValueError(f"Invalid parser format: {parser}")
|
|
619
|
+
|
|
620
|
+
return normalized_parsers
|
|
621
|
+
|
|
597
622
|
class LinkResult(BaseModel):
|
|
598
623
|
"""A generic link result with optional metadata (used by search and map)."""
|
|
599
624
|
url: str
|
|
@@ -671,6 +696,13 @@ class ClientConfig(BaseModel):
|
|
|
671
696
|
max_retries: int = 3
|
|
672
697
|
backoff_factor: float = 0.5
|
|
673
698
|
|
|
699
|
+
class PaginationConfig(BaseModel):
|
|
700
|
+
"""Configuration for pagination behavior."""
|
|
701
|
+
auto_paginate: bool = True
|
|
702
|
+
max_pages: Optional[int] = Field(default=None, ge=0)
|
|
703
|
+
max_results: Optional[int] = Field(default=None, ge=0)
|
|
704
|
+
max_wait_time: Optional[int] = Field(default=None, ge=0) # seconds
|
|
705
|
+
|
|
674
706
|
# Response union types
|
|
675
707
|
AnyResponse = Union[
|
|
676
708
|
ScrapeResponse,
|
|
@@ -679,4 +711,4 @@ AnyResponse = Union[
|
|
|
679
711
|
MapResponse,
|
|
680
712
|
SearchResponse,
|
|
681
713
|
ErrorResponse,
|
|
682
|
-
]
|
|
714
|
+
]
|
|
@@ -4,6 +4,7 @@ HTTP client utilities for v2 API.
|
|
|
4
4
|
|
|
5
5
|
import time
|
|
6
6
|
from typing import Dict, Any, Optional
|
|
7
|
+
from urllib.parse import urlparse, urlunparse, urljoin
|
|
7
8
|
import requests
|
|
8
9
|
from .get_version import get_version
|
|
9
10
|
|
|
@@ -15,6 +16,28 @@ class HttpClient:
|
|
|
15
16
|
def __init__(self, api_key: str, api_url: str):
|
|
16
17
|
self.api_key = api_key
|
|
17
18
|
self.api_url = api_url
|
|
19
|
+
|
|
20
|
+
def _build_url(self, endpoint: str) -> str:
|
|
21
|
+
base = urlparse(self.api_url)
|
|
22
|
+
ep = urlparse(endpoint)
|
|
23
|
+
|
|
24
|
+
# Absolute or protocol-relative (has netloc)
|
|
25
|
+
if ep.netloc:
|
|
26
|
+
# Different host: keep path/query but force base host/scheme (no token leakage)
|
|
27
|
+
path = ep.path or "/"
|
|
28
|
+
if (ep.hostname or "") != (base.hostname or ""):
|
|
29
|
+
return urlunparse((base.scheme or "https", base.netloc, path, "", ep.query, ""))
|
|
30
|
+
# Same host: normalize scheme to base
|
|
31
|
+
return urlunparse((base.scheme or "https", base.netloc, path, "", ep.query, ""))
|
|
32
|
+
|
|
33
|
+
# Relative (including leading slash or not)
|
|
34
|
+
base_str = self.api_url if self.api_url.endswith("/") else f"{self.api_url}/"
|
|
35
|
+
# Guard protocol-relative like //host/path slipping through as “relative”
|
|
36
|
+
if endpoint.startswith("//"):
|
|
37
|
+
ep2 = urlparse(f"https:{endpoint}")
|
|
38
|
+
path = ep2.path or "/"
|
|
39
|
+
return urlunparse((base.scheme or "https", base.netloc, path, "", ep2.query, ""))
|
|
40
|
+
return urljoin(base_str, endpoint)
|
|
18
41
|
|
|
19
42
|
def _prepare_headers(self, idempotency_key: Optional[str] = None) -> Dict[str, str]:
|
|
20
43
|
"""Prepare headers for API requests."""
|
|
@@ -43,7 +66,7 @@ class HttpClient:
|
|
|
43
66
|
|
|
44
67
|
data['origin'] = f'python-sdk@{version}'
|
|
45
68
|
|
|
46
|
-
url =
|
|
69
|
+
url = self._build_url(endpoint)
|
|
47
70
|
|
|
48
71
|
last_exception = None
|
|
49
72
|
|
|
@@ -84,7 +107,7 @@ class HttpClient:
|
|
|
84
107
|
if headers is None:
|
|
85
108
|
headers = self._prepare_headers()
|
|
86
109
|
|
|
87
|
-
url =
|
|
110
|
+
url = self._build_url(endpoint)
|
|
88
111
|
|
|
89
112
|
last_exception = None
|
|
90
113
|
|
|
@@ -124,7 +147,7 @@ class HttpClient:
|
|
|
124
147
|
if headers is None:
|
|
125
148
|
headers = self._prepare_headers()
|
|
126
149
|
|
|
127
|
-
url =
|
|
150
|
+
url = self._build_url(endpoint)
|
|
128
151
|
|
|
129
152
|
last_exception = None
|
|
130
153
|
|
firecrawl/v2/utils/validation.py
CHANGED
|
@@ -311,6 +311,20 @@ def prepare_scrape_options(options: Optional[ScrapeOptions]) -> Optional[Dict[st
|
|
|
311
311
|
converted_action[action_key] = action_value
|
|
312
312
|
converted_actions.append(converted_action)
|
|
313
313
|
scrape_data["actions"] = converted_actions
|
|
314
|
+
elif key == "parsers":
|
|
315
|
+
converted_parsers = []
|
|
316
|
+
for parser in value:
|
|
317
|
+
if isinstance(parser, str):
|
|
318
|
+
converted_parsers.append(parser)
|
|
319
|
+
elif isinstance(parser, dict):
|
|
320
|
+
converted_parsers.append(parser)
|
|
321
|
+
else:
|
|
322
|
+
parser_data = parser.model_dump(exclude_none=True)
|
|
323
|
+
# Convert snake_case to camelCase for API
|
|
324
|
+
if "max_pages" in parser_data:
|
|
325
|
+
parser_data["maxPages"] = parser_data.pop("max_pages")
|
|
326
|
+
converted_parsers.append(parser_data)
|
|
327
|
+
scrape_data["parsers"] = converted_parsers
|
|
314
328
|
elif key == "location":
|
|
315
329
|
# Handle location conversion
|
|
316
330
|
if isinstance(value, dict):
|
|
@@ -321,4 +335,4 @@ def prepare_scrape_options(options: Optional[ScrapeOptions]) -> Optional[Dict[st
|
|
|
321
335
|
# For fields that don't need conversion, use as-is
|
|
322
336
|
scrape_data[key] = value
|
|
323
337
|
|
|
324
|
-
return scrape_data
|
|
338
|
+
return scrape_data
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
firecrawl/__init__.py,sha256=
|
|
1
|
+
firecrawl/__init__.py,sha256=BT5Sx5lBRhzEEFNivjIhZaBA8kAeZCPFixbO9n8Myxw,2192
|
|
2
2
|
firecrawl/client.py,sha256=tp3mUo_3aGPuZ53kpU4bhM-5EtwD_IUWrJ7wm0GMuCc,11159
|
|
3
3
|
firecrawl/firecrawl.backup.py,sha256=v1FEN3jR4g5Aupg4xp6SLkuFvYMQuUKND2YELbYjE6c,200430
|
|
4
4
|
firecrawl/types.py,sha256=W9N2pqQuevEIIjYHN9rbDf31E-nwdCECqIn11Foz2T8,2836
|
|
5
5
|
firecrawl/__tests__/e2e/v2/conftest.py,sha256=I28TUpN5j0-9gM79NlbrDS8Jlsheao657od2f-2xK0Y,2587
|
|
6
6
|
firecrawl/__tests__/e2e/v2/test_async.py,sha256=ZXpf1FVOJgNclITglrxIyFwP4cOiqzWLicGaxIm70BQ,2526
|
|
7
7
|
firecrawl/__tests__/e2e/v2/test_batch_scrape.py,sha256=H9GtuwHIFdOQ958SOVThi_kvDDxcXAK_ECRh95ogonQ,3265
|
|
8
|
-
firecrawl/__tests__/e2e/v2/test_crawl.py,sha256=
|
|
8
|
+
firecrawl/__tests__/e2e/v2/test_crawl.py,sha256=fPbUZIKVtjENo8Mh4HyrwCVuqtNfn3Q1JrETufI27z4,9947
|
|
9
9
|
firecrawl/__tests__/e2e/v2/test_extract.py,sha256=HgvGiDlyWtFygiPo5EP44Dem1oWrwgRF-hfc1LfeVSU,1670
|
|
10
10
|
firecrawl/__tests__/e2e/v2/test_map.py,sha256=9sT-Yq8V_8c9esl_bv5hnTA9WXb2Dg81kj6M-s0484c,1618
|
|
11
11
|
firecrawl/__tests__/e2e/v2/test_scrape.py,sha256=oyroF_WaEdxgD8t_SHkLBBfDRv1_6xZ_7vSTQpwlmA8,7198
|
|
@@ -25,6 +25,7 @@ firecrawl/__tests__/unit/v2/methods/test_crawl_params.py,sha256=p9hzg14uAs1iHKXP
|
|
|
25
25
|
firecrawl/__tests__/unit/v2/methods/test_crawl_request_preparation.py,sha256=PEKbooNXfQwPpvcPHXABJnveztgAA-RFBhtlSs8uPro,8780
|
|
26
26
|
firecrawl/__tests__/unit/v2/methods/test_crawl_validation.py,sha256=kErOmHSD01eMjXiMd4rgsMVGd_aU2G9uVymBjbAFoGw,3918
|
|
27
27
|
firecrawl/__tests__/unit/v2/methods/test_map_request_preparation.py,sha256=toVcgnMp_cFeYsIUuyKGEWZGp0nAAkzaeFGUbY0zY0o,1868
|
|
28
|
+
firecrawl/__tests__/unit/v2/methods/test_pagination.py,sha256=wNc9UtdauII_jzsjlJh645NBRq4IbQij1NeBwbyTjBU,22463
|
|
28
29
|
firecrawl/__tests__/unit/v2/methods/test_scrape_request_preparation.py,sha256=wDOslsA5BN4kyezlaT5GeMv_Ifn8f461EaA7i5ujnaQ,3482
|
|
29
30
|
firecrawl/__tests__/unit/v2/methods/test_search_request_preparation.py,sha256=14lUgFpQsiosgMKjDustBRVE0zXnHujBI76F8BC5PZ4,6072
|
|
30
31
|
firecrawl/__tests__/unit/v2/methods/test_search_validation.py,sha256=7UGcNHpQzCpZbAPYjthfdPFWmAPcoApY-ED-khtuANs,9498
|
|
@@ -43,21 +44,21 @@ firecrawl/__tests__/unit/v2/watcher/test_ws_watcher.py,sha256=87w47n0iOihtu4jTR4
|
|
|
43
44
|
firecrawl/v1/__init__.py,sha256=aP1oisPeZVGGZynvENc07JySMOZfv_4zAlxQ0ecMJXA,481
|
|
44
45
|
firecrawl/v1/client.py,sha256=sydurfEFTsXyowyaGryA1lkPxN_r9Nf6iQpM43OwJyM,201672
|
|
45
46
|
firecrawl/v2/__init__.py,sha256=Jc6a8tBjYG5OPkjDM5pl-notyys-7DEj7PLEfepv3fc,137
|
|
46
|
-
firecrawl/v2/client.py,sha256=
|
|
47
|
-
firecrawl/v2/client_async.py,sha256=
|
|
48
|
-
firecrawl/v2/types.py,sha256=
|
|
47
|
+
firecrawl/v2/client.py,sha256=AMAHQ8Uz9bsEIy2vmIDNNUIT0FOivhLyj6lesEr1Rbg,31260
|
|
48
|
+
firecrawl/v2/client_async.py,sha256=XyzojIJlWatBGlAMish22H-XHkkH9zHsD6MGtAdtFg8,10487
|
|
49
|
+
firecrawl/v2/types.py,sha256=YnbEmskB4eyfSIBDQK_Kv6xNjID3McagGEoIUiIIbL8,23840
|
|
49
50
|
firecrawl/v2/watcher.py,sha256=FOU71tqSKxgeuGycu4ye0SLc2dw7clIcoQjPsi-4Csc,14229
|
|
50
51
|
firecrawl/v2/watcher_async.py,sha256=AVjW2mgABniolSsauK4u0FW8ya6WzRUdyEg2R-8vGCw,10278
|
|
51
|
-
firecrawl/v2/methods/batch.py,sha256=
|
|
52
|
-
firecrawl/v2/methods/crawl.py,sha256=
|
|
52
|
+
firecrawl/v2/methods/batch.py,sha256=jFSIPtvulUrPz3Y3zT1gDNwYEf8Botpfh4GOeYsVYRI,14852
|
|
53
|
+
firecrawl/v2/methods/crawl.py,sha256=DWH1wUUDpE0zPSRALkQj_vF-PdsT0A1NyAGtnfcDaR8,18634
|
|
53
54
|
firecrawl/v2/methods/extract.py,sha256=-Jr4BtraU3b7hd3JIY73V-S69rUclxyXyUpoQb6DCQk,4274
|
|
54
55
|
firecrawl/v2/methods/map.py,sha256=4SADb0-lkbdOWDmO6k8_TzK0yRti5xsN40N45nUl9uA,2592
|
|
55
56
|
firecrawl/v2/methods/scrape.py,sha256=CSHBwC-P91UfrW3zHirjNAs2h899FKcWvd1DY_4fJdo,1921
|
|
56
57
|
firecrawl/v2/methods/search.py,sha256=6BKiQ1aKJjWBKm9BBtKxFKGD74kCKBeMIp_OgjcDFAw,7673
|
|
57
58
|
firecrawl/v2/methods/usage.py,sha256=OJlkxwaB-AAtgO3WLr9QiqBRmjdh6GVhroCgleegupQ,1460
|
|
58
59
|
firecrawl/v2/methods/aio/__init__.py,sha256=RocMJnGwnLIvGu3G8ZvY8INkipC7WHZiu2bE31eSyJs,35
|
|
59
|
-
firecrawl/v2/methods/aio/batch.py,sha256=
|
|
60
|
-
firecrawl/v2/methods/aio/crawl.py,sha256=
|
|
60
|
+
firecrawl/v2/methods/aio/batch.py,sha256=4Uj05ffpMhQA2J_mkvHYYogdXb0IgbKGbomO43b4m94,6741
|
|
61
|
+
firecrawl/v2/methods/aio/crawl.py,sha256=j2Tb2AcGsT6bCiUbB2yjrfvGZqkinUt0tU-SzWmB7Jw,11551
|
|
61
62
|
firecrawl/v2/methods/aio/extract.py,sha256=IfNr2ETqt4dR73JFzrEYI4kk5vpKnJOG0BmPEjGEoO4,4217
|
|
62
63
|
firecrawl/v2/methods/aio/map.py,sha256=EuT-5A0cQr_e5SBfEZ6pnl8u0JUwEEvSwhyT2N-QoKU,2326
|
|
63
64
|
firecrawl/v2/methods/aio/scrape.py,sha256=ilA9qco8YGwCFpE0PN1XBQUyuHPQwH2QioZ-xsfxhgU,1386
|
|
@@ -66,14 +67,14 @@ firecrawl/v2/methods/aio/usage.py,sha256=OtBi6X-aT09MMR2dpm3vBCm9JrJZIJLCQ8jJ3L7
|
|
|
66
67
|
firecrawl/v2/utils/__init__.py,sha256=i1GgxySmqEXpWSBQCu3iZBPIJG7fXj0QXCDWGwerWNs,338
|
|
67
68
|
firecrawl/v2/utils/error_handler.py,sha256=Iuf916dHphDY8ObNNlWy75628DFeJ0Rv8ljRp4LttLE,4199
|
|
68
69
|
firecrawl/v2/utils/get_version.py,sha256=0CxW_41q2hlzIxEWOivUCaYw3GFiSIH32RPUMcIgwAY,492
|
|
69
|
-
firecrawl/v2/utils/http_client.py,sha256=
|
|
70
|
+
firecrawl/v2/utils/http_client.py,sha256=gUrC1CvU5sj03w27Lbq-3-yH38Yi_OXiI01-piwA83w,6027
|
|
70
71
|
firecrawl/v2/utils/http_client_async.py,sha256=iy89_bk2HS3afSRHZ8016eMCa9Fk-5MFTntcOHfbPgE,1936
|
|
71
72
|
firecrawl/v2/utils/normalize.py,sha256=nlTU6QRghT1YKZzNZlIQj4STSRuSUGrS9cCErZIcY5w,3636
|
|
72
|
-
firecrawl/v2/utils/validation.py,sha256=
|
|
73
|
-
firecrawl-
|
|
73
|
+
firecrawl/v2/utils/validation.py,sha256=qWWiWaVcvODmVxf9rxIVy1j_dyuJCvdMMUoYhvWUEIU,15269
|
|
74
|
+
firecrawl-4.1.0.dist-info/licenses/LICENSE,sha256=nPCunEDwjRGHlmjvsiDUyIWbkqqyj3Ej84ntnh0g0zA,1084
|
|
74
75
|
tests/test_change_tracking.py,sha256=_IJ5ShLcoj2fHDBaw-nE4I4lHdmDB617ocK_XMHhXps,4177
|
|
75
76
|
tests/test_timeout_conversion.py,sha256=PWlIEMASQNhu4cp1OW_ebklnE9NCiigPnEFCtI5N3w0,3996
|
|
76
|
-
firecrawl-
|
|
77
|
-
firecrawl-
|
|
78
|
-
firecrawl-
|
|
79
|
-
firecrawl-
|
|
77
|
+
firecrawl-4.1.0.dist-info/METADATA,sha256=IFmGv9ChnRIoKksvP9RebpAcqm8c5-SHZhN8LrF04l4,7392
|
|
78
|
+
firecrawl-4.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
79
|
+
firecrawl-4.1.0.dist-info/top_level.txt,sha256=8T3jOaSN5mtLghO-R3MQ8KO290gIX8hmfxQmglBPdLE,16
|
|
80
|
+
firecrawl-4.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|