dbgidchromium
Version: 1.1.9
Android-focused browser automation toolkit for DBG ID Browser (com.dbgid.browser).
Python talks to the Android browser over a local socket. Protocol values are base64-encoded (request and response), similar to Selenium-style WebDriver APIs with extra Playwright-style locators, network capture, header spoofing, and session resume helpers.
| Package | dbgidchromium |
| Version | 1.1.9 |
| Python | >= 3.10 |
| License | MIT |
| Browser package | com.dbgid.browser |
| Source API | __init__.py |
| Alias | Chrome = WebDriver, AsyncChrome = AsyncWebDriver |
import dbgidchromium as chromium
print(chromium.__version__) # 1.1.9
Requirements
- DBG ID Browser installed on the Android device/emulator.
- Shell access able to start activities/services (
am/cmd activity), preferably via Shizukurishon Termux. - Python 3.10+ (stdlib only; no extra pip deps required for core).
Optional env:
| Env | Purpose |
|---|---|
DBGIDCHROMIUM_RISH / DBGID_RISH |
Path to rish (default ~/bin/rish) |
DBGIDCHROMIUM_ANDROID_SHELL / DBGID_ANDROID_SHELL |
auto (default), rish, direct |
DBGIDCHROMIUM_GUI_FALLBACK / DBGID_GUI_FALLBACK |
Allow GUI fallback when headless launch fails |
Install
# from source (this repo root)
pip install -e .
# or plain path import
export PYTHONPATH=/path/to/dbgidchromium/..
python -c "import dbgidchromium; print(dbgidchromium.__version__)"
Packaging maps the repo root as package dbgidchromium and ships ip2asn-v4-u32.tsv for IP/ASN spoof helpers.
Quick start
import dbgidchromium as chromium
from dbgidchromium import By, Keys, WebDriverWait, presence_of_element_located
driver = chromium.WebDriver(gui=False, debug=True)
try:
driver.goto(
"https://example.com",
timeout=45,
wait_until="javascript",
clear_browser_state=True,
log=True,
)
print(driver.title)
print(driver.current_url)
el = driver.find_element(By.CSS_SELECTOR, "h1")
print(el.text)
driver.locator("a").first.click()
finally:
driver.close()
Context manager:
with chromium.WebDriver(gui=False) as driver:
driver.goto("https://example.com", wait_until="complete")
print(driver.page_source[:200])
Alias:
from dbgidchromium import Chrome # same as WebDriver
driver = Chrome(gui=True)
Architecture (short)
Python (dbgidchromium)
│ TCP socket + base64 DictMap payload
▼
DBG ID Browser (Android WebView / service)
SplashActivity → GUI mode
MainService → headless / gui=False
WebDriversubclassesRemoteConnection(a listeningsocket.socket).- Launch builds a
webdriver://com.dbgid.browser/?data=<base64-json>intent. - Commands are string names from
Command("get","find element", …). detach()keeps the browser open;close()ends the WebDriver session.
Module constants
| Name | Value / meaning |
|---|---|
__version__ |
"1.1.9" |
ANDROID_PACKAGE |
"com.dbgid.browser" |
ANDROID_ACTIVITY |
".SplashActivity" |
ANDROID_SERVICE |
".MainService" |
EXECUTE_SCRIPT_RESULT_ATTR |
DOM attr for script result side-channel |
EXECUTE_SCRIPT_STATUS_ATTR |
DOM attr for script status |
EXECUTE_SCRIPT_REQUEST_ATTR |
DOM attr for script request id |
REQUEST_INTERCEPTOR_WINDOW_NAME_PREFIX |
Prefix used by request interceptor |
REQUEST_INTERCEPTOR_DEFAULT_TYPES |
("image", "audio", "video") |
REQUEST_INTERCEPTOR_TYPE_ALIASES |
Maps aliases (css→stylesheet, xhr→connect, …) |
IP2ASN_DB_FILE |
Path to bundled ip2asn-v4-u32.tsv |
no_encode_again |
Global encode flag (default False) |
Chrome |
Alias of WebDriver |
AsyncChrome |
Alias of AsyncWebDriver |
Exceptions
All extend WebDriverException except the base itself.
| Class | When |
|---|---|
WebDriverException |
Generic driver/protocol error |
NoSuchElementException |
Element not found |
ApplicationClosed |
Browser/app closed while talking |
CrossOriginFrameException |
Cross-origin iframe DOM access blocked |
InvalidElementStateException |
Element state not valid for action |
UnexpectedTagNameException |
Wrong tag (e.g. Select on non-<select>) |
from dbgidchromium import NoSuchElementException, By
try:
driver.find_element(By.CSS_SELECTOR, "#missing")
except NoSuchElementException as e:
print("not found:", e)
By — locator strategies
class By:
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
driver.find_element(By.CSS_SELECTOR, "#login")
driver.find_elements(By.XPATH, "//button")
driver.find_element(By.NAME, "email")
driver.find_element(By.CLASS_NAME, "btn-primary")
driver.find_element(By.TAG_NAME, "h1")
driver.find_element(By.LINK_TEXT, "Sign in")
driver.find_element(By.PARTIAL_LINK_TEXT, "Sign")
Important: By.ID limitation
On some DBG ID Browser builds, By.ID may return empty because the browser side treats the value like a bare querySelector string instead of getElementById / #id.
Workaround — prefer CSS with #:
# may fail on affected browser builds
driver.find_element(By.ID, "text-input")
# reliable
driver.find_element(By.CSS_SELECTOR, "#text-input")
driver.query_selector("#text-input")
Keys
Android keycodes used with send_key / locator press:
class Keys:
ENTER = 66
TAB = 61
el.send_key(Keys.ENTER)
driver.locator("#q").press("Enter") # locator path
Command — wire command names
Low-level protocol action strings. Usually you call WebDriver methods instead of building these by hand.
| Attribute | Wire value |
|---|---|
CLOSE |
close |
GET |
get |
FIND_ELEMENT / FIND_ELEMENTS |
find element / find elements |
CLICK_JAVA |
click java |
EXECUTE_SCRIPT |
execute script |
GET_ATTRIBUTE / SET_ATTRIBUTE / REMOVE_ATTRIBUTE |
attribute ops |
SEND_KEY / SEND_TEXT |
input |
PAGE_SOURCE / TITLE / CURRENT_URL |
page meta |
GET_COOKIE(S) / SET_COOKIE / CLEAR_COOKIE(S) / DELETE_ALL_COOKIE |
cookies |
GET/SET_LOCAL_STORAGE / GET/SET_SESSION_STORAGE / clears |
storage |
GET/SET_USER_AGENT / GET/SET_HEADERS |
identity |
SET_PROXY / SET_REQUEST_INTERCEPTOR |
network |
SWIPE / SWIPE_UP / SWIPE_DOWN / SCROLL_TO |
gestures |
WINDOW_HANDLES / CURRENT_WINDOW_HANDLE / SWITCH_TO_WINDOW |
tabs |
SCREENSHOT |
screenshot |
WAIT_UNTIL_ELEMENT / WAIT_UNTIL_NOT_ELEMENT |
waits |
GET_RECAPTCHA_V3_TOKEN |
reCAPTCHA v3 |
OVERRIDE_JS_FUNCTION |
inject/override JS |
INIT |
session bootstrap |
DictMap / encode helpers
Protocol dict that stringifies values in the browser’s expected form.
from dbgidchromium import DictMap, b64encode, b64decode, decode_data
payload = DictMap({"command": "get", "url": "https://example.com"})
# WebDriver uses DictMap internally when sending commands
print(b64encode("hello"))
print(b64decode(b64encode("hello")))
| Function | Role |
|---|---|
b64encode(value) |
Encode str/value → base64 text (with decode_data cleanup) |
b64decode(value) |
Decode base64; coerces true/false/null/JSON-ish |
decode_data(data) |
Unicode-escape / HTML-unescape cleanup |
RemoteConnection
Base of WebDriver. Owns the listening socket server the Android app connects to.
# constructed via WebDriver(...); rarely used alone
# __init__(accept_time_out)
# init_socket_server()
WebDriver (core class)
WebDriver(
gui=True,
pip_mode=False,
lang="en",
debug=False,
accept_time_out=60,
recv_time_out=60 * 60,
gui_fallback=None,
resume=False,
)
| Parameter | Default | Meaning |
|---|---|---|
gui |
True |
True → Activity UI; False → headless service path |
pip_mode |
False |
Picture-in-picture related launch flag |
lang |
"en" |
Browser language hint |
debug |
False |
Extra debug prints |
accept_time_out |
60 |
Seconds to accept Android socket connect |
recv_time_out |
3600 |
Socket recv timeout |
gui_fallback |
env / auto | If headless fails, may fall back to GUI |
resume |
False |
Attach to existing live tab (see session resume) |
Instance attributes (notable)
| Attribute | Meaning |
|---|---|
gui / requested_gui |
Effective / requested GUI mode |
debug |
Debug flag |
switch_to |
SwitchTo helper (driver.switch_to.frame(...)) |
accept_time_out / recv_time_out |
Timeouts |
_frame_stack |
Nested iframe context stack (internal) |
Supports with (__enter__ / __exit__ → close()).
Lifecycle
| Method | Behavior |
|---|---|
close() |
End WebDriver session (sends close; tears down connection) |
detach() |
Drop Python socket without closing Android browser/tab |
resume_browser_session(...) / resume_chrome() |
New Python driver attached to live browser tab |
continue_browser_session() / continue_chrome() |
Continue helpers |
detach_browser_session(driver) |
Module helper around detach |
driver = chromium.WebDriver(gui=True)
driver.goto("https://example.com")
driver.detach() # leave tab open
# later, new process/shell:
driver = chromium.resume_browser_session(gui=False, debug=True)
print(driver.current_url)
driver.close()
Static Android helpers:
WebDriver.force_stop_command(package) # force-stop package string builder
WebDriver.home_command() # home intent helper
WebDriver.wait(delay) # sleep wrapper
Module launch helpers:
from dbgidchromium import (
start_browser_activity,
start_browser_service,
foreground_browser,
screencap_png,
)
start_browser_activity(data=None, wait=True, ...) # am start Activity
start_browser_service(data=None, ...) # headless MainService
foreground_browser() # bring UI forward, keep tabs
png_bytes = screencap_png("/sdcard/shot.png") # Android display PNG
Navigation
get(url, **kwargs)
Low-level navigate (no full wait pipeline of goto).
Optional kwargs:
use_cookie_from_requests— load cookies before GETcustom_headers/headers— apply headers before GET
goto(url, **kwargs) — preferred
High-level navigation + wait + optional spoof/headers/interceptor/clear.
| Kwarg | Default | Meaning |
|---|---|---|
wait_until |
"javascript" (GUI); headless defaults differ |
Readiness mode |
timeout |
30 |
Max wait seconds |
poll_frequency |
~0.06 headless / ~0.12 GUI |
Poll interval |
settle_time |
~0.15 headless / ~0.8 GUI |
Extra settle after ready |
locator / wait_for |
None |
Also wait for element |
clear_browser_state |
True |
clear_browser() before first nav |
use_spoof |
None |
IP/ASN header spoof (True = random) |
custom_headers / headers |
None |
Extra HTTP headers |
interceptor / interceptor_mime_types / block_mime_types |
None |
Block resource types |
fallback_wait_until |
None |
Softer wait if primary times out |
fallback_after |
None |
When to try fallback |
log |
True |
Log wait progress |
wait_until modes:
| Value | Meaning |
|---|---|
url_only |
URL changed / minimal |
domcontentloaded |
DOMContentLoaded-ish readiness |
realtime |
Early interactive/render signal |
javascript |
JS-ready (default for GUI) |
complete / load |
Full load style readiness |
Headless (gui=False) without explicit wait_until defaults to url_only, or domcontentloaded if a locator is passed.
driver.goto(
"https://www.google.com",
wait_until="javascript",
timeout=45,
poll_frequency=0.10,
settle_time=0.35,
clear_browser_state=True,
use_spoof=True,
interceptor=["image", "font", "media"],
custom_headers={"Accept-Language": "en-US"},
log=True,
)
Related:
driver.go_back()
driver.go_forward()
driver.reload()
driver.set_content("<html><body>hi</body></html>", wait_until="javascript", timeout=30)
html = driver.content() # alias-style page HTML helper
src = driver.page_source # property
title = driver.title # property
url = driver.current_url # property
SPA wait
details = driver.wait_for_spa_ready(
timeout=30,
selector="#app",
min_html_length=1200,
poll_frequency=0.1,
stable_time=0.35,
)
# aliases: wait_for_react_ready, wait_for_nextjs_ready (on async wrapper too)
driver.wait_for_navigation(
locator=(By.CSS_SELECTOR, "h1"),
timeout=30,
poll_frequency=0.1,
settle_time=0.75,
wait_until="javascript",
)
Finding elements
Classic Selenium-style
el = driver.find_element(By.CSS_SELECTOR, "#email")
els = driver.find_elements(By.CSS_SELECTOR, "input")
driver.find_element_by_css_selector("#email")
driver.find_element_by_xpath("//input[@name='q']")
driver.find_element_by_name("q")
driver.find_element_by_class_name("btn")
driver.find_element_by_tag_name("button")
driver.find_element_by_link_text("Docs")
driver.find_element_by_partial_link_text("Doc")
driver.find_element_by_id("email") # prefer CSS #email if By.ID flaky
driver.query_selector("#email") # CSS
driver.querySelector("#email") # camelCase alias
driver.query_selector_all(".item")
driver.querySelectorAll(".item")
Playwright-style locators
loc = driver.locator("css=button.submit") # or plain CSS / xpath=... / text=...
loc = driver.locator("#email")
loc = driver.locator("xpath=//button")
loc = driver.locator("text=Sign in")
loc = driver.locator("//button") # xpath if starts with // or (
loc.click()
loc.fill("user@example.com")
loc.type("slow text")
loc.press("Enter")
loc.dblclick()
loc.hover()
loc.check() / loc.uncheck() / loc.set_checked(True)
loc.is_checked() / loc.is_visible() / loc.is_enabled()
loc.text_content() / loc.inner_text() / loc.inner_html()
loc.input_value()
loc.get_attribute("href")
loc.evaluate("el => el.tagName")
loc.wait_for(state="visible", timeout=30) # visible / attached-style states
loc.count()
loc.all()
loc.nth(0) / loc.first / loc.last
loc.filter(has_text="Save")
loc.locator(".child") # nested
loc.all_text_contents()
el = loc.element_handle() # -> WebElement
Semantic getters:
driver.get_by_text("Sign in", exact=True)
driver.get_by_role("button", name="Submit")
driver.get_by_label("Email")
driver.get_by_placeholder("Search")
driver.get_by_test_id("login-form")
ElementLocator scopes a locator under a parent WebElement.
WebElement
Returned by find_element* / locator element_handle().
Actions
el.click()
el.click_java() # JS click path
el.clear()
el.focus()
el.send_text("hello")
el.send_key(Keys.ENTER)
el.set_attribute("data-x", "1", is_string=True)
el.remove_attribute("disabled")
Find under element
Same find_element* / query_selector* family as driver, scoped to the element.
child = el.find_element(By.CSS_SELECTOR, "span.label")
el.query_selector_all("li")
Properties / attributes
| Member | Type | Notes |
|---|---|---|
text |
property | Visible / text content |
value |
property + setter | Form value |
inner_html |
property + setter | |
outer_html |
property + setter | |
height / width |
property | |
position |
property | Position info |
disabled |
property + setter | |
is_displayed |
property | |
read_only |
property | |
get_attribute(name) |
method |
print(el.text, el.value, el.is_displayed)
el.value = "new"
print(el.get_attribute("class"))
Resilient interaction helpers
Retry-oriented helpers (visibility/clickable waits, multiple attempts):
driver.typing_like_human("#email", "user@example.com", press_enter=False)
driver.ensure_typing("#email", "user@example.com", press_enter=True)
driver.ensure_click("button[type=submit]")
driver.ensure_option_select("select#country", "US") # value / text / index-like
driver.ensure_checked_checkbox("input#terms")
token = driver.get_turnstile_token(
selector="input[name='cf-turnstile-response']",
timeout=10,
poll_frequency=0.25,
)
ensure_* methods retry (~5 attempts) with short backoff; raise last error / TimeoutError on failure.
Waits
WebDriverWait
from dbgidchromium import (
WebDriverWait,
presence_of_element_located,
visibility_of_element_located,
invisibility_of_element_located,
element_to_be_clickable,
By,
)
wait = WebDriverWait(driver, timeout=10, poll_frequency=0.2)
el = wait.until(visibility_of_element_located((By.CSS_SELECTOR, "#ready")))
wait.until_not(presence_of_element_located((By.CSS_SELECTOR, ".spinner")))
Expected-condition factories take a locator tuple (By.*, value) and return predicates for until / until_not.
On timeout: TimeoutError("Time out to wait element").
Frames / iframes
frames = driver.detect_iframes(include_elements=False)
# [{id, name, src, same_origin, ...}, ...]
driver.switch_to_iframe(0) # index
driver.switch_to_iframe("frame-one") # name/id
driver.switch_to_iframe(css_element) # element
driver.switch_to_frame(...) # alias of switch_to_iframe
driver.switch_to_parent_frame()
driver.switch_to_default_content()
# Selenium-style facade
driver.switch_to.frame(0)
driver.switch_to.iframe("frame-one")
driver.switch_to.parent_frame()
driver.switch_to.default_content()
driver.switch_to.window(handle)
FrameLocator (Playwright-style)
fl = driver.frame_locator("#frame-one")
print(fl.info()) # tag/id/name/src/same_origin/...
print(fl.is_same_origin(), fl.is_cross_origin())
fl.locator("#inside").fill("hi")
fl.get_by_text("hello")
fl.get_by_role("button", name="Go")
nested = fl.frame_locator("#frame-two")
# cross-origin: DOM from parent is blocked; open src top-level if needed
if fl.is_cross_origin():
fl.open() # driver.get(iframe src)
NestedFrameLocator / FrameScopedLocator support nested frame trees. Cross-origin frames raise / mark CrossOriginFrameException paths — Chromium SOP still applies.
Tabs / pages
handles = driver.window_handles # list; headless often single-tab
current = driver.current_window_handle
driver.switch_to_window(handles[0])
pages = driver.pages() # list[PageHandle]
page = driver.current_page # property
page = driver.new_page("https://example.com")
page.bring_to_front()
print(page.url, page.title)
page.locator("h1").text_content()
page.frame_locator("iframe")
page.evaluate("() => document.title")
page.screenshot(path="tab.png")
Select — <select> helper
from dbgidchromium import Select
select = Select(driver.find_element(By.CSS_SELECTOR, "select#country"))
print(select.options)
print(select.all_selected_options)
print(select.first_selected_option)
select.select_by_value("us")
select.select_by_index(2)
select.select_by_visible_text("United States")
select.deselect_all() # multi-select
select.deselect_by_value("us")
select.deselect_by_index(2)
select.deselect_by_visible_text("United States")
Non-<select> elements → UnexpectedTagNameException.
JavaScript
title = driver.execute_script("return document.title")
# *args supported; elements can round-trip depending on marshal path
driver.execute_script("arguments[0].style.border='2px solid red'", el)
driver.override_js_function(long_bootstrap_script)
execute_script uses a marshaling wrapper + optional DOM attribute side-channel (EXECUTE_SCRIPT_*_ATTR) when direct eval is restricted (CSP). Kwargs include side_channel_polls, side_channel_sleep, prefer_dom_fallback.
Returning DOM nodes may yield WebElement instances.
Cookies, storage, headers, UA, proxy
driver.set_cookie("session", "abc", url="https://example.com")
print(driver.get_cookie("session", url="https://example.com"))
print(driver.get_cookies(url="https://example.com"))
driver.clear_cookie("session")
driver.clear_cookies()
driver.delete_all_cookie()
driver.set_local_storage("k", "v", is_string=True)
print(driver.get_local_storage())
driver.clear_local_storage()
driver.set_session_storage("k", "v")
print(driver.get_session_storage())
driver.clear_session_storage()
print(driver.user_agent)
driver.user_agent = "MyAgent/1.0"
print(driver.headers) # property
driver.headers = {"X-Debug": "1"} # setter
driver.set_proxy("127.0.0.1", 8080)
driver.clear_browser(clear_cache=True)
Load cookies from a requests-like cookie jar / list:
from dbgidchromium import load_cookies_from_requests
load_cookies_from_requests(driver, cookies, url="https://example.com")
# or
driver.load_cookies_from_requests(cookies, url="https://example.com")
Module helpers: apply_custom_headers(driver, headers, merge=True), normalize_custom_headers(headers), clear_browser(driver, clear_cache=True), goto(driver, url, **kwargs).
IP / ASN spoof headers
Uses bundled ip2asn-v4-u32.tsv.
from dbgidchromium import generate_ip, use_spoof, AsnHit
info = generate_ip()
# {"ip": "...", "country": "US", "name": "...", "asn": 1234}
headers = driver.use_spoof(True) # random public IP + related headers
headers = driver.use_spoof(info) # explicit
headers = use_spoof(driver, spoof=info, merge=True)
# or via goto
driver.goto("https://httpbin.org/headers", use_spoof=True)
Related: load_ip2asn_u32_tsv, lookup_asn, random_public_ip_from_db, normalize_spoof, build_spoof_headers.
AsnHit dataclass fields: ip, asn, country, name.
Typical spoof headers include client IP / ASN-style forwarding headers derived from the hit.
Request interceptor (block resource types)
Pass to goto(..., interceptor=...) or set via protocol command.
Accepted types (after alias normalize): e.g. image, audio, video, media, font, stylesheet, script, document, connect, …
Aliases examples: img→image, css→stylesheet, xhr/fetch/ajax→connect, js→script.
driver.goto(
"https://example.com",
interceptor=["image", "font", "media"], # block these
)
Default type set constant: REQUEST_INTERCEPTOR_DEFAULT_TYPES = ("image", "audio", "video").
Network capture (fetch / XHR)
Injects JS hooks; stores records in-page.
driver.network_capture_start(clear=True, max_body_chars=200000)
driver.goto("https://example.com/app", wait_until="javascript")
# ... interact ...
records = driver.network_capture_get(include_document=False)
driver.network_capture_save("capture.json", include_document=False)
driver.network_capture_stop()
# aliases: start_network_capture / stop_network_capture
build_network_capture_script(clear=True, enabled=True, max_body_chars=200000) returns the raw JS if you need to inject manually.
Screenshots & gestures
png = driver.get_screenshot_as_png(use_rish=None, timeout=20)
driver.save_screenshot("/sdcard/page.png")
driver.get_screenshot_as_file("/sdcard/page.png")
driver.screenshot(path="/sdcard/page.png") # or as_bytes=True
driver.scroll_to(0, 500)
driver.swipe(100, 800, 100, 200, speed=1)
driver.swipe_up()
driver.swipe_down()
driver.click_java(x=120, y=400) # coordinate click via Java side
screencap_png(path=None) captures the full Android display (not only WebView) via screencap, with rish/file/base64 fallbacks.
reCAPTCHA / Turnstile helpers
token = driver.get_recaptcha_v3_token(action="login")
cf = driver.get_turnstile_token(
selector="input[name='cf-turnstile-response']",
timeout=10,
)
Async API
Thin asyncio wrappers around sync driver (run blocking calls in a worker).
import asyncio
from dbgidchromium import AsyncWebDriver, AsyncChrome
async def main():
async with AsyncWebDriver(gui=False, debug=True) as driver:
await driver.goto("https://example.com", wait_until="javascript")
loc = driver.locator("h1")
print(await loc.text_content())
await driver.screenshot(path="/sdcard/async.png")
asyncio.run(main())
Classes:
| Class | Wraps |
|---|---|
AsyncWebDriver |
WebDriver |
AsyncWebElement |
WebElement |
AsyncLocator |
Locator |
AsyncFrameLocator |
FrameLocator |
AsyncPageHandle |
PageHandle |
AsyncWebDriver supports __aenter__ / __aexit__, goto, execute_script, locator helpers, network capture, screenshots, etc. Unknown attrs proxy to the underlying sync driver as async callables when callable.
Module-level function index
| Function | Summary |
|---|---|
screencap_png(path=None, use_rish=None, timeout=20) |
Full-display PNG bytes |
start_browser_activity(...) |
Start SplashActivity / intent |
start_browser_service(...) |
Start MainService headless |
foreground_browser(...) |
Foreground UI without wiping tabs |
decode_data / b64encode / b64decode |
Protocol codecs |
load_cookies_from_requests(driver, cookies, url="") |
Import cookies |
clear_browser(driver, clear_cache=True) |
Clear via driver |
generate_ip / lookup_asn / load_ip2asn_u32_tsv / … |
ASN DB |
normalize_spoof / build_spoof_headers / use_spoof |
Spoof headers |
normalize_custom_headers / apply_custom_headers |
Header merge/set |
build_network_capture_script(...) |
JS capture bootstrap |
goto(driver, url, **kwargs) |
Functional goto |
find_element(driver, locator, command) |
Wait-condition helper |
presence_of_element_located / visibility_of_element_located / invisibility_of_element_located / element_to_be_clickable |
Expected conditions |
resume_browser_session / resume_chrome / continue_browser_session / continue_chrome / detach_browser_session |
Session continuity |
End-to-end examples
1) Headless smoke + CSS locators
import dbgidchromium as chromium
from dbgidchromium import By
with chromium.WebDriver(gui=False, debug=True) as driver:
driver.goto("https://example.com", wait_until="javascript", timeout=30)
h1 = driver.find_element(By.CSS_SELECTOR, "h1")
print(h1.text)
driver.locator("a").first.click()
print(driver.current_url)
2) Human-like login form
driver = chromium.WebDriver(gui=True, debug=True)
driver.goto("https://example.com/login", wait_until="javascript")
driver.ensure_typing("#email", "user@example.com")
driver.ensure_typing("#password", "secret", press_enter=False)
driver.ensure_checked_checkbox("#remember")
driver.ensure_click("button[type=submit]")
driver.wait_for_spa_ready(selector="#dashboard", timeout=20)
print(driver.title)
driver.close()
3) Iframe walk
driver.goto(local_fixture_url, wait_until="javascript")
frames = driver.detect_iframes()
driver.switch_to_iframe(0)
print(driver.find_element(By.CSS_SELECTOR, "#inside").text)
driver.switch_to_default_content()
# or
driver.frame_locator("#frame-one").locator("#inside").text_content()
4) Network capture + header spoof
with chromium.WebDriver(gui=False) as driver:
driver.network_capture_start()
driver.goto(
"https://httpbin.org/headers",
use_spoof=True,
interceptor=["image", "font"],
wait_until="javascript",
)
print(driver.locator("body").inner_text()[:500])
driver.network_capture_save("out.json")
5) Wait for element
from dbgidchromium import WebDriverWait, visibility_of_element_located, By
driver.goto("https://example.com")
el = WebDriverWait(driver, 15).until(
visibility_of_element_located((By.CSS_SELECTOR, "h1"))
)
print(el.text)
6) Async
import asyncio
from dbgidchromium import AsyncChrome
async def run():
async with AsyncChrome(gui=False) as page:
await page.goto("https://example.com", wait_until="complete")
print(await page.locator("h1").text_content())
asyncio.run(run())
7) Run bundled example
python example.py
# prints: dbgidchromium version: 1.1.9
# runs local iframe DOM smoke + google wait_until modes
Design notes / limitations
- Android-only transport — needs DBG ID Browser + shell start permissions.
By.IDmay be unreliable — useBy.CSS_SELECTORwith#id(browser-side issue on some builds).- Headless vs GUI —
gui=Falseuses service path; defaultwait_untilis more aggressive/minimal;gui_fallbackmay open UI if service handshake fails. - Cross-origin iframes — detectable; DOM access from parent is not possible; use
FrameLocator.open()to navigate top-level tosrc. - Single-tab headless —
window_handlesoften length 1 in service mode. - Base64 protocol — all command values encoded; raw socket debugging will look opaque.
- Stdlib-first — core automation does not require Selenium/Playwright packages.
Versioning
Current package version is defined in __init__.py:
__version__ = "1.1.9"
setup.py reads the same field for distribution builds. See CHANGELOG.md for history (1.1.8 documented resilient helpers, release script, README refresh; this tree is 1.1.9).
python -c "import dbgidchromium as c; print(c.__version__)"
Links
- Package / toolkit: https://github.com/dbgid/dbgidchromium
- Required browser: https://github.com/dbgid/DBG-ID-Browser
- License: MIT (
LICENSE)
API map (classes)
dbgidchromium
├── __version__ = "1.1.9"
├── By, Keys, Command, DictMap, AsnHit
├── Exceptions: WebDriverException, NoSuchElementException, ApplicationClosed,
│ CrossOriginFrameException, InvalidElementStateException,
│ UnexpectedTagNameException
├── RemoteConnection
│ └── WebDriver (= Chrome)
│ ├── WebElement
│ ├── Select
│ ├── WebDriverWait + expected conditions
│ ├── SwitchTo
│ ├── Locator / ElementLocator
│ ├── FrameLocator / NestedFrameLocator / FrameScopedLocator
│ └── PageHandle
└── AsyncWebDriver (= AsyncChrome)
├── AsyncWebElement
├── AsyncLocator
├── AsyncFrameLocator
└── AsyncPageHandle
For behavioral smoke tests mirroring navigation + iframe DOM, see example.py.
Release files for dbgidchromium 1.1.10
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dbgidchromium-1.1.10.tar.gz | 7.5 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dbgidchromium-1.1.10-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.9 MB
Release files / dbgidchromium-1.1.10.tar.gz
| Download URL | dbgidchromium-1.1.10.tar.gz |
|---|---|
| Size | 7.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
210dc5a795191fc000ab74f2548c76807b7aa094b39486db0a428d88cd5baf9e
|
|
BLAKE2b-256 checksum How to use checksums |
d74b1df55569654f6b2bae06f2f8d95d5e9cbe1224590d44ad454138c72f39e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|
Release files / dbgidchromium-1.1.10-py3-none-any.whl
| Download URL | dbgidchromium-1.1.10-py3-none-any.whl |
|---|---|
| Size | 7.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2827461be8629e3e965abe0ed81ce82fe88a2a5f0ee8f6c9d91453f324889241
|
|
BLAKE2b-256 checksum How to use checksums |
2e7c92cbfb952053fd847dec9e70d69b110f6bdb8fcdfecf0672588f60baa786
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|