arsenic

repository·main·Indexed 16 days ago

https://github.com/hennge/arsenic

An asynchronous WebDriver client built on top of asyncio for browser automation. Arsenic enables testing web applications, load testing, web scraping, and website automation using the Webdriver specification. It supports managing multiple web drivers concurrently and integrating browser control into asynchronous web servers without blocking the event loop. Key features include support for action chains for mouse and keyboard sequences, and integration with pytest-asyncio for testing async web applications.

Tokens
15.5K
Snippets
63
Records
81
Agent score
62%

What's inside arsenic

  1. Combine multiple device actions using the OR operator (|)

    main

    A Tick represents an action tick that can contain multiple actions across different devices. You can combine actions from different devices (e.g., a keyboard press and a mouse movement) into a single Tick using the bitwise OR operator (|).

    # Combining a keyboard key down and a mouse move into one tick
    tick = keyboard.down('a') | mouse.move_to(element)
  2. Understand the asynchronous model of arsenic

    main

    Arsenic allows you to control web browsers from asynchronous Python code (e.g., using asyncio, aiohttp, or Tornado).

    Critical Constraint: While the arsenic library itself is asynchronous, the underlying web drivers are not. This means you must call the arsenic APIs in sequence within your async tasks. The primary benefit of using arsenic is the ability to manage multiple web drivers concurrently (asynchronously) or to integrate web driver control into an asynchronous web server without blocking the event loop.

  3. Use Action Chains for mouse and keyboard sequences

    main

    Arsenic supports action chains, which allow you to define a sequence of mouse and/or keyboard actions to be performed either in sequence or in parallel.

    Note on Browser Support: Action chains are natively supported by only a few browsers. For other browsers, Arsenic attempts to emulate these actions using older APIs, but emulation is limited to a single mouse input.

  4. Quickstart with Arsenic and Firefox

    main

    Arsenic is an asynchronous webdriver client built on asyncio. You can start a local browser session by using get_session with a driver service (like Geckodriver) and a browser implementation (like Firefox).

    To use it, wrap the session in an async with block to ensure proper cleanup. Within the session, you can navigate to URLs using await session.get(), locate elements with timeouts using await session.wait_for_element(), and interact with elements like retrieving text via await element.get_text().

    from arsenic import get_session
    from arsenic.browsers import Firefox
    from arsenic.services import Geckodriver
    
    async def example():
        # Runs geckodriver and starts a firefox session
        async with get_session(Geckodriver(), Firefox()) as session:
              # go to example.com
              await session.get('http://example.com')
              # wait up to 5 seconds to get the h1 element from the page
              h1 = await session.wait_for_element(5, 'h1')
              # print the text of the h1 element
              print(await h1.get_text())
  5. Install arsenic and set up the environment

    main

    To use arsenic, you need Python 3.6, Firefox, and geckodriver.

    1. Install geckodriver: Download the latest release for your OS, extract the binary, and place it in your project directory. On macOS or Linux, ensure it is executable by running chmod +x geckodriver.
    2. Create a virtual environment: Use python3.6 -m venv env.
    3. Upgrade pip: Run env/bin/pip install --upgrade pip.
    4. Install arsenic: Install the pre-release version using env/bin/pip install --pre arsenic.
    python3.6 -m venv env
    env/bin/pip install --upgrade pip
    env/bin/pip install --pre arsenic
  6. Implement drag and drop using Action Chains

    main

    To implement drag and drop functionality, combine arsenic.actions.Mouse with arsenic.actions.chain and execute the sequence using arsenic.session.Session.preform_actions.

    Below is a helper function pattern for moving the mouse to an element and dragging it by a specific pixel offset.

    from arsenic.actions import Mouse, chain
    
    async def drag_and_drop(session, element, offset_x, offset_y):
        mouse = Mouse()
        actions = chain(
            mouse.move_to(element),
            mouse.click_and_hold(),
            mouse.move_by_offset(offset_x, offset_y),
            mouse.release()
        )
        await session.preform_actions(actions)
  7. Specify absolute paths for service binaries on Windows

    main

    Unlike Unix systems where local services work automatically, Windows requires you to explicitly provide the absolute path to the service binary (e.g., geckodriver.exe) when instantiating a service.

    from arsenic import get_session, services, browsers
    
    async def example():
        service = services.Geckodriver(
            binary='C:\\geckodriver\\geckodriver.exe'
        )
        browser = browsers.Firefox()
        async with get_session(service, browser) as session:
            ...
  8. Add a new browser to the test suite

    main

    To extend the test suite with a new browser, modify tests/conftest.py:

    1. Locate the pytest.fixture decorator for the async def session function.
    2. Add a new function to the params list.
    3. The new function must be an async context manager that accepts the root URL of the application to test as an argument and yields a Session object.