Spaces:
Sleeping
Sleeping
| """ | |
| Cloud Example 5: Search API (Beta) π | |
| ===================================== | |
| This example demonstrates the Browser Use Search API (BETA): | |
| - Simple search: Search Google and extract from multiple results | |
| - URL search: Extract specific content from a target URL | |
| - Deep navigation through websites (depth parameter) | |
| - Real-time content extraction vs cached results | |
| Perfect for: Content extraction, research, competitive analysis | |
| """ | |
| import argparse | |
| import asyncio | |
| import json | |
| import os | |
| import time | |
| from typing import Any | |
| import aiohttp | |
| # Configuration | |
| API_KEY = os.getenv('BROWSER_USE_API_KEY') | |
| if not API_KEY: | |
| raise ValueError( | |
| 'Please set BROWSER_USE_API_KEY environment variable. You can also create an API key at https://cloud.browser-use.com/new-api-key' | |
| ) | |
| BASE_URL = os.getenv('BROWSER_USE_BASE_URL', 'https://api.browser-use.com/api/v1') | |
| TIMEOUT = int(os.getenv('BROWSER_USE_TIMEOUT', '30')) | |
| HEADERS = {'Authorization': f'Bearer {API_KEY}', 'Content-Type': 'application/json'} | |
| async def simple_search(query: str, max_websites: int = 5, depth: int = 2) -> dict[str, Any]: | |
| """ | |
| Search Google and extract content from multiple top results. | |
| Args: | |
| query: Search query to process | |
| max_websites: Number of websites to process (1-10) | |
| depth: How deep to navigate (2-5) | |
| Returns: | |
| Dictionary with results from multiple websites | |
| """ | |
| # Validate input parameters | |
| max_websites = max(1, min(max_websites, 10)) # Clamp to 1-10 | |
| depth = max(2, min(depth, 5)) # Clamp to 2-5 | |
| start_time = time.time() | |
| print(f"π Simple Search: '{query}'") | |
| print(f'π Processing {max_websites} websites at depth {depth}') | |
| print(f'π° Estimated cost: {depth * max_websites}Β’') | |
| payload = {'query': query, 'max_websites': max_websites, 'depth': depth} | |
| timeout = aiohttp.ClientTimeout(total=TIMEOUT) | |
| connector = aiohttp.TCPConnector(limit=10) # Limit concurrent connections | |
| async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session: | |
| async with session.post(f'{BASE_URL}/simple-search', json=payload, headers=HEADERS) as response: | |
| elapsed = time.time() - start_time | |
| if response.status == 200: | |
| try: | |
| result = await response.json() | |
| print(f'β Found results from {len(result.get("results", []))} websites in {elapsed:.1f}s') | |
| return result | |
| except (aiohttp.ContentTypeError, json.JSONDecodeError) as e: | |
| error_text = await response.text() | |
| print(f'β Invalid JSON response: {e} (after {elapsed:.1f}s)') | |
| return {'error': 'Invalid JSON', 'details': error_text} | |
| else: | |
| error_text = await response.text() | |
| print(f'β Search failed: {response.status} - {error_text} (after {elapsed:.1f}s)') | |
| return {'error': f'HTTP {response.status}', 'details': error_text} | |
| async def search_url(url: str, query: str, depth: int = 2) -> dict[str, Any]: | |
| """ | |
| Extract specific content from a target URL. | |
| Args: | |
| url: Target URL to extract from | |
| query: What specific content to look for | |
| depth: How deep to navigate (2-5) | |
| Returns: | |
| Dictionary with extracted content | |
| """ | |
| # Validate input parameters | |
| depth = max(2, min(depth, 5)) # Clamp to 2-5 | |
| start_time = time.time() | |
| print(f'π― URL Search: {url}') | |
| print(f"π Looking for: '{query}'") | |
| print(f'π Navigation depth: {depth}') | |
| print(f'π° Estimated cost: {depth}Β’') | |
| payload = {'url': url, 'query': query, 'depth': depth} | |
| timeout = aiohttp.ClientTimeout(total=TIMEOUT) | |
| connector = aiohttp.TCPConnector(limit=10) # Limit concurrent connections | |
| async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session: | |
| async with session.post(f'{BASE_URL}/search-url', json=payload, headers=HEADERS) as response: | |
| elapsed = time.time() - start_time | |
| if response.status == 200: | |
| try: | |
| result = await response.json() | |
| print(f'β Extracted content from {result.get("url", "website")} in {elapsed:.1f}s') | |
| return result | |
| except (aiohttp.ContentTypeError, json.JSONDecodeError) as e: | |
| error_text = await response.text() | |
| print(f'β Invalid JSON response: {e} (after {elapsed:.1f}s)') | |
| return {'error': 'Invalid JSON', 'details': error_text} | |
| else: | |
| error_text = await response.text() | |
| print(f'β URL search failed: {response.status} - {error_text} (after {elapsed:.1f}s)') | |
| return {'error': f'HTTP {response.status}', 'details': error_text} | |
| def display_simple_search_results(results: dict[str, Any]): | |
| """Display simple search results in a readable format.""" | |
| if 'error' in results: | |
| print(f'β Error: {results["error"]}') | |
| return | |
| websites = results.get('results', []) | |
| print(f'\nπ Search Results ({len(websites)} websites)') | |
| print('=' * 50) | |
| for i, site in enumerate(websites, 1): | |
| url = site.get('url', 'Unknown URL') | |
| content = site.get('content', 'No content') | |
| print(f'\n{i}. π {url}') | |
| print('-' * 40) | |
| # Show first 300 chars of content | |
| if len(content) > 300: | |
| print(f'{content[:300]}...') | |
| print(f'[Content truncated - {len(content)} total characters]') | |
| else: | |
| print(content) | |
| # Show execution URLs if available | |
| if results.get('live_url'): | |
| print(f'\nπ Live Preview: {results["live_url"]}') | |
| if results.get('public_share_url'): | |
| print(f'π Share URL: {results["public_share_url"]}') | |
| elif results.get('share_url'): | |
| print(f'π Share URL: {results["share_url"]}') | |
| def display_url_search_results(results: dict[str, Any]): | |
| """Display URL search results in a readable format.""" | |
| if 'error' in results: | |
| print(f'β Error: {results["error"]}') | |
| return | |
| url = results.get('url', 'Unknown URL') | |
| content = results.get('content', 'No content') | |
| print(f'\nπ Extracted Content from: {url}') | |
| print('=' * 60) | |
| print(content) | |
| # Show execution URLs if available | |
| if results.get('live_url'): | |
| print(f'\nπ Live Preview: {results["live_url"]}') | |
| if results.get('public_share_url'): | |
| print(f'π Share URL: {results["public_share_url"]}') | |
| elif results.get('share_url'): | |
| print(f'π Share URL: {results["share_url"]}') | |
| async def demo_news_search(): | |
| """Demo: Search for latest news across multiple sources.""" | |
| print('\nπ° Demo 1: Latest News Search') | |
| print('-' * 35) | |
| demo_start = time.time() | |
| query = 'latest developments in artificial intelligence 2024' | |
| results = await simple_search(query, max_websites=4, depth=2) | |
| demo_elapsed = time.time() - demo_start | |
| display_simple_search_results(results) | |
| print(f'\nβ±οΈ Total demo time: {demo_elapsed:.1f}s') | |
| return results | |
| async def demo_competitive_analysis(): | |
| """Demo: Analyze competitor websites.""" | |
| print('\nπ’ Demo 2: Competitive Analysis') | |
| print('-' * 35) | |
| query = 'browser automation tools comparison features pricing' | |
| results = await simple_search(query, max_websites=3, depth=3) | |
| display_simple_search_results(results) | |
| return results | |
| async def demo_deep_website_analysis(): | |
| """Demo: Deep analysis of a specific website.""" | |
| print('\nπ― Demo 3: Deep Website Analysis') | |
| print('-' * 35) | |
| demo_start = time.time() | |
| url = 'https://docs.browser-use.com' | |
| query = 'Browser Use features, pricing, and API capabilities' | |
| results = await search_url(url, query, depth=3) | |
| demo_elapsed = time.time() - demo_start | |
| display_url_search_results(results) | |
| print(f'\nβ±οΈ Total demo time: {demo_elapsed:.1f}s') | |
| return results | |
| async def demo_product_research(): | |
| """Demo: Product research and comparison.""" | |
| print('\nποΈ Demo 4: Product Research') | |
| print('-' * 30) | |
| query = 'best wireless headphones 2024 reviews comparison' | |
| results = await simple_search(query, max_websites=5, depth=2) | |
| display_simple_search_results(results) | |
| return results | |
| async def demo_real_time_vs_cached(): | |
| """Demo: Show difference between real-time and cached results.""" | |
| print('\nβ‘ Demo 5: Real-time vs Cached Data') | |
| print('-' * 40) | |
| print('π Browser Use Search API benefits:') | |
| print('β’ Actually browses websites like a human') | |
| print('β’ Gets live, current data (not cached)') | |
| print('β’ Navigates deep into sites via clicks') | |
| print('β’ Handles JavaScript and dynamic content') | |
| print('β’ Accesses pages requiring navigation') | |
| # Example with live data | |
| query = 'current Bitcoin price USD live' | |
| results = await simple_search(query, max_websites=3, depth=2) | |
| print('\nπ° Live Bitcoin Price Search Results:') | |
| display_simple_search_results(results) | |
| return results | |
| async def demo_search_depth_comparison(): | |
| """Demo: Compare different search depths.""" | |
| print('\nπ Demo 6: Search Depth Comparison') | |
| print('-' * 40) | |
| url = 'https://news.ycombinator.com' | |
| query = 'trending technology discussions' | |
| depths = [2, 3, 4] | |
| results = {} | |
| for depth in depths: | |
| print(f'\nπ Testing depth {depth}:') | |
| result = await search_url(url, query, depth) | |
| results[depth] = result | |
| if 'content' in result: | |
| content_length = len(result['content']) | |
| print(f'π Content length: {content_length} characters') | |
| # Brief pause between requests | |
| await asyncio.sleep(1) | |
| # Summary | |
| print('\nπ Depth Comparison Summary:') | |
| print('-' * 30) | |
| for depth, result in results.items(): | |
| if 'content' in result: | |
| length = len(result['content']) | |
| print(f'Depth {depth}: {length} characters') | |
| else: | |
| print(f'Depth {depth}: Error or no content') | |
| return results | |
| async def main(): | |
| """Demonstrate comprehensive Search API usage.""" | |
| print('π Browser Use Cloud - Search API (BETA)') | |
| print('=' * 45) | |
| print('β οΈ Note: This API is in BETA and may change') | |
| print() | |
| print('π― Search API Features:') | |
| print('β’ Real-time website browsing (not cached)') | |
| print('β’ Deep navigation through multiple pages') | |
| print('β’ Dynamic content and JavaScript handling') | |
| print('β’ Multiple result aggregation') | |
| print('β’ Cost-effective content extraction') | |
| print('\nπ° Pricing:') | |
| print('β’ Simple Search: 1Β’ Γ depth Γ websites') | |
| print('β’ URL Search: 1Β’ Γ depth') | |
| print('β’ Example: depth=2, 5 websites = 10Β’') | |
| try: | |
| # Parse command line arguments | |
| parser = argparse.ArgumentParser(description='Search API (BETA) examples') | |
| parser.add_argument( | |
| '--demo', | |
| choices=['news', 'competitive', 'deep', 'product', 'realtime', 'depth', 'all'], | |
| default='news', | |
| help='Which demo to run', | |
| ) | |
| args = parser.parse_args() | |
| print(f'\nπ Running {args.demo} demo(s)...') | |
| if args.demo == 'news': | |
| await demo_news_search() | |
| elif args.demo == 'competitive': | |
| await demo_competitive_analysis() | |
| elif args.demo == 'deep': | |
| await demo_deep_website_analysis() | |
| elif args.demo == 'product': | |
| await demo_product_research() | |
| elif args.demo == 'realtime': | |
| await demo_real_time_vs_cached() | |
| elif args.demo == 'depth': | |
| await demo_search_depth_comparison() | |
| elif args.demo == 'all': | |
| await demo_news_search() | |
| await demo_competitive_analysis() | |
| await demo_deep_website_analysis() | |
| await demo_product_research() | |
| await demo_real_time_vs_cached() | |
| await demo_search_depth_comparison() | |
| except aiohttp.ClientError as e: | |
| print(f'β Network Error: {e}') | |
| except Exception as e: | |
| print(f'β Error: {e}') | |
| if __name__ == '__main__': | |
| asyncio.run(main()) | |