webcrawlerapi 2.0.7__tar.gz → 2.0.9__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.0.7
3
+ Version: 2.0.9
4
4
  Summary: Python SDK for WebCrawler API
5
5
  Home-page: https://github.com/webcrawlerapi/webcrawlerapi-python-sdk
6
6
  Author: Andrew
@@ -124,6 +124,8 @@ Starts a new crawling job and waits for its completion. This method will continu
124
124
  ### crawl_async()
125
125
  Starts a new crawling job and returns immediately with a job ID. Use this when you want to handle polling and status checks yourself, or when using webhooks.
126
126
 
127
+ Use `crawl_raw_markdown()` when you need the combined `/job/{id}/markdown` output after a crawl finishes.
128
+
127
129
  ### get_job()
128
130
  Retrieves the current status and details of a specific job.
129
131
 
@@ -103,6 +103,8 @@ Starts a new crawling job and waits for its completion. This method will continu
103
103
  ### crawl_async()
104
104
  Starts a new crawling job and returns immediately with a job ID. Use this when you want to handle polling and status checks yourself, or when using webhooks.
105
105
 
106
+ Use `crawl_raw_markdown()` when you need the combined `/job/{id}/markdown` output after a crawl finishes.
107
+
106
108
  ### get_job()
107
109
  Retrieves the current status and details of a specific job.
108
110
 
@@ -181,4 +183,4 @@ Each JobItem object represents a crawled page and contains:
181
183
 
182
184
  ## License
183
185
 
184
- MIT License
186
+ MIT License
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="webcrawlerapi",
5
- version="2.0.7",
5
+ version="2.0.9",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "requests>=2.25.0",
@@ -50,6 +50,7 @@ class WebCrawlerAPI:
50
50
  actions: Optional[Union[Action, List[Action]]] = None,
51
51
  respect_robots_txt: bool = False,
52
52
  main_content_only: bool = False,
53
+ max_depth: Optional[int] = None,
53
54
  ) -> CrawlResponse:
54
55
  """
55
56
  Start a new crawling job asynchronously.
@@ -65,6 +66,7 @@ class WebCrawlerAPI:
65
66
  actions (Action or List[Action], optional): Actions to perform during crawling
66
67
  respect_robots_txt (bool): Whether to respect robots.txt file (default: False)
67
68
  main_content_only (bool): Whether to extract only main content (default: False)
69
+ max_depth (int, optional): Maximum depth of crawl (0 for seed URL only, 1 for one level deep, etc.)
68
70
 
69
71
  Returns:
70
72
  CrawlResponse: Response containing the job ID
@@ -87,6 +89,8 @@ class WebCrawlerAPI:
87
89
  payload["whitelist_regexp"] = whitelist_regexp
88
90
  if blacklist_regexp:
89
91
  payload["blacklist_regexp"] = blacklist_regexp
92
+ if max_depth is not None:
93
+ payload["max_depth"] = max_depth
90
94
  if actions:
91
95
  # Convert single action to list if needed
92
96
  action_list = [actions] if not isinstance(actions, list) else actions
@@ -118,6 +122,42 @@ class WebCrawlerAPI:
118
122
  response.raise_for_status()
119
123
  return Job(response.json())
120
124
 
125
+ def get_job_markdown(self, job_id: str) -> str:
126
+ """
127
+ Get combined markdown content for a completed markdown job.
128
+
129
+ Args:
130
+ job_id (str): The unique identifier of the job
131
+
132
+ Returns:
133
+ str: Combined markdown content
134
+
135
+ Raises:
136
+ requests.exceptions.RequestException: If the API request fails
137
+ """
138
+ response = self.session.get(
139
+ urljoin(self.base_url, f"/{CRAWLER_VERSION}/job/{job_id}/markdown")
140
+ )
141
+
142
+ if not response.ok:
143
+ try:
144
+ error_payload = response.json()
145
+ detail = (
146
+ error_payload.get("message")
147
+ or error_payload.get("error_message")
148
+ or error_payload.get("error")
149
+ )
150
+ except ValueError:
151
+ detail = response.text
152
+
153
+ try:
154
+ response.raise_for_status()
155
+ except requests.exceptions.HTTPError as exc:
156
+ raise requests.exceptions.HTTPError(f"{exc}: {detail}") from exc
157
+
158
+ response.raise_for_status()
159
+ return response.text
160
+
121
161
  def cancel_job(self, job_id: str) -> Dict[str, str]:
122
162
  """
123
163
  Cancel a running job. All items that are not in progress and not done
@@ -150,6 +190,7 @@ class WebCrawlerAPI:
150
190
  actions: Optional[Union[Action, List[Action]]] = None,
151
191
  respect_robots_txt: bool = False,
152
192
  main_content_only: bool = False,
193
+ max_depth: Optional[int] = None,
153
194
  max_polls: int = 100,
