mirror of
https://git.zavage.net/Zavage-Software/wabot.git
synced 2026-07-21 13:06:08 -06:00
docs: sphinx site — quickstart, sessions guide, page objects, API ref
This commit is contained in:
parent
7e24d3445d
commit
163f71e51b
24
docs/api.rst
Normal file
24
docs/api.rst
Normal file
@ -0,0 +1,24 @@
|
||||
API reference
|
||||
=============
|
||||
|
||||
.. automodule:: wabot
|
||||
:members: browser, sessions, destroy
|
||||
|
||||
.. autoclass:: wabot.Browser
|
||||
:members:
|
||||
|
||||
.. autoclass:: wabot.Page
|
||||
:members:
|
||||
|
||||
.. automodule:: wabot.fields
|
||||
:members: PageObject, TextField, SelectField, CheckField, NullField
|
||||
|
||||
.. automodule:: wabot.pacing
|
||||
:members:
|
||||
|
||||
.. automodule:: wabot.sessions
|
||||
:members:
|
||||
:no-index:
|
||||
|
||||
.. automodule:: wabot.hosts
|
||||
:members: ExternalServer, ManagedService, attach, service_alive
|
||||
14
docs/conf.py
Normal file
14
docs/conf.py
Normal file
@ -0,0 +1,14 @@
|
||||
project = "wabot"
|
||||
author = "Mathew Guest"
|
||||
release = "0.2.0"
|
||||
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.napoleon",
|
||||
]
|
||||
|
||||
# sphinx_rtd_theme registers itself via entry point — do NOT add to extensions
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
autodoc_member_order = "bysource"
|
||||
napoleon_google_docstring = True
|
||||
13
docs/index.rst
Normal file
13
docs/index.rst
Normal file
@ -0,0 +1,13 @@
|
||||
wabot
|
||||
=====
|
||||
|
||||
Stateful Selenium browser automation with sessions that survive the
|
||||
Python process.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
quickstart
|
||||
sessions
|
||||
page-objects
|
||||
api
|
||||
47
docs/page-objects.rst
Normal file
47
docs/page-objects.rst
Normal file
@ -0,0 +1,47 @@
|
||||
Page objects
|
||||
============
|
||||
|
||||
Model each website page as a :class:`wabot.Page` subclass with a
|
||||
class-level ``elements`` map; drive them through one
|
||||
:class:`wabot.Browser`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Inventory(wabot.Page):
|
||||
elements = {
|
||||
"search": ("el", ("id", "search-box")),
|
||||
"region": ("select", ("id", "region")),
|
||||
"instock": ("checkbox", ("id", "in-stock-only")),
|
||||
"rows": ("els", ("css selector", "table#items tr")),
|
||||
}
|
||||
|
||||
Element types
|
||||
-------------
|
||||
|
||||
============ ======================================= =====================
|
||||
Type key Returned wrapper Main methods
|
||||
============ ======================================= =====================
|
||||
``el`` :class:`wabot.TextField` get_value / set_value
|
||||
``select`` :class:`wabot.SelectField` set_value(value|text)
|
||||
``checkbox`` :class:`wabot.CheckField` get/set_checked
|
||||
``els`` list of raw WebElements (selenium API)
|
||||
a class your :class:`wabot.PageObject` subclass whatever you define
|
||||
============ ======================================= =====================
|
||||
|
||||
Missing elements come back as a falsy :class:`wabot.NullField`, so guard
|
||||
with ``if el:`` instead of try/except.
|
||||
|
||||
Inheritance
|
||||
-----------
|
||||
|
||||
Element lookup walks the MRO: subclasses inherit the parent map and can
|
||||
override individual keys — useful for sites with shared page chrome.
|
||||
|
||||
Verification and delegation
|
||||
---------------------------
|
||||
|
||||
``Browser.set_page(PageClass)`` refuses the switch if the page's
|
||||
``verify()`` returns False. Once set, unknown attributes on the Browser
|
||||
delegate to the current page: ``bot.log_in(...)`` calls
|
||||
``bot.page.log_in(...)``. After any trapped failure the Browser refuses
|
||||
further actions until ``bot.reset()``.
|
||||
44
docs/quickstart.rst
Normal file
44
docs/quickstart.rst
Normal file
@ -0,0 +1,44 @@
|
||||
Quickstart
|
||||
==========
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
uv add wabot # or: pip install .
|
||||
|
||||
You also need Firefox or Chromium. Driver binaries (geckodriver /
|
||||
chromedriver) are found on PATH or downloaded automatically by Selenium
|
||||
Manager.
|
||||
|
||||
First scrape
|
||||
------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import wabot
|
||||
|
||||
class Login(wabot.Page):
|
||||
elements = {
|
||||
"username": ("el", ("id", "username")),
|
||||
"password": ("el", ("id", "password")),
|
||||
"submit": ("el", ("id", "submit-btn")),
|
||||
}
|
||||
|
||||
def verify(self):
|
||||
return "Login" in self.driver.title
|
||||
|
||||
def log_in(self, user, password):
|
||||
self["username"].set_value(user)
|
||||
self["password"].set_value(password)
|
||||
return self["submit"].click_and_go()
|
||||
|
||||
bot = wabot.browser(browser="firefox", headless=True)
|
||||
bot.driver.get("https://example.com/login")
|
||||
bot.set_page(Login)
|
||||
bot.log_in("me", "secret")
|
||||
|
||||
By default wabot paces itself like a human (multi-second random delays,
|
||||
randomized click positions). Pass ``pacing=wabot.NoPacing()`` for full
|
||||
speed on sites you trust.
|
||||
51
docs/sessions.rst
Normal file
51
docs/sessions.rst
Normal file
@ -0,0 +1,51 @@
|
||||
Persistent sessions
|
||||
===================
|
||||
|
||||
The flagship feature: a browser created with a ``session`` name survives
|
||||
the Python process, and any later process can pick it up by name.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import wabot
|
||||
|
||||
bot = wabot.browser(session="scraper1", browser="firefox")
|
||||
bot.driver.get("https://example.com/login")
|
||||
# ... log in, then the process exits; the browser stays open ...
|
||||
|
||||
# hours later, a different process:
|
||||
bot = wabot.browser(session="scraper1", browser="firefox")
|
||||
print(bot.driver.current_url) # still logged in
|
||||
|
||||
How it works
|
||||
------------
|
||||
|
||||
A session is just ``(executor_url, session_id)`` stored as JSON in the
|
||||
platform data dir. Nothing is pickled. The browser is hosted by a driver
|
||||
service that outlives Python:
|
||||
|
||||
* **Managed (default):** wabot spawns chromedriver/geckodriver as a
|
||||
detached process and records its port and pid.
|
||||
* **External:** pass ``host="http://localhost:4444"`` to use a Selenium
|
||||
Grid or standalone server you run yourself. wabot then never kills the
|
||||
server — only the session.
|
||||
|
||||
Reattaching constructs a driver that *adopts* the saved session id
|
||||
instead of creating a new session. Dead sessions (browser closed, server
|
||||
gone, record older than 3 days) are pruned automatically and a fresh
|
||||
browser is created instead.
|
||||
|
||||
Housekeeping
|
||||
------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
wabot.sessions() # ["scraper1", ...]
|
||||
wabot.destroy("scraper1") # quit browser, stop managed service, forget
|
||||
|
||||
Selenium Grid caveat
|
||||
--------------------
|
||||
|
||||
Grid 4 kills idle sessions after **5 minutes** by default. If your
|
||||
process sleeps longer between reattaches, raise it::
|
||||
|
||||
java -jar selenium-server.jar standalone --session-timeout 86400
|
||||
Loading…
Reference in New Issue
Block a user