The same four interactions, six implementations

This page shows one scenario — browse to the site, follow a link, use the search box, and click a button — implemented six ways: two browser-automation tools (Selenium and Playwright), each in three languages (JavaScript, Python, Rust). The target for all six is Google Search, because it is a search box and results page that almost every reader already knows how to use, which makes it easy to see what each tool's syntax is doing without having to first learn the page itself.

The four interactions, defined once

Rather than repeat these per example, here is what each of the six scripts below does:

  1. Browse to the site — navigate to https://www.google.com.
  2. Use the search box — locate the search input and type a query, e.g. "testing examples".
  3. Click a button / submit — press Enter, or find the submit button and click it.
  4. Follow a link — after results load, find and click the first organic result link.

A caveat worth stating plainly rather than glossing over: Google's exact markup for the search box has drifted over time, and will likely keep drifting. It has historically been an <input> and is currently often a <textarea>, but in both cases it has commonly carried name="q", so the examples below locate it with a selector like [name="q"] (or, for tools with a typed-attribute locator, By.name("q")). That is a real illustration of why name/tag selectors are brittle: they can silently stop matching when a site’s markup changes underneath them. Where a tool supports locating by accessible role and name instead (for example a role="combobox" with a visible "Search" label), that is the more robust choice, and is noted in the relevant example. The submit button has historically carried name="btnK", but it can be obscured by autocomplete suggestions the moment the search box gains focus, which is one reason pressing Enter after typing is generally more reliable than trying to click it.

Selenium

Selenium is the longest-established cross-language browser automation project — its WebDriver protocol is the same one several of the other tools on this page speak underneath.

Selenium + JavaScript
import { Builder, By, Key } from 'selenium-webdriver';

async function demo() {
  const driver = await new Builder().forBrowser('chrome').build();

  try {
    // 1. Browse to the site.
    await driver.get('https://www.google.com');

    // 2. Use the search box.
    // Google's search input has drifted between <input> and <textarea>
    // over the years, but has commonly carried name="q".
    const searchBox = await driver.findElement(By.name('q'));
    await searchBox.sendKeys('testing examples');

    // 3. Click a button / submit.
    // Pressing Enter is generally more reliable than locating the submit
    // button, which autocomplete suggestions can obscure.
    await searchBox.sendKeys(Key.RETURN);

    // 4. Follow a link.
    const firstResult = await driver.findElement(By.css('a'));
    await firstResult.click();
  } finally {
    await driver.quit();
  }
}

demo().catch((err) => console.error(err));
Selenium + Python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()

try:
    # 1. Browse to the site.
    driver.get("https://www.google.com")

    # 2. Use the search box.
    # Google's search input has drifted between <input> and <textarea>
    # over the years, but has commonly carried name="q".
    search_box = driver.find_element(By.NAME, "q")
    search_box.send_keys("testing examples")

    # 3. Click a button / submit.
    # Pressing Enter is generally more reliable than locating the submit
    # button, which autocomplete suggestions can obscure.
    search_box.send_keys(Keys.RETURN)

    # 4. Follow a link.
    first_result = driver.find_element(By.CSS_SELECTOR, "a")
    first_result.click()
finally:
    driver.quit()
Selenium + Rust

There's no official Rust binding from the Selenium project itself — thirtyfour (whose name nods to selenium's atomic number, 34) is the de facto Selenium/WebDriver client for Rust. It needs a running chromedriver (or similar) at the given URL, the same way the two examples above need a local driver/browser too.

use thirtyfour::prelude::*;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let caps = DesiredCapabilities::chrome();
    let driver = WebDriver::new("http://localhost:9515", caps).await?;

    // 1. Browse to the site.
    driver.goto("https://www.google.com").await?;

    // 2. Use the search box.
    // Google's search input has drifted between <input> and <textarea>
    // over the years, but has commonly carried name="q".
    let search_box = driver
        .query(By::Name("q"))
        .desc("Google search box")
        .single()
        .await?;

    // 3. Click a button / submit.
    // \u{E007} is the WebDriver "Enter" key; sending it is generally more
    // reliable than locating the submit button, which autocomplete
    // suggestions can obscure.
    search_box.send_keys("testing examples\u{E007}").await?;

    // 4. Follow a link.
    let first_result = driver
        .query(By::Css("a"))
        .desc("First result link")
        .first()
        .await?;
    first_result.click().await?;

    driver.quit().await?;
    Ok(())
}

Playwright

Playwright has official bindings in JavaScript, Python, .NET, and Java; Rust support is community-maintained rather than official.

Playwright + JavaScript
import { chromium } from 'playwright';

const browser = await chromium.launch();

try {
  const page = await browser.newPage();

  // 1. Browse to the site.
  await page.goto('https://www.google.com');

  // 2. Use the search box.
  // Google's search input has drifted between <input> and <textarea>
  // over the years, but has commonly carried name="q".
  await page.fill('[name="q"]', 'testing examples');

  // 3. Click a button / submit.
  // Pressing Enter is generally more reliable than locating the submit
  // button, which autocomplete suggestions can obscure.
  await page.keyboard.press('Enter');

  // 4. Follow a link.
  await page.click('a');
} finally {
  await browser.close();
}
Playwright + Python
from playwright.sync_api import sync_playwright

def demo() -> None:
    """Search Google and follow the first result."""

    with sync_playwright() as p:
        browser = p.chromium.launch()

        try:
            page = browser.new_page()

            # 1. Browse to the site.
            page.goto("https://www.google.com")

            # 2. Use the search box.
            # Google's search input has drifted between <input> and
            # <textarea> over the years, but has commonly carried name="q".
            page.fill('[name="q"]', "testing examples")

            # 3. Click a button / submit.
            # Pressing Enter is generally more reliable than locating the
            # submit button, which autocomplete suggestions can obscure.
            page.keyboard.press("Enter")

            # 4. Follow a link.
            page.click("a")
        finally:
            browser.close()


if __name__ == "__main__":
    demo()
Playwright + Rust

Be careful which crate you install. playwright-rs (padamson/playwright-rust) is actively maintained but still pre-1.0 and stabilising its API — it's the one used below. The older crate published on crates.io simply as playwright (octaltree/playwright-rust) has been abandoned since 2022; don't reach for that one.

use playwright_rs::Playwright;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let pw = Playwright::launch().await?;
    let browser = pw.chromium().launch().await?;
    let page = browser.new_page().await?;

    // 1. Browse to the site.
    page.goto("https://www.google.com", None).await?;

    // 2. Use the search box.
    // Google's search input has drifted between <input> and <textarea>
    // over the years, but has commonly carried name="q".
    let search_box = page.locator("[name='q']");
    search_box.fill("testing examples", None).await?;

    // 3. Click a button / submit.
    // Pressing Enter is generally more reliable than locating the submit
    // button, which autocomplete suggestions can obscure.
    search_box.press("Enter", None).await?;

    // 4. Follow a link.
    let first_result = page.locator("a").first();
    first_result.click(None).await?;

    browser.close().await?;
    Ok(())
}

Back to examples Google Maps examples