Add web browser example to doc (#439)
This commit is contained in:
		
							parent
							
								
									cedf63cde7
								
							
						
					
					
						commit
						b453d63f33
					
				|  | @ -28,6 +28,8 @@ | ||||||
|     title: Master you knowledge base with agentic RAG |     title: Master you knowledge base with agentic RAG | ||||||
|   - local: examples/multiagents |   - local: examples/multiagents | ||||||
|     title: Orchestrate a multi-agent system |     title: Orchestrate a multi-agent system | ||||||
|  |   - local: examples/web_browser | ||||||
|  |     title: Build a web browser agent using vision models | ||||||
| - title: Reference | - title: Reference | ||||||
|   sections: |   sections: | ||||||
|   - local: reference/agents |   - local: reference/agents | ||||||
|  |  | ||||||
|  | @ -0,0 +1,218 @@ | ||||||
|  | # Web Browser Automation with Agents 🤖🌐 | ||||||
|  | 
 | ||||||
|  | [[open-in-colab]] | ||||||
|  | 
 | ||||||
|  | In this notebook, we'll create an **agent-powered web browser automation system**! This system can navigate websites, interact with elements, and extract information automatically. | ||||||
|  | 
 | ||||||
|  | The agent will be able to: | ||||||
|  | ✅ Navigate to web pages | ||||||
|  | ✅ Click on elements | ||||||
|  | ✅ Search within pages | ||||||
|  | ✅ Handle popups and modals | ||||||
|  | ✅ Take screenshots | ||||||
|  | ✅ Extract information | ||||||
|  | 
 | ||||||
|  | Let's set up this system step by step. | ||||||
|  | 
 | ||||||
|  | First, run these lines to install the required dependencies: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | pip install smolagents selenium helium pillow python-dotenv -q | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Let's import our required libraries and set up environment variables: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | from io import BytesIO | ||||||
|  | from time import sleep | ||||||
|  | 
 | ||||||
|  | import helium | ||||||
|  | from dotenv import load_dotenv | ||||||
|  | from PIL import Image | ||||||
|  | from selenium import webdriver | ||||||
|  | from selenium.webdriver.common.by import By | ||||||
|  | from selenium.webdriver.common.keys import Keys | ||||||
|  | 
 | ||||||
|  | from smolagents import CodeAgent, tool | ||||||
|  | from smolagents.agents import ActionStep | ||||||
|  | 
 | ||||||
|  | # Load environment variables | ||||||
|  | load_dotenv() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Now let's create our core browser interaction tools that will allow our agent to navigate and interact with web pages: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | @tool | ||||||
|  | def search_item_ctrl_f(text: str, nth_result: int = 1) -> str: | ||||||
|  |     """ | ||||||
|  |     Searches for text on the current page via Ctrl + F and jumps to the nth occurrence. | ||||||
|  |     Args: | ||||||
|  |         text: The text to search for | ||||||
|  |         nth_result: Which occurrence to jump to (default: 1) | ||||||
|  |     """ | ||||||
|  |     elements = driver.find_elements(By.XPATH, f"//*[contains(text(), '{text}')]") | ||||||
|  |     if nth_result > len(elements): | ||||||
|  |         raise Exception(f"Match n°{nth_result} not found (only {len(elements)} matches found)") | ||||||
|  |     result = f"Found {len(elements)} matches for '{text}'." | ||||||
|  |     elem = elements[nth_result - 1] | ||||||
|  |     driver.execute_script("arguments[0].scrollIntoView(true);", elem) | ||||||
|  |     result += f"Focused on element {nth_result} of {len(elements)}" | ||||||
|  |     return result | ||||||
|  | 
 | ||||||
|  | @tool | ||||||
|  | def go_back() -> None: | ||||||
|  |     """Goes back to previous page.""" | ||||||
|  |     driver.back() | ||||||
|  | 
 | ||||||
|  | @tool | ||||||
|  | def close_popups() -> str: | ||||||
|  |     """ | ||||||
|  |     Closes any visible modal or pop-up on the page. Use this to dismiss pop-up windows! | ||||||
|  |     This does not work on cookie consent banners. | ||||||
|  |     """ | ||||||
|  |     webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Let's set up our browser with Chrome and configure screenshot capabilities: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Configure Chrome options | ||||||
|  | chrome_options = webdriver.ChromeOptions() | ||||||
|  | chrome_options.add_argument("--force-device-scale-factor=1") | ||||||
|  | chrome_options.add_argument("--window-size=1000,1350") | ||||||
|  | chrome_options.add_argument("--disable-pdf-viewer") | ||||||
|  | chrome_options.add_argument("--window-position=0,0") | ||||||
|  | 
 | ||||||
|  | # Initialize the browser | ||||||
|  | driver = helium.start_chrome(headless=False, options=chrome_options) | ||||||
|  | 
 | ||||||
|  | # Set up screenshot callback | ||||||
|  | def save_screenshot(memory_step: ActionStep, agent: CodeAgent) -> None: | ||||||
|  |     sleep(1.0)  # Let JavaScript animations happen before taking the screenshot | ||||||
|  |     driver = helium.get_driver() | ||||||
|  |     current_step = memory_step.step_number | ||||||
|  |     if driver is not None: | ||||||
|  |         for previous_memory_step in agent.memory.steps:  # Remove previous screenshots for lean processing | ||||||
|  |             if isinstance(previous_memory_step, ActionStep) and previous_memory_step.step_number <= current_step - 2: | ||||||
|  |                 previous_memory_step.observations_images = None | ||||||
|  |         png_bytes = driver.get_screenshot_as_png() | ||||||
|  |         image = Image.open(BytesIO(png_bytes)) | ||||||
|  |         print(f"Captured a browser screenshot: {image.size} pixels") | ||||||
|  |         memory_step.observations_images = [image.copy()]  # Create a copy to ensure it persists | ||||||
|  | 
 | ||||||
|  |     # Update observations with current URL | ||||||
|  |     url_info = f"Current url: {driver.current_url}" | ||||||
|  |     memory_step.observations = ( | ||||||
|  |         url_info if memory_step.observations is None else memory_step.observations + "\n" + url_info | ||||||
|  |     ) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Now let's create our web automation agent: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Initialize the model | ||||||
|  | model_id = "meta-llama/Llama-3.3-70B-Instruct"  # You can change this to your preferred model | ||||||
|  | model = HfApiModel(model_id) | ||||||
|  | 
 | ||||||
|  | # Create the agent | ||||||
|  | agent = CodeAgent( | ||||||
|  |     tools=[go_back, close_popups, search_item_ctrl_f], | ||||||
|  |     model=model, | ||||||
|  |     additional_authorized_imports=["helium"], | ||||||
|  |     step_callbacks=[save_screenshot], | ||||||
|  |     max_steps=20, | ||||||
|  |     verbosity_level=2, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | # Import helium for the agent | ||||||
|  | agent.python_executor("from helium import *", agent.state) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The agent needs instructions on how to use Helium for web automation. Here are the instructions we'll provide: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | helium_instructions = """ | ||||||
|  | You can use helium to access websites. Don't bother about the helium driver, it's already managed. | ||||||
|  | We've already ran "from helium import *" | ||||||
|  | Then you can go to pages! | ||||||
|  | Code: | ||||||
|  | ```py | ||||||
|  | go_to('github.com/trending') | ||||||
|  | ```<end_code> | ||||||
|  | 
 | ||||||
|  | You can directly click clickable elements by inputting the text that appears on them. | ||||||
|  | Code: | ||||||
|  | ```py | ||||||
|  | click("Top products") | ||||||
|  | ```<end_code> | ||||||
|  | 
 | ||||||
|  | If it's a link: | ||||||
|  | Code: | ||||||
|  | ```py | ||||||
|  | click(Link("Top products")) | ||||||
|  | ```<end_code> | ||||||
|  | 
 | ||||||
|  | If you try to interact with an element and it's not found, you'll get a LookupError. | ||||||
|  | In general stop your action after each button click to see what happens on your screenshot. | ||||||
|  | Never try to login in a page. | ||||||
|  | 
 | ||||||
|  | To scroll up or down, use scroll_down or scroll_up with as an argument the number of pixels to scroll from. | ||||||
|  | Code: | ||||||
|  | ```py | ||||||
|  | scroll_down(num_pixels=1200) # This will scroll one viewport down | ||||||
|  | ```<end_code> | ||||||
|  | 
 | ||||||
|  | When you have pop-ups with a cross icon to close, don't try to click the close icon by finding its element or targeting an 'X' element (this most often fails). | ||||||
|  | Just use your built-in tool `close_popups` to close them: | ||||||
|  | Code: | ||||||
|  | ```py | ||||||
|  | close_popups() | ||||||
|  | ```<end_code> | ||||||
|  | 
 | ||||||
|  | You can use .exists() to check for the existence of an element. For example: | ||||||
|  | Code: | ||||||
|  | ```py | ||||||
|  | if Text('Accept cookies?').exists(): | ||||||
|  |     click('I accept') | ||||||
|  | ```<end_code> | ||||||
|  | """ | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Now we can run our agent with a task! Let's try finding information on Wikipedia: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | search_request = """ | ||||||
|  | Please navigate to https://en.wikipedia.org/wiki/Chicago and give me a sentence containing the word "1992" that mentions a construction accident. | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | agent_output = agent.run(search_request + helium_instructions) | ||||||
|  | print("Final output:") | ||||||
|  | print(agent_output) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | You can run different tasks by modifying the request. For example, here's for me to know if I should work harder: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | github_request = """ | ||||||
|  | I'm trying to find how hard I have to work to get a repo in github.com/trending. | ||||||
|  | Can you navigate to the profile for the top author of the top trending repo, and give me their total number of commits over the last year? | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | agent_output = agent.run(github_request + helium_instructions) | ||||||
|  | print("Final output:") | ||||||
|  | print(agent_output) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The system is particularly effective for tasks like: | ||||||
|  | - Data extraction from websites | ||||||
|  | - Web research automation | ||||||
|  | - UI testing and verification | ||||||
|  | - Content monitoring | ||||||
|  | 
 | ||||||
|  | Best Practices: | ||||||
|  | 1. Always provide clear, specific instructions | ||||||
|  | 2. Use the screenshot callback for debugging | ||||||
|  | 3. Handle errors gracefully | ||||||
|  | 4. Clean up old screenshots to manage memory | ||||||
|  | 5. Set reasonable step limits for your tasks | ||||||
		Loading…
	
		Reference in New Issue