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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webcrawlerapi
3
- Version: 2.1.2
3
+ Version: 2.1.5
4
4
  Summary: Python SDK for WebCrawler API
5
5
  Home-page: https://github.com/webcrawlerapi/webcrawlerapi-python-sdk
6
6
  Author: Andrew
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="webcrawlerapi",
5
- version="2.1.2",
5
+ version="2.1.5",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "requests>=2.25.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."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webcrawlerapi
3
- Version: 2.1.2
3
+ Version: 2.1.5
4
4
  Summary: Python SDK for WebCrawler API
5
5
  Home-page: https://github.com/webcrawlerapi/webcrawlerapi-python-sdk
6
6
  Author: Andrew
File without changes
File without changes