I recently needed to do a small amount of web scraping. This scraping involved pages with an indeterminate amount of JavaScript, so I needed some kind of browser automation (instead of something like Beautiful Soup).
Normally, I'd do this by setting up Selenium with ChromeDriver or geckodriver. However, today I learned that macOS's Safari has built-in WebDriver support!
$ which safaridriver /System/Cryptexes/App/usr/bin/safaridriverTo use it, you need to run safaridriver --enable once. That'll prompt you for your password and will ensure that the safaridriver binary is allowed to control Safari.
From there, I was able to use Selenium (from Python) as normal, with webdriver.Safari as the driver instance:
options = webdriver.SafariOptions() driver = webdriver.Safari(options=options) driver.get("https://example.com")This dovetails really nicely with uv's support for inline script metadata, making it incredibly easy to write self-contained scrapers that Just Work™ on macOS:
from selenium import webdriver def main(): options = webdriver.SafariOptions() driver = webdriver.Safari(options=options) driver.maximize_window() driver.get("https://example.com") input() driver.quit() if __name__ == "__main__": main()And to run it:
uv run --script demo.pyThen, as a cherry on top, it turns out that the macOS runners on GitHub Actions also have safaridriver installed and already enabled by default!
In other words, this Just Works™ on GitHub Actions:
name: Safari WebDriver Demo on: workflow_dispatch: push: branches: - main permissions: {} jobs: check-appointments: runs-on: macos-latest permissions: contents: read steps: - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: persist-credentials: false - name: Set up uv uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e - run: | uv run --script demo.pyNo more mucking with different versions of ChromeDriver or geckodriver, at least for my minimal use case.
Apple's documentation has more details on safaridriver as well.