154
195
  ) -> Job:
155
196
  """
@@ -170,6 +211,7 @@ class WebCrawlerAPI:
170
211
  actions (Action or List[Action], optional): Actions to perform during crawling
171
212
  respect_robots_txt (bool): Whether to respect robots.txt file (default: False)
172
213
  main_content_only (bool): Whether to extract only main content (default: False)
214
+ max_depth (int, optional): Maximum depth of crawl (0 for seed URL only, 1 for one level deep, etc.)
173
215
  max_polls (int): Maximum number of status checks before returning (default: 100)
174
216
 
175
217
  Returns:
@@ -190,6 +232,7 @@ class WebCrawlerAPI:
190
232
  actions=actions,
191
233
  respect_robots_txt=respect_robots_txt,
192
234
  main_content_only=main_content_only,
235
+ max_depth=max_depth,
193
236
  )
194
237
 
195
238
  job_id = response.id
@@ -215,6 +258,54 @@ class WebCrawlerAPI:
215
258
  # Return the last known state if max_polls is reached
216
259
  return job
217
260
 
261
+ def crawl_raw_markdown(
262
+ self,
263
+ url: str,
264
+ scrape_type: str = "markdown",
265
+ items_limit: int = 10,
266
+ webhook_url: Optional[str] = None,
267
+ allow_subdomains: bool = False,
268
+ whitelist_regexp: Optional[str] = None,
269
+ blacklist_regexp: Optional[str] = None,
270
+ actions: Optional[Union[Action, List[Action]]] = None,
271
+ respect_robots_txt: bool = False,
272
+ main_content_only: bool = False,
273
+ max_depth: Optional[int] = None,
274
+ max_polls: int = 100,
275
+ ) -> str:
276
+ """
277
+ Run a crawl job and return the combined markdown output when finished.
278
+
279
+ Raises:
280
+ requests.exceptions.RequestException: If any API request fails
281
+ """
282
+ job = self.crawl(
283
+ url=url,
284
+ scrape_type=scrape_type,
285
+ items_limit=items_limit,
286
+ webhook_url=webhook_url,
287
+ allow_subdomains=allow_subdomains,
288
+ whitelist_regexp=whitelist_regexp,
289
+ blacklist_regexp=blacklist_regexp,
290
+ actions=actions,
291
+ respect_robots_txt=respect_robots_txt,
292
+ main_content_only=main_content_only,
293
+ max_depth=max_depth,
294
+ max_polls=max_polls,
295
+ )
296
+
297
+ if job.scrape_type != "markdown":
298
+ raise requests.exceptions.HTTPError(
299
+ "crawl_raw_markdown requires scrape_type to be markdown"
300
+ )
301
+
302
+ if job.status != "done":
303
+ raise requests.exceptions.HTTPError(
304
+ f"Job finished with status {job.status}"
305
+ )
306
+
307
+ return self.get_job_markdown(job.id)
308
+
218
309
  def scrape_async(
219
310
  self,
220
311
  url: str,
@@ -125,6 +125,7 @@ class JobItem:
125
125
  self.referred_url: Optional[str] = data.get("referred_url")
126
126
  self.last_error: Optional[str] = data.get("last_error")
127
127
  self.error_code: Optional[str] = data.get("error_code")
128
+ self.depth: Optional[int] = data.get("depth")
128
129
 
129
130
  # Optional content URLs based on scrape_type
130
131
  self.raw_content_url: Optional[str] = data.get("raw_content_url")
@@ -201,6 +202,7 @@ class Job:
201
202
  self.blacklist_regexp: Optional[str] = data.get("blacklist_regexp")
202
203
  self.allow_subdomains: bool = data.get("allow_subdomains", False)
203
204
  self.items_limit: int = data["items_limit"]
205
+ self.max_depth: Optional[int] = data.get("max_depth")
204
206
  self.created_at: datetime = parse_datetime(data["created_at"])
205
207
  self.updated_at: datetime = parse_datetime(data["updated_at"])
206
208
  self.webhook_url: Optional[str] = data.get("webhook_url")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webcrawlerapi
3
- Version: 2.0.7
3
+ Version: 2.0.9
4
4
  Summary: Python SDK for WebCrawler API
5
5
  Home-page: https://github.com/webcrawlerapi/webcrawlerapi-python-sdk
6
6
  Author: Andrew
@@ -124,6 +124,8 @@ Starts a new crawling job and waits for its completion. This method will continu
124
124
  ### crawl_async()
125
125
  Starts a new crawling job and returns immediately with a job ID. Use this when you want to handle polling and status checks yourself, or when using webhooks.
126
126
 
127
+ Use `crawl_raw_markdown()` when you need the combined `/job/{id}/markdown` output after a crawl finishes.
128
+
127
129
  ### get_job()
128
130
  Retrieves the current status and details of a specific job.
129
131
 
File without changes