strands-apify 0.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.
@@ -0,0 +1,58 @@
1
+ """Apify web scraping, social media, search and crawling tools for Strands Agents SDK."""
2
+
3
+ from .core import (
4
+ APIFY_CORE_TOOLS,
5
+ apify_get_dataset_items,
6
+ apify_run_actor,
7
+ apify_run_actor_and_get_dataset,
8
+ apify_run_task,
9
+ apify_run_task_and_get_dataset,
10
+ apify_scrape_url,
11
+ )
12
+ from .search_crawling import (
13
+ APIFY_SEARCH_TOOLS,
14
+ apify_ecommerce_scraper,
15
+ apify_google_places_scraper,
16
+ apify_google_search_scraper,
17
+ apify_website_content_crawler,
18
+ apify_youtube_scraper,
19
+ )
20
+ from .social_media import (
21
+ APIFY_SOCIAL_TOOLS,
22
+ apify_facebook_posts_scraper,
23
+ apify_instagram_scraper,
24
+ apify_linkedin_profile_detail,
25
+ apify_linkedin_profile_posts,
26
+ apify_linkedin_profile_search,
27
+ apify_tiktok_scraper,
28
+ apify_twitter_scraper,
29
+ )
30
+ from .utils import ApifyToolClient
31
+
32
+ APIFY_ALL_TOOLS = APIFY_CORE_TOOLS + APIFY_SOCIAL_TOOLS + APIFY_SEARCH_TOOLS
33
+
34
+ __all__ = [
35
+ "APIFY_ALL_TOOLS",
36
+ "APIFY_CORE_TOOLS",
37
+ "APIFY_SEARCH_TOOLS",
38
+ "APIFY_SOCIAL_TOOLS",
39
+ "ApifyToolClient",
40
+ "apify_ecommerce_scraper",
41
+ "apify_facebook_posts_scraper",
42
+ "apify_get_dataset_items",
43
+ "apify_google_places_scraper",
44
+ "apify_google_search_scraper",
45
+ "apify_instagram_scraper",
46
+ "apify_linkedin_profile_detail",
47
+ "apify_linkedin_profile_posts",
48
+ "apify_linkedin_profile_search",
49
+ "apify_run_actor",
50
+ "apify_run_actor_and_get_dataset",
51
+ "apify_run_task",
52
+ "apify_run_task_and_get_dataset",
53
+ "apify_scrape_url",
54
+ "apify_tiktok_scraper",
55
+ "apify_twitter_scraper",
56
+ "apify_website_content_crawler",
57
+ "apify_youtube_scraper",
58
+ ]
strands_apify/core.py ADDED
@@ -0,0 +1,331 @@
1
+ """Core Apify platform tools for Strands Agents.
2
+
3
+ Available Tools:
4
+ ---------------
5
+ - apify_run_actor: Run any Apify Actor with custom input
6
+ - apify_get_dataset_items: Fetch items from an Apify dataset with pagination
7
+ - apify_run_actor_and_get_dataset: Run an Actor and fetch results in one step
8
+ - apify_run_task: Run a saved Actor task with optional input overrides
9
+ - apify_run_task_and_get_dataset: Run a task and fetch results in one step
10
+ - apify_scrape_url: Scrape a single URL and return content as Markdown
11
+ """
12
+
13
+ import json
14
+ from typing import Any
15
+
16
+ from strands import tool
17
+
18
+ from .utils import (
19
+ DEFAULT_DATASET_ITEMS_LIMIT,
20
+ DEFAULT_SCRAPE_TIMEOUT_SECS,
21
+ DEFAULT_TIMEOUT_SECS,
22
+ ApifyToolClient,
23
+ CrawlerType,
24
+ _check_dependency,
25
+ _error_result,
26
+ _success_result,
27
+ )
28
+
29
+
30
+ @tool
31
+ def apify_run_actor(
32
+ actor_id: str,
33
+ run_input: dict[str, Any] | None = None,
34
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
35
+ memory_mbytes: int | None = None,
36
+ build: str | None = None,
37
+ ) -> dict[str, Any]:
38
+ """Run any Apify Actor and return the run metadata as JSON.
39
+
40
+ An Actor is a serverless cloud app on the Apify platform - it takes JSON input,
41
+ runs the scraping or automation job, and writes results to a dataset. This tool
42
+ executes the Actor synchronously and returns run metadata only (run_id, status,
43
+ dataset_id, timestamps). Use apify_run_actor_and_get_dataset to also fetch the
44
+ output data in one call, or apify_scrape_url for quick single-URL extraction.
45
+
46
+ Common Actors:
47
+ - "apify/website-content-crawler" - scrape websites and extract content as Markdown
48
+ - "apify/web-scraper" - general-purpose web scraper with JS rendering
49
+ - "apify/google-search-scraper" - scrape Google search results
50
+
51
+ Args:
52
+ actor_id: Actor identifier in "username/actor-name" format,
53
+ e.g. "apify/website-content-crawler". Find Actors at https://apify.com/store.
54
+ run_input: JSON-serializable input for the Actor. Each Actor defines its own
55
+ input schema - check the Actor README on Apify Store for required fields.
56
+ timeout_secs: Maximum time in seconds to wait for the Actor run to finish. Defaults to 300.
57
+ memory_mbytes: Memory allocation in MB for the Actor run. Uses Actor default `memory` value if not set.
58
+ build: Actor build tag or number to run a specific version. Uses latest build if not set.
59
+
60
+ Returns:
61
+ Dict with status and content containing run metadata: run_id, status, dataset_id,
62
+ started_at, finished_at.
63
+ """
64
+ try:
65
+ _check_dependency()
66
+ client = ApifyToolClient()
67
+ result = client.run_actor(
68
+ actor_id=actor_id,
69
+ run_input=run_input,
70
+ timeout_secs=timeout_secs,
71
+ memory_mbytes=memory_mbytes,
72
+ build=build,
73
+ )
74
+ return _success_result(
75
+ text=json.dumps(result, indent=2, default=str),
76
+ panel_body=(
77
+ f"[green]Actor run completed[/green]\n"
78
+ f"Actor: {actor_id}\n"
79
+ f"Run ID: {result['run_id']}\n"
80
+ f"Status: {result['status']}\n"
81
+ f"Dataset ID: {result['dataset_id']}"
82
+ ),
83
+ panel_title="Apify: Run Actor",
84
+ )
85
+ except Exception as e:
86
+ return _error_result(e, "apify_run_actor")
87
+
88
+
89
+ @tool
90
+ def apify_get_dataset_items(
91
+ dataset_id: str,
92
+ limit: int = DEFAULT_DATASET_ITEMS_LIMIT,
93
+ offset: int = 0,
94
+ ) -> dict[str, Any]:
95
+ """Fetch items from an existing Apify dataset and return them as JSON.
96
+
97
+ Every Actor run writes its output to a dataset - a structured, append-only store
98
+ for tabular data. Use the dataset_id from the run metadata returned by apify_run_actor
99
+ or apify_run_task. Use offset for pagination through large datasets.
100
+
101
+ Args:
102
+ dataset_id: The Apify dataset ID to fetch items from.
103
+ limit: Maximum number of items to return. Defaults to 100.
104
+ offset: Number of items to skip for pagination. Defaults to 0.
105
+
106
+ Returns:
107
+ Dict with status and content containing an array of dataset items.
108
+ """
109
+ try:
110
+ _check_dependency()
111
+ client = ApifyToolClient()
112
+ items = client.get_dataset_items(dataset_id=dataset_id, limit=limit, offset=offset)
113
+ return _success_result(
114
+ text=json.dumps(items, indent=2, default=str),
115
+ panel_body=(
116
+ f"[green]Dataset items retrieved[/green]\nDataset ID: {dataset_id}\nItems returned: {len(items)}"
117
+ ),
118
+ panel_title="Apify: Dataset Items",
119
+ )
120
+ except Exception as e:
121
+ return _error_result(e, "apify_get_dataset_items")
122
+
123
+
124
+ @tool
125
+ def apify_run_actor_and_get_dataset(
126
+ actor_id: str,
127
+ run_input: dict[str, Any] | None = None,
128
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
129
+ memory_mbytes: int | None = None,
130
+ build: str | None = None,
131
+ dataset_items_limit: int = DEFAULT_DATASET_ITEMS_LIMIT,
132
+ dataset_items_offset: int = 0,
133
+ ) -> dict[str, Any]:
134
+ """Run an Apify Actor and fetch its dataset results in one step.
135
+
136
+ Convenience tool that combines running an Actor and fetching its default dataset
137
+ items into a single call. Use this when you want both the run metadata and the
138
+ result data without making two separate tool calls.
139
+
140
+ Args:
141
+ actor_id: Actor identifier in "username/actor-name" format,
142
+ e.g. "apify/website-content-crawler". Find Actors at https://apify.com/store.
143
+ run_input: JSON-serializable input for the Actor. Each Actor defines its own
144
+ input schema - check the Actor README on Apify Store for required fields.
145
+ timeout_secs: Maximum time in seconds to wait for the Actor run to finish. Defaults to 300.
146
+ memory_mbytes: Memory allocation in MB for the Actor run. Uses Actor default `memory` value if not set.
147
+ build: Actor build tag or number to run a specific version. Uses latest build if not set.
148
+ dataset_items_limit: Maximum number of dataset items to return. Defaults to 100.
149
+ dataset_items_offset: Number of dataset items to skip for pagination. Defaults to 0.
150
+
151
+ Returns:
152
+ Dict with status and content containing run metadata (run_id, status, dataset_id,
153
+ started_at, finished_at) plus an "items" array containing the dataset results.
154
+ """
155
+ try:
156
+ _check_dependency()
157
+ client = ApifyToolClient()
158
+ result = client.run_actor_and_get_dataset(
159
+ actor_id=actor_id,
160
+ run_input=run_input,
161
+ timeout_secs=timeout_secs,
162
+ memory_mbytes=memory_mbytes,
163
+ build=build,
164
+ dataset_items_limit=dataset_items_limit,
165
+ dataset_items_offset=dataset_items_offset,
166
+ )
167
+ return _success_result(
168
+ text=json.dumps(result, indent=2, default=str),
169
+ panel_body=(
170
+ f"[green]Actor run completed with dataset[/green]\n"
171
+ f"Actor: {actor_id}\n"
172
+ f"Run ID: {result['run_id']}\n"
173
+ f"Status: {result['status']}\n"
174
+ f"Dataset ID: {result['dataset_id']}\n"
175
+ f"Items returned: {len(result['items'])}"
176
+ ),
177
+ panel_title="Apify: Run Actor + Dataset",
178
+ )
179
+ except Exception as e:
180
+ return _error_result(e, "apify_run_actor_and_get_dataset")
181
+
182
+
183
+ @tool
184
+ def apify_run_task(
185
+ task_id: str,
186
+ task_input: dict[str, Any] | None = None,
187
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
188
+ memory_mbytes: int | None = None,
189
+ ) -> dict[str, Any]:
190
+ """Run a saved Apify task and return the run metadata as JSON.
191
+
192
+ Tasks are saved Actor configurations with preset inputs, managed in Apify Console.
193
+ Use this when a task has already been configured, so you don't need to specify
194
+ the full Actor input every time. Use apify_run_task_and_get_dataset to also fetch
195
+ the output data in one call.
196
+
197
+ Args:
198
+ task_id: Task identifier in "username/task-name" format or a task ID string.
199
+ task_input: Optional JSON-serializable input to override the task's default input fields.
200
+ timeout_secs: Maximum time in seconds to wait for the task run to finish. Defaults to 300.
201
+ memory_mbytes: Memory allocation in MB for the task run. Uses task default `memory` value if not set.
202
+
203
+ Returns:
204
+ Dict with status and content containing run metadata: run_id, status, dataset_id,
205
+ started_at, finished_at.
206
+ """
207
+ try:
208
+ _check_dependency()
209
+ client = ApifyToolClient()
210
+ result = client.run_task(
211
+ task_id=task_id,
212
+ task_input=task_input,
213
+ timeout_secs=timeout_secs,
214
+ memory_mbytes=memory_mbytes,
215
+ )
216
+ return _success_result(
217
+ text=json.dumps(result, indent=2, default=str),
218
+ panel_body=(
219
+ f"[green]Task run completed[/green]\n"
220
+ f"Task: {task_id}\n"
221
+ f"Run ID: {result['run_id']}\n"
222
+ f"Status: {result['status']}\n"
223
+ f"Dataset ID: {result['dataset_id']}"
224
+ ),
225
+ panel_title="Apify: Run Task",
226
+ )
227
+ except Exception as e:
228
+ return _error_result(e, "apify_run_task")
229
+
230
+
231
+ @tool
232
+ def apify_run_task_and_get_dataset(
233
+ task_id: str,
234
+ task_input: dict[str, Any] | None = None,
235
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
236
+ memory_mbytes: int | None = None,
237
+ dataset_items_limit: int = DEFAULT_DATASET_ITEMS_LIMIT,
238
+ dataset_items_offset: int = 0,
239
+ ) -> dict[str, Any]:
240
+ """Run a saved Apify task and fetch its dataset results in one step.
241
+
242
+ Convenience tool that combines running a task and fetching its default dataset
243
+ items into a single call. Use this when you want both the run metadata and the
244
+ result data without making two separate tool calls.
245
+
246
+ Args:
247
+ task_id: Task identifier in "username/task-name" format or a task ID string.
248
+ task_input: Optional JSON-serializable input to override the task's default input fields.
249
+ timeout_secs: Maximum time in seconds to wait for the task run to finish. Defaults to 300.
250
+ memory_mbytes: Memory allocation in MB for the task run. Uses task default `memory` value if not set.
251
+ dataset_items_limit: Maximum number of dataset items to return. Defaults to 100.
252
+ dataset_items_offset: Number of dataset items to skip for pagination. Defaults to 0.
253
+
254
+ Returns:
255
+ Dict with status and content containing run metadata (run_id, status, dataset_id,
256
+ started_at, finished_at) plus an "items" array containing the dataset results.
257
+ """
258
+ try:
259
+ _check_dependency()
260
+ client = ApifyToolClient()
261
+ result = client.run_task_and_get_dataset(
262
+ task_id=task_id,
263
+ task_input=task_input,
264
+ timeout_secs=timeout_secs,
265
+ memory_mbytes=memory_mbytes,
266
+ dataset_items_limit=dataset_items_limit,
267
+ dataset_items_offset=dataset_items_offset,
268
+ )
269
+ return _success_result(
270
+ text=json.dumps(result, indent=2, default=str),
271
+ panel_body=(
272
+ f"[green]Task run completed with dataset[/green]\n"
273
+ f"Task: {task_id}\n"
274
+ f"Run ID: {result['run_id']}\n"
275
+ f"Status: {result['status']}\n"
276
+ f"Dataset ID: {result['dataset_id']}\n"
277
+ f"Items returned: {len(result['items'])}"
278
+ ),
279
+ panel_title="Apify: Run Task + Dataset",
280
+ )
281
+ except Exception as e:
282
+ return _error_result(e, "apify_run_task_and_get_dataset")
283
+
284
+
285
+ @tool
286
+ def apify_scrape_url(
287
+ url: str,
288
+ timeout_secs: int = DEFAULT_SCRAPE_TIMEOUT_SECS,
289
+ crawler_type: CrawlerType = "cheerio",
290
+ ) -> dict[str, Any]:
291
+ """Scrape a single URL and return its content as Markdown.
292
+
293
+ Uses the Website Content Crawler Actor under the hood, pre-configured for
294
+ fast single-page scraping. This is the simplest way to extract readable content
295
+ from any web page - no Actor input schema needed. For multi-page crawls, use
296
+ apify_run_actor_and_get_dataset with "apify/website-content-crawler" directly.
297
+
298
+ Args:
299
+ url: The URL to scrape, e.g. "https://example.com".
300
+ timeout_secs: Maximum time in seconds to wait for scraping to finish. Defaults to 120.
301
+ crawler_type: Crawler engine to use. One of:
302
+ - "cheerio" (default): Fastest, no JavaScript rendering. Best for static HTML.
303
+ - "playwright:adaptive": Renders JS only when needed. Good general-purpose choice.
304
+ - "playwright:firefox": Full JS rendering, best at bypassing anti-bot protection but slowest.
305
+
306
+ Returns:
307
+ Dict with status and content containing the Markdown content of the scraped page.
308
+ """
309
+ try:
310
+ _check_dependency()
311
+ client = ApifyToolClient()
312
+ content = client.scrape_url(url=url, timeout_secs=timeout_secs, crawler_type=crawler_type)
313
+ return _success_result(
314
+ text=content,
315
+ panel_body=(
316
+ f"[green]URL scraped successfully[/green]\nURL: {url}\nContent length: {len(content)} characters"
317
+ ),
318
+ panel_title="Apify: Scrape URL",
319
+ )
320
+ except Exception as e:
321
+ return _error_result(e, "apify_scrape_url")
322
+
323
+
324
+ APIFY_CORE_TOOLS = [
325
+ apify_run_actor,
326
+ apify_get_dataset_items,
327
+ apify_run_actor_and_get_dataset,
328
+ apify_run_task,
329
+ apify_run_task_and_get_dataset,
330
+ apify_scrape_url,
331
+ ]
strands_apify/py.typed ADDED
File without changes
@@ -0,0 +1,302 @@
1
+ """Apify search and web crawling tools for Strands Agents.
2
+
3
+ Available Tools:
4
+ ---------------
5
+ - apify_google_search_scraper: Search Google and return structured results
6
+ - apify_google_places_scraper: Search Google Maps for places and businesses
7
+ - apify_youtube_scraper: Scrape YouTube videos, channels, or search results
8
+ - apify_website_content_crawler: Multi-page website crawl with markdown extraction
9
+ - apify_ecommerce_scraper: Scrape product data from e-commerce sites
10
+ """
11
+
12
+ import json
13
+ from typing import Any
14
+
15
+ from strands import tool
16
+
17
+ from .utils import (
18
+ DEFAULT_TIMEOUT_SECS,
19
+ WEBSITE_CONTENT_CRAWLER,
20
+ ApifyToolClient,
21
+ _check_dependency,
22
+ _error_result,
23
+ _success_result,
24
+ _validate_url,
25
+ _validate_urls,
26
+ )
27
+
28
+ GOOGLE_SEARCH_SCRAPER_ID = "apify/google-search-scraper"
29
+ GOOGLE_PLACES_SCRAPER_ID = "compass/crawler-google-places"
30
+ YOUTUBE_SCRAPER_ID = "streamers/youtube-scraper"
31
+ ECOMMERCE_SCRAPER_ID = "apify/e-commerce-scraping-tool"
32
+ DEFAULT_SEARCH_RESULTS_LIMIT = 20
33
+
34
+ VALID_ECOMMERCE_URL_TYPES = ("product", "listing")
35
+
36
+
37
+ def _search_crawl_result(
38
+ actor_name: str,
39
+ client: ApifyToolClient,
40
+ run_input: dict[str, Any],
41
+ actor_id: str,
42
+ timeout_secs: int,
43
+ results_limit: int,
44
+ ) -> dict[str, Any]:
45
+ """Run a search/crawling Actor and return formatted results."""
46
+ result = client.run_actor_and_get_dataset(
47
+ actor_id=actor_id,
48
+ run_input=run_input,
49
+ timeout_secs=timeout_secs,
50
+ dataset_items_limit=results_limit,
51
+ )
52
+ return _success_result(
53
+ text=json.dumps(result, indent=2, default=str),
54
+ panel_body=(
55
+ f"[green]{actor_name} completed[/green]\nRun ID: {result['run_id']}\nItems returned: {len(result['items'])}"
56
+ ),
57
+ panel_title=f"Apify: {actor_name}",
58
+ )
59
+
60
+
61
+ @tool
62
+ def apify_google_search_scraper(
63
+ search_query: str,
64
+ results_limit: int = 10,
65
+ country_code: str | None = None,
66
+ language_code: str | None = None,
67
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
68
+ ) -> dict[str, Any]:
69
+ """Search Google and return structured search results.
70
+
71
+ Uses the Google Search Scraper Actor to perform a Google search and return
72
+ organic results, ads, People Also Ask, and related queries in a structured format.
73
+
74
+ Args:
75
+ search_query: The search query string, e.g. "best AI frameworks 2025".
76
+ Supports advanced Google operators like "site:example.com" or "AI OR ML".
77
+ results_limit: Maximum number of results to return. Google returns ~10 results
78
+ per page, so requesting more triggers additional page scraping. Defaults to 10.
79
+ country_code: Two-letter country code for localized results, e.g. "us", "de".
80
+ language_code: Two-letter language code for the interface, e.g. "en", "de".
81
+ timeout_secs: Maximum time in seconds to wait for the run to finish. Defaults to 300.
82
+
83
+ Returns:
84
+ Dict with status and content containing structured Google search results including
85
+ organic results, ads, and People Also Ask data.
86
+ """
87
+ try:
88
+ _check_dependency()
89
+ client = ApifyToolClient()
90
+ max_pages = max(1, (results_limit + 9) // 10)
91
+ run_input: dict[str, Any] = {
92
+ "queries": search_query,
93
+ "maxPagesPerQuery": max_pages,
94
+ }
95
+ if country_code is not None:
96
+ run_input["countryCode"] = country_code
97
+ if language_code is not None:
98
+ run_input["languageCode"] = language_code
99
+ return _search_crawl_result(
100
+ actor_name="Google Search Scraper",
101
+ client=client,
102
+ run_input=run_input,
103
+ actor_id=GOOGLE_SEARCH_SCRAPER_ID,
104
+ timeout_secs=timeout_secs,
105
+ results_limit=results_limit,
106
+ )
107
+ except Exception as e:
108
+ return _error_result(e, "apify_google_search_scraper")
109
+
110
+
111
+ @tool
112
+ def apify_google_places_scraper(
113
+ search_query: str,
114
+ results_limit: int = DEFAULT_SEARCH_RESULTS_LIMIT,
115
+ language: str | None = None,
116
+ include_reviews: bool = False,
117
+ max_reviews: int = 5,
118
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
119
+ ) -> dict[str, Any]:
120
+ """Search Google Maps for businesses and places, optionally including reviews.
121
+
122
+ Uses the Google Maps Scraper Actor to find places matching a search query
123
+ and return structured data including name, address, rating, phone, and website.
124
+
125
+ Args:
126
+ search_query: Search query for Google Maps, e.g. "restaurants in Prague".
127
+ results_limit: Maximum number of places to return. Defaults to 20.
128
+ language: Language for results, e.g. "en", "de". Defaults to English.
129
+ include_reviews: Whether to include user reviews for each place. Defaults to False.
130
+ max_reviews: Maximum reviews per place when include_reviews is True. Defaults to 5.
131
+ timeout_secs: Maximum time in seconds to wait for the run to finish. Defaults to 300.
132
+
133
+ Returns:
134
+ Dict with status and content containing structured Google Maps place data.
135
+ """
136
+ try:
137
+ _check_dependency()
138
+ client = ApifyToolClient()
139
+ run_input: dict[str, Any] = {
140
+ "searchStringsArray": [search_query],
141
+ "maxCrawledPlacesPerSearch": results_limit,
142
+ "maxReviews": max_reviews if include_reviews else 0,
143
+ }
144
+ if language is not None:
145
+ run_input["language"] = language
146
+ return _search_crawl_result(
147
+ actor_name="Google Places Scraper",
148
+ client=client,
149
+ run_input=run_input,
150
+ actor_id=GOOGLE_PLACES_SCRAPER_ID,
151
+ timeout_secs=timeout_secs,
152
+ results_limit=results_limit,
153
+ )
154
+ except Exception as e:
155
+ return _error_result(e, "apify_google_places_scraper")
156
+
157
+
158
+ @tool
159
+ def apify_youtube_scraper(
160
+ search_query: str | None = None,
161
+ urls: list[str] | None = None,
162
+ results_limit: int = DEFAULT_SEARCH_RESULTS_LIMIT,
163
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
164
+ ) -> dict[str, Any]:
165
+ """Scrape YouTube videos, channels, or search results.
166
+
167
+ Uses the YouTube Scraper Actor to search YouTube or scrape specific video/channel
168
+ URLs. Provide either a search query, specific URLs, or both.
169
+
170
+ Args:
171
+ search_query: YouTube search query, e.g. "python tutorial".
172
+ urls: Specific YouTube video or channel URLs to scrape.
173
+ results_limit: Maximum number of results to return. Defaults to 20.
174
+ timeout_secs: Maximum time in seconds to wait for the run to finish. Defaults to 300.
175
+
176
+ Returns:
177
+ Dict with status and content containing structured YouTube video/channel data.
178
+ """
179
+ try:
180
+ _check_dependency()
181
+ if not search_query and not urls:
182
+ raise ValueError("At least one of 'search_query' or 'urls' must be provided.")
183
+ if urls is not None:
184
+ _validate_urls(urls, "urls")
185
+ client = ApifyToolClient()
186
+ run_input: dict[str, Any] = {
187
+ "maxResults": results_limit,
188
+ }
189
+ if search_query is not None:
190
+ run_input["searchQueries"] = [search_query]
191
+ if urls is not None:
192
+ run_input["startUrls"] = [{"url": u} for u in urls]
193
+ return _search_crawl_result(
194
+ actor_name="YouTube Scraper",
195
+ client=client,
196
+ run_input=run_input,
197
+ actor_id=YOUTUBE_SCRAPER_ID,
198
+ timeout_secs=timeout_secs,
199
+ results_limit=results_limit,
200
+ )
201
+ except Exception as e:
202
+ return _error_result(e, "apify_youtube_scraper")
203
+
204
+
205
+ @tool
206
+ def apify_website_content_crawler(
207
+ start_url: str,
208
+ max_pages: int = 10,
209
+ max_depth: int = 2,
210
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
211
+ ) -> dict[str, Any]:
212
+ """Crawl a website and extract content from multiple pages.
213
+
214
+ Uses the Website Content Crawler Actor to perform a multi-page crawl starting
215
+ from the given URL. Returns page content as markdown. This is the extended
216
+ multi-page version - distinct from apify_scrape_url which scrapes a single page.
217
+
218
+ Args:
219
+ start_url: The starting URL to crawl, e.g. "https://docs.example.com".
220
+ max_pages: Maximum number of pages to crawl. Defaults to 10.
221
+ max_depth: Maximum crawl depth from the start URL. Defaults to 2.
222
+ timeout_secs: Maximum time in seconds to wait for the run to finish. Defaults to 300.
223
+
224
+ Returns:
225
+ Dict with status and content containing crawled page data with markdown content.
226
+ """
227
+ try:
228
+ _check_dependency()
229
+ client = ApifyToolClient()
230
+ _validate_url(start_url)
231
+ run_input: dict[str, Any] = {
232
+ "startUrls": [{"url": start_url}],
233
+ "maxCrawlPages": max_pages,
234
+ "maxCrawlDepth": max_depth,
235
+ "proxyConfiguration": {"useApifyProxy": True},
236
+ }
237
+ return _search_crawl_result(
238
+ actor_name="Website Content Crawler",
239
+ client=client,
240
+ run_input=run_input,
241
+ actor_id=WEBSITE_CONTENT_CRAWLER,
242
+ timeout_secs=timeout_secs,
243
+ results_limit=max_pages,
244
+ )
245
+ except Exception as e:
246
+ return _error_result(e, "apify_website_content_crawler")
247
+
248
+
249
+ @tool
250
+ def apify_ecommerce_scraper(
251
+ url: str,
252
+ url_type: str = "product",
253
+ results_limit: int = DEFAULT_SEARCH_RESULTS_LIMIT,
254
+ timeout_secs: int = DEFAULT_TIMEOUT_SECS,
255
+ ) -> dict[str, Any]:
256
+ """Scrape product data from e-commerce websites.
257
+
258
+ Uses the E-commerce Scraping Tool Actor to extract structured product data
259
+ (title, price, description, images, etc.) from supported e-commerce platforms
260
+ including Amazon, eBay, Walmart, and others. The Actor auto-detects the site.
261
+
262
+ Args:
263
+ url: The URL to scrape.
264
+ url_type: Type of URL being scraped. Use "product" (default) for a direct product
265
+ detail page, or "listing" for a category page or search results page containing
266
+ multiple products.
267
+ results_limit: Maximum number of products to return. Defaults to 20.
268
+ timeout_secs: Maximum time in seconds to wait for the run to finish. Defaults to 300.
269
+
270
+ Returns:
271
+ Dict with status and content containing structured product data.
272
+ """
273
+ try:
274
+ _check_dependency()
275
+ client = ApifyToolClient()
276
+ _validate_url(url)
277
+ if url_type not in VALID_ECOMMERCE_URL_TYPES:
278
+ raise ValueError(f"Invalid url_type '{url_type}'. Must be one of: {', '.join(VALID_ECOMMERCE_URL_TYPES)}.")
279
+ url_field = "listingUrls" if url_type == "listing" else "detailsUrls"
280
+ run_input: dict[str, Any] = {
281
+ url_field: [{"url": url}],
282
+ "maxProductResults": results_limit,
283
+ }
284
+ return _search_crawl_result(
285
+ actor_name="E-commerce Scraper",
286
+ client=client,
287
+ run_input=run_input,
288
+ actor_id=ECOMMERCE_SCRAPER_ID,
289
+ timeout_secs=timeout_secs,
290
+ results_limit=results_limit,
291
+ )
292
+ except Exception as e:
293
+ return _error_result(e, "apify_ecommerce_scraper")
294
+
295
+
296
+ APIFY_SEARCH_TOOLS = [
297
+ apify_google_search_scraper,
298
+ apify_google_places_scraper,
299
+ apify_youtube_scraper,
300
+ apify_website_content_crawler,
301
+ apify_ecommerce_scraper,
302
+ ]