webcrawlerapi 2.1.2__tar.gz → 2.1.5__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.
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/PKG-INFO +1 -1
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/setup.py +1 -1
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/tests/test_client.py +0 -32
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/webcrawlerapi/__init__.py +2 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/webcrawlerapi/client.py +26 -10
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/webcrawlerapi/models.py +8 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/webcrawlerapi.egg-info/PKG-INFO +1 -1
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/README.md +0 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/pyproject.toml +0 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/setup.cfg +0 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/tests/__init__.py +0 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/tests/test_models.py +0 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/webcrawlerapi.egg-info/SOURCES.txt +0 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/webcrawlerapi.egg-info/dependency_links.txt +0 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/webcrawlerapi.egg-info/requires.txt +0 -0
- {webcrawlerapi-2.1.2 → webcrawlerapi-2.1.5}/webcrawlerapi.egg-info/top_level.txt +0 -0
|
@@ -13,7 +13,6 @@ from webcrawlerapi.models import (
|
|
|
13
13
|
ScrapeId,
|
|
14
14
|
ScrapeResponse,
|
|
15
15
|
ScrapeResponseError,
|
|
16
|
-
UploadS3Action,
|
|
17
16
|
WebCrawlerApiError,
|
|
18
17
|
)
|
|
19
18
|
|
|
@@ -99,37 +98,6 @@ class TestWebCrawlerAPI:
|
|
|
99
98
|
assert payload["items_limit"] == 5
|
|
100
99
|
assert payload["respect_robots_txt"] is True
|
|
101
100
|
|
|
102
|
-
@responses.activate
|
|
103
|
-
def test_crawl_async_with_actions(self, client):
|
|
104
|
-
"""Test crawl_async with S3 upload action."""
|
|
105
|
-
responses.add(
|
|
106
|
-
responses.POST,
|
|
107
|
-
"https://api.test.com/v1/crawl",
|
|
108
|
-
json={"id": "crawl-456"},
|
|
109
|
-
status=200,
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
s3_action = UploadS3Action(
|
|
113
|
-
path="crawl-results/",
|
|
114
|
-
access_key_id="AKIAEXAMPLE",
|
|
115
|
-
secret_access_key="secret123",
|
|
116
|
-
bucket="my-bucket",
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
result = client.crawl_async(url="https://example.com", actions=[s3_action])
|
|
120
|
-
|
|
121
|
-
assert result.id == "crawl-456"
|
|
122
|
-
|
|
123
|
-
# Verify action in payload
|
|
124
|
-
request = responses.calls[0].request
|
|
125
|
-
import json
|
|
126
|
-
|
|
127
|
-
payload = json.loads(request.body)
|
|
128
|
-
assert "actions" in payload
|
|
129
|
-
assert len(payload["actions"]) == 1
|
|
130
|
-
assert payload["actions"][0]["type"] == "upload_s3"
|
|
131
|
-
assert payload["actions"][0]["bucket"] == "my-bucket"
|
|
132
|
-
|
|
133
101
|
@responses.activate
|
|
134
102
|
def test_crawl_async_with_max_age(self, client):
|
|
135
103
|
"""Test crawl_async includes max_age when provided."""
|
|
@@ -30,6 +30,7 @@ from .models import (
|
|
|
30
30
|
Job,
|
|
31
31
|
JobItem,
|
|
32
32
|
JobMarkdownResponse,
|
|
33
|
+
MarkdownResponse,
|
|
33
34
|
ScrapeId,
|
|
34
35
|
ScrapeResponse,
|
|
35
36
|
ScrapeResponseError,
|
|
@@ -44,6 +45,7 @@ __all__ = [
|
|
|
44
45
|
"Job",
|
|
45
46
|
"JobItem",
|
|
46
47
|
"JobMarkdownResponse",
|
|
48
|
+
"MarkdownResponse",
|
|
47
49
|
"CrawlResponse",
|
|
48
50
|
"ScrapeId",
|
|
49
51
|
"ScrapeResponse",
|
|
@@ -10,6 +10,7 @@ from .models import (
|
|
|
10
10
|
CrawlResponse,
|
|
11
11
|
Job,
|
|
12
12
|
JobMarkdownResponse,
|
|
13
|
+
MarkdownResponse,
|
|
13
14
|
ScrapeId,
|
|
14
15
|
ScrapeResponse,
|
|
15
16
|
ScrapeResponseError,
|
|
@@ -68,7 +69,6 @@ class WebCrawlerAPI:
|
|
|
68
69
|
webhook_url: Optional[str] = None,
|
|
69
70
|
whitelist_regexp: Optional[str] = None,
|
|
70
71
|
blacklist_regexp: Optional[str] = None,
|
|
71
|
-
actions: Optional[Union[Action, List[Action]]] = None,
|
|
72
72
|
respect_robots_txt: bool = False,
|
|
73
73
|
main_content_only: bool = False,
|
|
74
74
|
max_depth: Optional[int] = None,
|
|
@@ -87,7 +87,6 @@ class WebCrawlerAPI:
|
|
|
87
87
|
webhook_url (str, optional): URL for webhook notifications
|
|
88
88
|
whitelist_regexp (str, optional): Regex pattern for URL whitelist
|
|
89
89
|
blacklist_regexp (str, optional): Regex pattern for URL blacklist
|
|
90
|
-
actions (Action or List[Action], optional): Actions to perform during crawling
|
|
91
90
|
respect_robots_txt (bool): Whether to respect robots.txt (default: False)
|
|
92
91
|
main_content_only (bool): Whether to extract only main content (default: False)
|
|
93
92
|
max_depth (int, optional): Maximum crawl depth (0 = seed only, 1 = seed + direct links)
|
|
@@ -131,9 +130,6 @@ class WebCrawlerAPI:
|
|
|
131
130
|
payload["main_content_only"] = main_content_only
|
|
132
131
|
if keep_query_params is not None:
|
|
133
132
|
payload["keep_query_params"] = keep_query_params
|
|
134
|
-
if actions:
|
|
135
|
-
action_list = [actions] if not isinstance(actions, list) else actions
|
|
136
|
-
payload["actions"] = [vars(action) for action in action_list]
|
|
137
133
|
|
|
138
134
|
response = self.session.post(
|
|
139
135
|
urljoin(self.base_url, f"/{CRAWLER_VERSION}/crawl"), json=payload
|
|
@@ -206,6 +202,31 @@ class WebCrawlerAPI:
|
|
|
206
202
|
self._raise_for_error(response)
|
|
207
203
|
return response.text
|
|
208
204
|
|
|
205
|
+
def markdown(self, url: str) -> MarkdownResponse:
|
|
206
|
+
"""
|
|
207
|
+
Extract cleaned article markdown (main content only) from a webpage.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
url (str): The URL of the webpage to extract the article markdown from
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
MarkdownResponse: Response containing the extracted markdown
|
|
214
|
+
|
|
215
|
+
Raises:
|
|
216
|
+
WebCrawlerApiError: If the API returns an error response
|
|
217
|
+
requests.exceptions.RequestException: If the HTTP request fails
|
|
218
|
+
"""
|
|
219
|
+
response = self.session.post(
|
|
220
|
+
urljoin(self.base_url, "/markdown"),
|
|
221
|
+
json={"url": url},
|
|
222
|
+
)
|
|
223
|
+
if not response.ok:
|
|
224
|
+
self._raise_for_error(response)
|
|
225
|
+
data = response.json()
|
|
226
|
+
return MarkdownResponse(
|
|
227
|
+
success=data.get("success", True), markdown=data.get("markdown")
|
|
228
|
+
)
|
|
229
|
+
|
|
209
230
|
def cancel_job(self, job_id: str) -> Dict[str, str]:
|
|
210
231
|
"""
|
|
211
232
|
Cancel a running job. All items that are not in progress and not done
|
|
@@ -237,7 +258,6 @@ class WebCrawlerAPI:
|
|
|
237
258
|
webhook_url: Optional[str] = None,
|
|
238
259
|
whitelist_regexp: Optional[str] = None,
|
|
239
260
|
blacklist_regexp: Optional[str] = None,
|
|
240
|
-
actions: Optional[Union[Action, List[Action]]] = None,
|
|
241
261
|
respect_robots_txt: bool = False,
|
|
242
262
|
main_content_only: bool = False,
|
|
243
263
|
max_depth: Optional[int] = None,
|
|
@@ -256,7 +276,6 @@ class WebCrawlerAPI:
|
|
|
256
276
|
webhook_url (str, optional): URL for webhook notifications
|
|
257
277
|
whitelist_regexp (str, optional): Regex pattern for URL whitelist
|
|
258
278
|
blacklist_regexp (str, optional): Regex pattern for URL blacklist
|
|
259
|
-
actions (Action or List[Action], optional): Actions to perform during crawling
|
|
260
279
|
respect_robots_txt (bool): Whether to respect robots.txt (default: False)
|
|
261
280
|
main_content_only (bool): Whether to extract only main content (default: False)
|
|
262
281
|
max_depth (int, optional): Maximum crawl depth
|
|
@@ -279,7 +298,6 @@ class WebCrawlerAPI:
|
|
|
279
298
|
webhook_url=webhook_url,
|
|
280
299
|
whitelist_regexp=whitelist_regexp,
|
|
281
300
|
blacklist_regexp=blacklist_regexp,
|
|
282
|
-
actions=actions,
|
|
283
301
|
respect_robots_txt=respect_robots_txt,
|
|
284
302
|
main_content_only=main_content_only,
|
|
285
303
|
max_depth=max_depth,
|
|
@@ -315,7 +333,6 @@ class WebCrawlerAPI:
|
|
|
315
333
|
webhook_url: Optional[str] = None,
|
|
316
334
|
whitelist_regexp: Optional[str] = None,
|
|
317
335
|
blacklist_regexp: Optional[str] = None,
|
|
318
|
-
actions: Optional[Union[Action, List[Action]]] = None,
|
|
319
336
|
respect_robots_txt: bool = False,
|
|
320
337
|
main_content_only: bool = False,
|
|
321
338
|
max_depth: Optional[int] = None,
|
|
@@ -340,7 +357,6 @@ class WebCrawlerAPI:
|
|
|
340
357
|
webhook_url=webhook_url,
|
|
341
358
|
whitelist_regexp=whitelist_regexp,
|
|
342
359
|
blacklist_regexp=blacklist_regexp,
|
|
343
|
-
actions=actions,
|
|
344
360
|
respect_robots_txt=respect_robots_txt,
|
|
345
361
|
main_content_only=main_content_only,
|
|
346
362
|
max_depth=max_depth,
|
|
@@ -62,6 +62,14 @@ class JobMarkdownResponse:
|
|
|
62
62
|
content_url: str
|
|
63
63
|
|
|
64
64
|
|
|
65
|
+
@dataclass
|
|
66
|
+
class MarkdownResponse:
|
|
67
|
+
"""Response from the markdown endpoint."""
|
|
68
|
+
|
|
69
|
+
success: bool
|
|
70
|
+
markdown: Optional[str] = None
|
|
71
|
+
|
|
72
|
+
|
|
65
73
|
@dataclass
|
|
66
74
|
class ScrapeId:
|
|
67
75
|
"""Response from an asynchronous scrape request."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|