cmdop 0.1.20__py3-none-any.whl → 0.1.22__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cmdop/__init__.py +1 -1
- cmdop/_generated/rpc_messages/browser_pb2.py +81 -81
- cmdop/_generated/rpc_messages/browser_pb2.pyi +4 -2
- cmdop/client.py +2 -8
- cmdop/services/browser/__init__.py +44 -31
- cmdop/services/browser/capabilities/__init__.py +15 -0
- cmdop/services/browser/capabilities/_base.py +28 -0
- cmdop/services/browser/capabilities/_helpers.py +16 -0
- cmdop/services/browser/capabilities/dom.py +76 -0
- cmdop/services/browser/capabilities/fetch.py +46 -0
- cmdop/services/browser/capabilities/input.py +49 -0
- cmdop/services/browser/capabilities/scroll.py +147 -0
- cmdop/services/browser/capabilities/timing.py +66 -0
- cmdop/services/browser/js/__init__.py +6 -4
- cmdop/services/browser/js/interaction.py +34 -0
- cmdop/services/browser/service/__init__.py +5 -0
- cmdop/services/browser/service/aio.py +30 -0
- cmdop/services/browser/{sync/service.py → service/sync.py} +9 -4
- cmdop/services/browser/session.py +166 -0
- {cmdop-0.1.20.dist-info → cmdop-0.1.22.dist-info}/METADATA +70 -41
- {cmdop-0.1.20.dist-info → cmdop-0.1.22.dist-info}/RECORD +24 -20
- cmdop/services/browser/aio/__init__.py +0 -6
- cmdop/services/browser/aio/service.py +0 -415
- cmdop/services/browser/aio/session.py +0 -358
- cmdop/services/browser/base/__init__.py +0 -6
- cmdop/services/browser/base/session.py +0 -124
- cmdop/services/browser/sync/__init__.py +0 -6
- cmdop/services/browser/sync/session.py +0 -580
- /cmdop/services/browser/{base/service.py → service/_helpers.py} +0 -0
- {cmdop-0.1.20.dist-info → cmdop-0.1.22.dist-info}/WHEEL +0 -0
- {cmdop-0.1.20.dist-info → cmdop-0.1.22.dist-info}/licenses/LICENSE +0 -0
cmdop/__init__.py
CHANGED
|
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1arpc_messages/browser.proto\x12\x08terminal\"\x9b\x01\n\x1b\x42rowserCreateSessionRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x10\n\x08provider\x18\x02 \x01(\t\x12\x12\n\nprofile_id\x18\x03 \x01(\t\x12\x11\n\tstart_url\x18\x04 \x01(\t\x12\x10\n\x08headless\x18\x05 \x01(\x08\x12\r\n\x05width\x18\x06 \x01(\x05\x12\x0e\n\x06height\x18\x07 \x01(\x05\"Z\n\x1c\x42rowserCreateSessionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"L\n\x1a\x42rowserCloseSessionRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\"=\n\x1b\x42rowserCloseSessionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"i\n\x16\x42rowserNavigateRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\"L\n\x17\x42rowserNavigateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x11\n\tfinal_url\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"
|
|
27
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1arpc_messages/browser.proto\x12\x08terminal\"\x9b\x01\n\x1b\x42rowserCreateSessionRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x10\n\x08provider\x18\x02 \x01(\t\x12\x12\n\nprofile_id\x18\x03 \x01(\t\x12\x11\n\tstart_url\x18\x04 \x01(\t\x12\x10\n\x08headless\x18\x05 \x01(\x08\x12\r\n\x05width\x18\x06 \x01(\x05\x12\x0e\n\x06height\x18\x07 \x01(\x05\"Z\n\x1c\x42rowserCreateSessionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"L\n\x1a\x42rowserCloseSessionRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\"=\n\x1b\x42rowserCloseSessionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"i\n\x16\x42rowserNavigateRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\"L\n\x17\x42rowserNavigateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x11\n\tfinal_url\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"\x80\x01\n\x13\x42rowserClickRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\x12\x13\n\x0bmove_cursor\x18\x05 \x01(\x08\"6\n\x14\x42rowserClickResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\x8d\x01\n\x12\x42rowserTypeRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x0c\n\x04text\x18\x04 \x01(\t\x12\x12\n\nhuman_like\x18\x05 \x01(\x08\x12\x13\n\x0b\x63lear_first\x18\x06 \x01(\x08\"5\n\x13\x42rowserTypeResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"j\n\x12\x42rowserWaitRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\"D\n\x13\x42rowserWaitResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x66ound\x18\x02 \x01(\x08\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"{\n\x15\x42rowserExtractRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x11\n\tattribute\x18\x04 \x01(\t\x12\r\n\x05limit\x18\x05 \x01(\x05\"W\n\x16\x42rowserExtractResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06values\x18\x02 \x03(\t\x12\r\n\x05\x63ount\x18\x03 \x01(\x05\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"\x7f\n\x1a\x42rowserExtractRegexRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0f\n\x07pattern\x18\x03 \x01(\t\x12\x11\n\tfrom_html\x18\x04 \x01(\x08\x12\r\n\x05limit\x18\x05 \x01(\x05\"]\n\x1b\x42rowserExtractRegexResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07matches\x18\x02 \x03(\t\x12\r\n\x05\x63ount\x18\x03 \x01(\x05\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"Y\n\x15\x42rowserGetHTMLRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\"F\n\x16\x42rowserGetHTMLResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0c\n\x04html\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"Y\n\x15\x42rowserGetTextRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\"F\n\x16\x42rowserGetTextResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0c\n\x04text\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"]\n\x1b\x42rowserExecuteScriptRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0e\n\x06script\x18\x03 \x01(\t\"N\n\x1c\x42rowserExecuteScriptResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06result\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"~\n\x18\x42rowserScreenshotRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x11\n\tfull_page\x18\x03 \x01(\x08\x12\x0e\n\x06\x66ormat\x18\x04 \x01(\t\x12\x0f\n\x07quality\x18\x05 \x01(\x05\"I\n\x19\x42rowserScreenshotResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"H\n\x16\x42rowserGetStateRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\"U\n\x17\x42rowserGetStateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\r\n\x05title\x18\x03 \x01(\t\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"K\n\x19\x42rowserGetPageInfoRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\"\xbb\x03\n\x1a\x42rowserGetPageInfoResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\r\n\x05title\x18\x04 \x01(\t\x12\x13\n\x0bpage_height\x18\x05 \x01(\x05\x12\x17\n\x0fviewport_height\x18\x06 \x01(\x05\x12\x16\n\x0eviewport_width\x18\x07 \x01(\x05\x12\x10\n\x08scroll_x\x18\x08 \x01(\x05\x12\x10\n\x08scroll_y\x18\t \x01(\x05\x12\x0e\n\x06\x61t_top\x18\n \x01(\x08\x12\x11\n\tat_bottom\x18\x0b \x01(\x08\x12\x14\n\x0cload_time_ms\x18\x0c \x01(\x05\x12\x15\n\rcookies_count\x18\r \x01(\x05\x12\x10\n\x08is_https\x18\x0e \x01(\x08\x12\x13\n\x0bhas_iframes\x18\x0f \x01(\x08\x12\x15\n\rdom_nodes_raw\x18\x10 \x01(\x05\x12\x19\n\x11\x64om_nodes_cleaned\x18\x11 \x01(\x05\x12\x17\n\x0ftokens_estimate\x18\x12 \x01(\x05\x12\x1b\n\x13\x63loudflare_detected\x18\x13 \x01(\x08\x12\x18\n\x10\x63\x61ptcha_detected\x18\x14 \x01(\x08\"\x91\x01\n\rBrowserCookie\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x12\x0e\n\x06\x64omain\x18\x03 \x01(\t\x12\x0c\n\x04path\x18\x04 \x01(\t\x12\x0e\n\x06secure\x18\x05 \x01(\x08\x12\x11\n\thttp_only\x18\x06 \x01(\x08\x12\x11\n\tsame_site\x18\x07 \x01(\t\x12\x0f\n\x07\x65xpires\x18\x08 \x01(\x03\"t\n\x18\x42rowserSetCookiesRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12(\n\x07\x63ookies\x18\x03 \x03(\x0b\x32\x17.terminal.BrowserCookie\";\n\x19\x42rowserSetCookiesResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"Z\n\x18\x42rowserGetCookiesRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0e\n\x06\x64omain\x18\x03 \x01(\t\"e\n\x19\x42rowserGetCookiesResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12(\n\x07\x63ookies\x18\x02 \x03(\x0b\x32\x17.terminal.BrowserCookie\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"n\n\x17\x42rowserMouseMoveRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\t\n\x01x\x18\x03 \x01(\x05\x12\t\n\x01y\x18\x04 \x01(\x05\x12\r\n\x05steps\x18\x05 \x01(\x05\":\n\x18\x42rowserMouseMoveResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"k\n\x13\x42rowserHoverRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\"6\n\x14\x42rowserHoverResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\x9e\x01\n\x14\x42rowserScrollRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x11\n\tdirection\x18\x03 \x01(\t\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x05\x12\x10\n\x08selector\x18\x05 \x01(\t\x12\x11\n\tcontainer\x18\x06 \x01(\t\x12\x0e\n\x06smooth\x18\x07 \x01(\x08\"\xb1\x01\n\x15\x42rowserScrollResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x10\n\x08scroll_x\x18\x02 \x01(\x05\x12\x10\n\x08scroll_y\x18\x03 \x01(\x05\x12\x13\n\x0bscrolled_by\x18\x04 \x01(\x05\x12\x13\n\x0bpage_height\x18\x05 \x01(\x05\x12\x17\n\x0fviewport_height\x18\x06 \x01(\x05\x12\x11\n\tat_bottom\x18\x07 \x01(\x08\x12\r\n\x05\x65rror\x18\x08 \x01(\t\"\xd5\x01\n\x1f\x42rowserValidateSelectorsRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0c\n\x04item\x18\x03 \x01(\t\x12\x45\n\x06\x66ields\x18\x04 \x03(\x0b\x32\x35.terminal.BrowserValidateSelectorsRequest.FieldsEntry\x1a-\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xd2\x02\n BrowserValidateSelectorsResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05valid\x18\x02 \x01(\x08\x12\x46\n\x06\x63ounts\x18\x03 \x03(\x0b\x32\x36.terminal.BrowserValidateSelectorsResponse.CountsEntry\x12H\n\x07samples\x18\x04 \x03(\x0b\x32\x37.terminal.BrowserValidateSelectorsResponse.SamplesEntry\x12\x0e\n\x06\x65rrors\x18\x05 \x03(\t\x12\r\n\x05\x65rror\x18\x06 \x01(\t\x1a-\n\x0b\x43ountsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a.\n\x0cSamplesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"}\n\x19\x42rowserExtractDataRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0c\n\x04item\x18\x03 \x01(\t\x12\x13\n\x0b\x66ields_json\x18\x04 \x01(\t\x12\r\n\x05limit\x18\x05 \x01(\x05\"_\n\x1a\x42rowserExtractDataResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\nitems_json\x18\x02 \x01(\t\x12\r\n\x05\x63ount\x18\x03 \x01(\x05\x12\r\n\x05\x65rror\x18\x04 \x01(\tB\x10Z\x0eterminal/protob\x06proto3')
|
|
28
28
|
|
|
29
29
|
_globals = globals()
|
|
30
30
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -50,84 +50,84 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
50
50
|
_globals['_BROWSERNAVIGATEREQUEST']._serialized_end=536
|
|
51
51
|
_globals['_BROWSERNAVIGATERESPONSE']._serialized_start=538
|
|
52
52
|
_globals['_BROWSERNAVIGATERESPONSE']._serialized_end=614
|
|
53
|
-
_globals['_BROWSERCLICKREQUEST']._serialized_start=
|
|
54
|
-
_globals['_BROWSERCLICKREQUEST']._serialized_end=
|
|
55
|
-
_globals['_BROWSERCLICKRESPONSE']._serialized_start=
|
|
56
|
-
_globals['_BROWSERCLICKRESPONSE']._serialized_end=
|
|
57
|
-
_globals['_BROWSERTYPEREQUEST']._serialized_start=
|
|
58
|
-
_globals['_BROWSERTYPEREQUEST']._serialized_end=
|
|
59
|
-
_globals['_BROWSERTYPERESPONSE']._serialized_start=
|
|
60
|
-
_globals['_BROWSERTYPERESPONSE']._serialized_end=
|
|
61
|
-
_globals['_BROWSERWAITREQUEST']._serialized_start=
|
|
62
|
-
_globals['_BROWSERWAITREQUEST']._serialized_end=
|
|
63
|
-
_globals['_BROWSERWAITRESPONSE']._serialized_start=
|
|
64
|
-
_globals['_BROWSERWAITRESPONSE']._serialized_end=
|
|
65
|
-
_globals['_BROWSEREXTRACTREQUEST']._serialized_start=
|
|
66
|
-
_globals['_BROWSEREXTRACTREQUEST']._serialized_end=
|
|
67
|
-
_globals['_BROWSEREXTRACTRESPONSE']._serialized_start=
|
|
68
|
-
_globals['_BROWSEREXTRACTRESPONSE']._serialized_end=
|
|
69
|
-
_globals['_BROWSEREXTRACTREGEXREQUEST']._serialized_start=
|
|
70
|
-
_globals['_BROWSEREXTRACTREGEXREQUEST']._serialized_end=
|
|
71
|
-
_globals['_BROWSEREXTRACTREGEXRESPONSE']._serialized_start=
|
|
72
|
-
_globals['_BROWSEREXTRACTREGEXRESPONSE']._serialized_end=
|
|
73
|
-
_globals['_BROWSERGETHTMLREQUEST']._serialized_start=
|
|
74
|
-
_globals['_BROWSERGETHTMLREQUEST']._serialized_end=
|
|
75
|
-
_globals['_BROWSERGETHTMLRESPONSE']._serialized_start=
|
|
76
|
-
_globals['_BROWSERGETHTMLRESPONSE']._serialized_end=
|
|
77
|
-
_globals['_BROWSERGETTEXTREQUEST']._serialized_start=
|
|
78
|
-
_globals['_BROWSERGETTEXTREQUEST']._serialized_end=
|
|
79
|
-
_globals['_BROWSERGETTEXTRESPONSE']._serialized_start=
|
|
80
|
-
_globals['_BROWSERGETTEXTRESPONSE']._serialized_end=
|
|
81
|
-
_globals['_BROWSEREXECUTESCRIPTREQUEST']._serialized_start=
|
|
82
|
-
_globals['_BROWSEREXECUTESCRIPTREQUEST']._serialized_end=
|
|
83
|
-
_globals['_BROWSEREXECUTESCRIPTRESPONSE']._serialized_start=
|
|
84
|
-
_globals['_BROWSEREXECUTESCRIPTRESPONSE']._serialized_end=
|
|
85
|
-
_globals['_BROWSERSCREENSHOTREQUEST']._serialized_start=
|
|
86
|
-
_globals['_BROWSERSCREENSHOTREQUEST']._serialized_end=
|
|
87
|
-
_globals['_BROWSERSCREENSHOTRESPONSE']._serialized_start=
|
|
88
|
-
_globals['_BROWSERSCREENSHOTRESPONSE']._serialized_end=
|
|
89
|
-
_globals['_BROWSERGETSTATEREQUEST']._serialized_start=
|
|
90
|
-
_globals['_BROWSERGETSTATEREQUEST']._serialized_end=
|
|
91
|
-
_globals['_BROWSERGETSTATERESPONSE']._serialized_start=
|
|
92
|
-
_globals['_BROWSERGETSTATERESPONSE']._serialized_end=
|
|
93
|
-
_globals['_BROWSERGETPAGEINFOREQUEST']._serialized_start=
|
|
94
|
-
_globals['_BROWSERGETPAGEINFOREQUEST']._serialized_end=
|
|
95
|
-
_globals['_BROWSERGETPAGEINFORESPONSE']._serialized_start=
|
|
96
|
-
_globals['_BROWSERGETPAGEINFORESPONSE']._serialized_end=
|
|
97
|
-
_globals['_BROWSERCOOKIE']._serialized_start=
|
|
98
|
-
_globals['_BROWSERCOOKIE']._serialized_end=
|
|
99
|
-
_globals['_BROWSERSETCOOKIESREQUEST']._serialized_start=
|
|
100
|
-
_globals['_BROWSERSETCOOKIESREQUEST']._serialized_end=
|
|
101
|
-
_globals['_BROWSERSETCOOKIESRESPONSE']._serialized_start=
|
|
102
|
-
_globals['_BROWSERSETCOOKIESRESPONSE']._serialized_end=
|
|
103
|
-
_globals['_BROWSERGETCOOKIESREQUEST']._serialized_start=
|
|
104
|
-
_globals['_BROWSERGETCOOKIESREQUEST']._serialized_end=
|
|
105
|
-
_globals['_BROWSERGETCOOKIESRESPONSE']._serialized_start=
|
|
106
|
-
_globals['_BROWSERGETCOOKIESRESPONSE']._serialized_end=
|
|
107
|
-
_globals['_BROWSERMOUSEMOVEREQUEST']._serialized_start=
|
|
108
|
-
_globals['_BROWSERMOUSEMOVEREQUEST']._serialized_end=
|
|
109
|
-
_globals['_BROWSERMOUSEMOVERESPONSE']._serialized_start=
|
|
110
|
-
_globals['_BROWSERMOUSEMOVERESPONSE']._serialized_end=
|
|
111
|
-
_globals['_BROWSERHOVERREQUEST']._serialized_start=
|
|
112
|
-
_globals['_BROWSERHOVERREQUEST']._serialized_end=
|
|
113
|
-
_globals['_BROWSERHOVERRESPONSE']._serialized_start=
|
|
114
|
-
_globals['_BROWSERHOVERRESPONSE']._serialized_end=
|
|
115
|
-
_globals['_BROWSERSCROLLREQUEST']._serialized_start=
|
|
116
|
-
_globals['_BROWSERSCROLLREQUEST']._serialized_end=
|
|
117
|
-
_globals['_BROWSERSCROLLRESPONSE']._serialized_start=
|
|
118
|
-
_globals['_BROWSERSCROLLRESPONSE']._serialized_end=
|
|
119
|
-
_globals['_BROWSERVALIDATESELECTORSREQUEST']._serialized_start=
|
|
120
|
-
_globals['_BROWSERVALIDATESELECTORSREQUEST']._serialized_end=
|
|
121
|
-
_globals['_BROWSERVALIDATESELECTORSREQUEST_FIELDSENTRY']._serialized_start=
|
|
122
|
-
_globals['_BROWSERVALIDATESELECTORSREQUEST_FIELDSENTRY']._serialized_end=
|
|
123
|
-
_globals['_BROWSERVALIDATESELECTORSRESPONSE']._serialized_start=
|
|
124
|
-
_globals['_BROWSERVALIDATESELECTORSRESPONSE']._serialized_end=
|
|
125
|
-
_globals['_BROWSERVALIDATESELECTORSRESPONSE_COUNTSENTRY']._serialized_start=
|
|
126
|
-
_globals['_BROWSERVALIDATESELECTORSRESPONSE_COUNTSENTRY']._serialized_end=
|
|
127
|
-
_globals['_BROWSERVALIDATESELECTORSRESPONSE_SAMPLESENTRY']._serialized_start=
|
|
128
|
-
_globals['_BROWSERVALIDATESELECTORSRESPONSE_SAMPLESENTRY']._serialized_end=
|
|
129
|
-
_globals['_BROWSEREXTRACTDATAREQUEST']._serialized_start=
|
|
130
|
-
_globals['_BROWSEREXTRACTDATAREQUEST']._serialized_end=
|
|
131
|
-
_globals['_BROWSEREXTRACTDATARESPONSE']._serialized_start=
|
|
132
|
-
_globals['_BROWSEREXTRACTDATARESPONSE']._serialized_end=
|
|
53
|
+
_globals['_BROWSERCLICKREQUEST']._serialized_start=617
|
|
54
|
+
_globals['_BROWSERCLICKREQUEST']._serialized_end=745
|
|
55
|
+
_globals['_BROWSERCLICKRESPONSE']._serialized_start=747
|
|
56
|
+
_globals['_BROWSERCLICKRESPONSE']._serialized_end=801
|
|
57
|
+
_globals['_BROWSERTYPEREQUEST']._serialized_start=804
|
|
58
|
+
_globals['_BROWSERTYPEREQUEST']._serialized_end=945
|
|
59
|
+
_globals['_BROWSERTYPERESPONSE']._serialized_start=947
|
|
60
|
+
_globals['_BROWSERTYPERESPONSE']._serialized_end=1000
|
|
61
|
+
_globals['_BROWSERWAITREQUEST']._serialized_start=1002
|
|
62
|
+
_globals['_BROWSERWAITREQUEST']._serialized_end=1108
|
|
63
|
+
_globals['_BROWSERWAITRESPONSE']._serialized_start=1110
|
|
64
|
+
_globals['_BROWSERWAITRESPONSE']._serialized_end=1178
|
|
65
|
+
_globals['_BROWSEREXTRACTREQUEST']._serialized_start=1180
|
|
66
|
+
_globals['_BROWSEREXTRACTREQUEST']._serialized_end=1303
|
|
67
|
+
_globals['_BROWSEREXTRACTRESPONSE']._serialized_start=1305
|
|
68
|
+
_globals['_BROWSEREXTRACTRESPONSE']._serialized_end=1392
|
|
69
|
+
_globals['_BROWSEREXTRACTREGEXREQUEST']._serialized_start=1394
|
|
70
|
+
_globals['_BROWSEREXTRACTREGEXREQUEST']._serialized_end=1521
|
|
71
|
+
_globals['_BROWSEREXTRACTREGEXRESPONSE']._serialized_start=1523
|
|
72
|
+
_globals['_BROWSEREXTRACTREGEXRESPONSE']._serialized_end=1616
|
|
73
|
+
_globals['_BROWSERGETHTMLREQUEST']._serialized_start=1618
|
|
74
|
+
_globals['_BROWSERGETHTMLREQUEST']._serialized_end=1707
|
|
75
|
+
_globals['_BROWSERGETHTMLRESPONSE']._serialized_start=1709
|
|
76
|
+
_globals['_BROWSERGETHTMLRESPONSE']._serialized_end=1779
|
|
77
|
+
_globals['_BROWSERGETTEXTREQUEST']._serialized_start=1781
|
|
78
|
+
_globals['_BROWSERGETTEXTREQUEST']._serialized_end=1870
|
|
79
|
+
_globals['_BROWSERGETTEXTRESPONSE']._serialized_start=1872
|
|
80
|
+
_globals['_BROWSERGETTEXTRESPONSE']._serialized_end=1942
|
|
81
|
+
_globals['_BROWSEREXECUTESCRIPTREQUEST']._serialized_start=1944
|
|
82
|
+
_globals['_BROWSEREXECUTESCRIPTREQUEST']._serialized_end=2037
|
|
83
|
+
_globals['_BROWSEREXECUTESCRIPTRESPONSE']._serialized_start=2039
|
|
84
|
+
_globals['_BROWSEREXECUTESCRIPTRESPONSE']._serialized_end=2117
|
|
85
|
+
_globals['_BROWSERSCREENSHOTREQUEST']._serialized_start=2119
|
|
86
|
+
_globals['_BROWSERSCREENSHOTREQUEST']._serialized_end=2245
|
|
87
|
+
_globals['_BROWSERSCREENSHOTRESPONSE']._serialized_start=2247
|
|
88
|
+
_globals['_BROWSERSCREENSHOTRESPONSE']._serialized_end=2320
|
|
89
|
+
_globals['_BROWSERGETSTATEREQUEST']._serialized_start=2322
|
|
90
|
+
_globals['_BROWSERGETSTATEREQUEST']._serialized_end=2394
|
|
91
|
+
_globals['_BROWSERGETSTATERESPONSE']._serialized_start=2396
|
|
92
|
+
_globals['_BROWSERGETSTATERESPONSE']._serialized_end=2481
|
|
93
|
+
_globals['_BROWSERGETPAGEINFOREQUEST']._serialized_start=2483
|
|
94
|
+
_globals['_BROWSERGETPAGEINFOREQUEST']._serialized_end=2558
|
|
95
|
+
_globals['_BROWSERGETPAGEINFORESPONSE']._serialized_start=2561
|
|
96
|
+
_globals['_BROWSERGETPAGEINFORESPONSE']._serialized_end=3004
|
|
97
|
+
_globals['_BROWSERCOOKIE']._serialized_start=3007
|
|
98
|
+
_globals['_BROWSERCOOKIE']._serialized_end=3152
|
|
99
|
+
_globals['_BROWSERSETCOOKIESREQUEST']._serialized_start=3154
|
|
100
|
+
_globals['_BROWSERSETCOOKIESREQUEST']._serialized_end=3270
|
|
101
|
+
_globals['_BROWSERSETCOOKIESRESPONSE']._serialized_start=3272
|
|
102
|
+
_globals['_BROWSERSETCOOKIESRESPONSE']._serialized_end=3331
|
|
103
|
+
_globals['_BROWSERGETCOOKIESREQUEST']._serialized_start=3333
|
|
104
|
+
_globals['_BROWSERGETCOOKIESREQUEST']._serialized_end=3423
|
|
105
|
+
_globals['_BROWSERGETCOOKIESRESPONSE']._serialized_start=3425
|
|
106
|
+
_globals['_BROWSERGETCOOKIESRESPONSE']._serialized_end=3526
|
|
107
|
+
_globals['_BROWSERMOUSEMOVEREQUEST']._serialized_start=3528
|
|
108
|
+
_globals['_BROWSERMOUSEMOVEREQUEST']._serialized_end=3638
|
|
109
|
+
_globals['_BROWSERMOUSEMOVERESPONSE']._serialized_start=3640
|
|
110
|
+
_globals['_BROWSERMOUSEMOVERESPONSE']._serialized_end=3698
|
|
111
|
+
_globals['_BROWSERHOVERREQUEST']._serialized_start=3700
|
|
112
|
+
_globals['_BROWSERHOVERREQUEST']._serialized_end=3807
|
|
113
|
+
_globals['_BROWSERHOVERRESPONSE']._serialized_start=3809
|
|
114
|
+
_globals['_BROWSERHOVERRESPONSE']._serialized_end=3863
|
|
115
|
+
_globals['_BROWSERSCROLLREQUEST']._serialized_start=3866
|
|
116
|
+
_globals['_BROWSERSCROLLREQUEST']._serialized_end=4024
|
|
117
|
+
_globals['_BROWSERSCROLLRESPONSE']._serialized_start=4027
|
|
118
|
+
_globals['_BROWSERSCROLLRESPONSE']._serialized_end=4204
|
|
119
|
+
_globals['_BROWSERVALIDATESELECTORSREQUEST']._serialized_start=4207
|
|
120
|
+
_globals['_BROWSERVALIDATESELECTORSREQUEST']._serialized_end=4420
|
|
121
|
+
_globals['_BROWSERVALIDATESELECTORSREQUEST_FIELDSENTRY']._serialized_start=4375
|
|
122
|
+
_globals['_BROWSERVALIDATESELECTORSREQUEST_FIELDSENTRY']._serialized_end=4420
|
|
123
|
+
_globals['_BROWSERVALIDATESELECTORSRESPONSE']._serialized_start=4423
|
|
124
|
+
_globals['_BROWSERVALIDATESELECTORSRESPONSE']._serialized_end=4761
|
|
125
|
+
_globals['_BROWSERVALIDATESELECTORSRESPONSE_COUNTSENTRY']._serialized_start=4668
|
|
126
|
+
_globals['_BROWSERVALIDATESELECTORSRESPONSE_COUNTSENTRY']._serialized_end=4713
|
|
127
|
+
_globals['_BROWSERVALIDATESELECTORSRESPONSE_SAMPLESENTRY']._serialized_start=4715
|
|
128
|
+
_globals['_BROWSERVALIDATESELECTORSRESPONSE_SAMPLESENTRY']._serialized_end=4761
|
|
129
|
+
_globals['_BROWSEREXTRACTDATAREQUEST']._serialized_start=4763
|
|
130
|
+
_globals['_BROWSEREXTRACTDATAREQUEST']._serialized_end=4888
|
|
131
|
+
_globals['_BROWSEREXTRACTDATARESPONSE']._serialized_start=4890
|
|
132
|
+
_globals['_BROWSEREXTRACTDATARESPONSE']._serialized_end=4985
|
|
133
133
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -73,16 +73,18 @@ class BrowserNavigateResponse(_message.Message):
|
|
|
73
73
|
def __init__(self, success: bool = ..., final_url: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ...
|
|
74
74
|
|
|
75
75
|
class BrowserClickRequest(_message.Message):
|
|
76
|
-
__slots__ = ("session_id", "browser_session_id", "selector", "timeout_ms")
|
|
76
|
+
__slots__ = ("session_id", "browser_session_id", "selector", "timeout_ms", "move_cursor")
|
|
77
77
|
SESSION_ID_FIELD_NUMBER: _ClassVar[int]
|
|
78
78
|
BROWSER_SESSION_ID_FIELD_NUMBER: _ClassVar[int]
|
|
79
79
|
SELECTOR_FIELD_NUMBER: _ClassVar[int]
|
|
80
80
|
TIMEOUT_MS_FIELD_NUMBER: _ClassVar[int]
|
|
81
|
+
MOVE_CURSOR_FIELD_NUMBER: _ClassVar[int]
|
|
81
82
|
session_id: str
|
|
82
83
|
browser_session_id: str
|
|
83
84
|
selector: str
|
|
84
85
|
timeout_ms: int
|
|
85
|
-
|
|
86
|
+
move_cursor: bool
|
|
87
|
+
def __init__(self, session_id: _Optional[str] = ..., browser_session_id: _Optional[str] = ..., selector: _Optional[str] = ..., timeout_ms: _Optional[int] = ..., move_cursor: bool = ...) -> None: ...
|
|
86
88
|
|
|
87
89
|
class BrowserClickResponse(_message.Message):
|
|
88
90
|
__slots__ = ("success", "error")
|
cmdop/client.py
CHANGED
|
@@ -439,15 +439,9 @@ class AsyncCMDOPClient:
|
|
|
439
439
|
@property
|
|
440
440
|
def browser(self) -> AsyncBrowserService:
|
|
441
441
|
"""
|
|
442
|
-
Async browser service
|
|
442
|
+
Async browser service (stub - not implemented).
|
|
443
443
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
Example:
|
|
447
|
-
>>> async with client.browser.create_session() as session:
|
|
448
|
-
... await session.navigate("https://google.com")
|
|
449
|
-
... await session.type("input[name='q']", "Python")
|
|
450
|
-
... results = await session.extract(".result-title")
|
|
444
|
+
Use sync CMDOPClient.browser instead.
|
|
451
445
|
"""
|
|
452
446
|
if self._browser is None:
|
|
453
447
|
self._browser = AsyncBrowserService(self._transport)
|
|
@@ -1,46 +1,59 @@
|
|
|
1
|
-
"""Browser
|
|
2
|
-
|
|
3
|
-
Structure:
|
|
4
|
-
browser/
|
|
5
|
-
models.py - Data models (BrowserCookie, BrowserState)
|
|
6
|
-
js.py - JavaScript code builders
|
|
7
|
-
base/ - Base classes (BaseSession, BaseServiceMixin)
|
|
8
|
-
sync/ - Sync implementation (BrowserSession, BrowserService)
|
|
9
|
-
aio/ - Async implementation (AsyncBrowserSession, AsyncBrowserService)
|
|
1
|
+
"""Browser SDK with capability-based API.
|
|
10
2
|
|
|
11
3
|
Usage:
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
from cmdop.services.browser import BrowserSession
|
|
5
|
+
|
|
6
|
+
with service.create_session() as session:
|
|
14
7
|
session.navigate("https://example.com")
|
|
15
|
-
data = session.fetch_all(urls, headers={"Accept": "application/json"})
|
|
16
8
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
data = await session.fetch_all(urls, headers={"Accept": "application/json"})
|
|
21
|
-
"""
|
|
9
|
+
# Capabilities
|
|
10
|
+
session.scroll.js("down", 500)
|
|
11
|
+
session.scroll.to_bottom()
|
|
22
12
|
|
|
23
|
-
|
|
13
|
+
session.input.click_js(".button")
|
|
14
|
+
session.input.key("Escape")
|
|
24
15
|
|
|
25
|
-
|
|
26
|
-
from cmdop.services.browser.sync.session import BrowserSession
|
|
27
|
-
from cmdop.services.browser.sync.service import BrowserService
|
|
16
|
+
session.timing.wait(1000)
|
|
28
17
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
soup = session.dom.soup()
|
|
19
|
+
data = session.fetch.json("/api/data")
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from .session import BrowserSession
|
|
23
|
+
from .service.sync import BrowserService
|
|
24
|
+
from .service.aio import AsyncBrowserService
|
|
25
|
+
from .models import (
|
|
26
|
+
BrowserCookie,
|
|
27
|
+
BrowserState,
|
|
28
|
+
PageInfo,
|
|
29
|
+
ScrollResult,
|
|
30
|
+
ScrollInfo,
|
|
31
|
+
InfiniteScrollResult,
|
|
32
|
+
)
|
|
33
|
+
from .capabilities import (
|
|
34
|
+
ScrollCapability,
|
|
35
|
+
InputCapability,
|
|
36
|
+
TimingCapability,
|
|
37
|
+
DOMCapability,
|
|
38
|
+
FetchCapability,
|
|
39
|
+
)
|
|
32
40
|
|
|
33
41
|
__all__ = [
|
|
42
|
+
# Session & Service
|
|
43
|
+
"BrowserSession",
|
|
44
|
+
"BrowserService",
|
|
45
|
+
"AsyncBrowserService",
|
|
34
46
|
# Models
|
|
35
47
|
"BrowserCookie",
|
|
36
48
|
"BrowserState",
|
|
37
49
|
"PageInfo",
|
|
38
50
|
"ScrollResult",
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
51
|
+
"ScrollInfo",
|
|
52
|
+
"InfiniteScrollResult",
|
|
53
|
+
# Capabilities
|
|
54
|
+
"ScrollCapability",
|
|
55
|
+
"InputCapability",
|
|
56
|
+
"TimingCapability",
|
|
57
|
+
"DOMCapability",
|
|
58
|
+
"FetchCapability",
|
|
46
59
|
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Browser capabilities."""
|
|
2
|
+
|
|
3
|
+
from .scroll import ScrollCapability
|
|
4
|
+
from .input import InputCapability
|
|
5
|
+
from .timing import TimingCapability
|
|
6
|
+
from .dom import DOMCapability
|
|
7
|
+
from .fetch import FetchCapability
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"ScrollCapability",
|
|
11
|
+
"InputCapability",
|
|
12
|
+
"TimingCapability",
|
|
13
|
+
"DOMCapability",
|
|
14
|
+
"FetchCapability",
|
|
15
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Base capability class."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from ..session import BrowserSession
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BaseCapability:
|
|
11
|
+
"""Base class for all capabilities.
|
|
12
|
+
|
|
13
|
+
Capabilities group related browser operations and delegate
|
|
14
|
+
actual execution to the session.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__slots__ = ("_s",)
|
|
18
|
+
|
|
19
|
+
def __init__(self, session: "BrowserSession") -> None:
|
|
20
|
+
self._s = session
|
|
21
|
+
|
|
22
|
+
def _js(self, script: str) -> str:
|
|
23
|
+
"""Execute JS via session."""
|
|
24
|
+
return self._s.execute_script(script)
|
|
25
|
+
|
|
26
|
+
def _call(self, method: str, *args: Any, **kwargs: Any) -> Any:
|
|
27
|
+
"""Call service method via session."""
|
|
28
|
+
return self._s._call_service(method, *args, **kwargs)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Shared parsing helpers for capabilities."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
from cmdop.services.browser.js import parse_json_result
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def to_dict(raw: str) -> dict[str, Any]:
|
|
8
|
+
"""Parse JS result to dict, default empty."""
|
|
9
|
+
result = parse_json_result(raw)
|
|
10
|
+
return result if isinstance(result, dict) else {}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def to_list(raw: str) -> list[Any]:
|
|
14
|
+
"""Parse JS result to list, default empty."""
|
|
15
|
+
result = parse_json_result(raw)
|
|
16
|
+
return result if isinstance(result, list) else []
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""DOM capability."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from cmdop.services.browser.js import build_select_js, build_close_modal_js
|
|
7
|
+
from cmdop.services.browser.parsing import parse_html, SoupWrapper
|
|
8
|
+
|
|
9
|
+
from ._base import BaseCapability
|
|
10
|
+
from ._helpers import to_dict
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from bs4 import BeautifulSoup
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DOMCapability(BaseCapability):
|
|
17
|
+
"""DOM operations: extraction, forms, modals.
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
html = session.dom.html()
|
|
21
|
+
soup = session.dom.soup()
|
|
22
|
+
session.dom.select("#country", value="US")
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def html(self, selector: str | None = None) -> str:
|
|
26
|
+
"""Get page HTML."""
|
|
27
|
+
return self._call("get_html", selector)
|
|
28
|
+
|
|
29
|
+
def text(self, selector: str | None = None) -> str:
|
|
30
|
+
"""Get page text content."""
|
|
31
|
+
return self._call("get_text", selector)
|
|
32
|
+
|
|
33
|
+
def soup(self, selector: str | None = None) -> SoupWrapper:
|
|
34
|
+
"""Get HTML as SoupWrapper with chainable API."""
|
|
35
|
+
return SoupWrapper(html=self.html(selector))
|
|
36
|
+
|
|
37
|
+
def parse(self, html: str | None = None, selector: str | None = None) -> "BeautifulSoup":
|
|
38
|
+
"""Parse HTML with BeautifulSoup."""
|
|
39
|
+
if html is None:
|
|
40
|
+
html = self.html(selector)
|
|
41
|
+
return parse_html(html)
|
|
42
|
+
|
|
43
|
+
def select(
|
|
44
|
+
self,
|
|
45
|
+
selector: str,
|
|
46
|
+
value: str | None = None,
|
|
47
|
+
text: str | None = None,
|
|
48
|
+
) -> dict:
|
|
49
|
+
"""Select dropdown option by value or text."""
|
|
50
|
+
js = build_select_js(selector, value, text)
|
|
51
|
+
return to_dict(self._js(js))
|
|
52
|
+
|
|
53
|
+
def close_modal(self, selectors: list[str] | None = None) -> bool:
|
|
54
|
+
"""Try to close modal/dialog."""
|
|
55
|
+
js = build_close_modal_js(selectors)
|
|
56
|
+
return to_dict(self._js(js)).get("success", False)
|
|
57
|
+
|
|
58
|
+
def extract(
|
|
59
|
+
self, selector: str, attr: str | None = None, limit: int = 100
|
|
60
|
+
) -> list[str]:
|
|
61
|
+
"""Extract text or attribute from elements."""
|
|
62
|
+
return self._call("extract", selector, attr, limit)
|
|
63
|
+
|
|
64
|
+
def extract_regex(
|
|
65
|
+
self, pattern: str, from_html: bool = False, limit: int = 100
|
|
66
|
+
) -> list[str]:
|
|
67
|
+
"""Extract matches using regex pattern."""
|
|
68
|
+
return self._call("extract_regex", pattern, from_html, limit)
|
|
69
|
+
|
|
70
|
+
def validate_selectors(self, item: str, fields: dict[str, str]) -> dict:
|
|
71
|
+
"""Validate CSS selectors on page."""
|
|
72
|
+
return self._call("validate_selectors", item, fields)
|
|
73
|
+
|
|
74
|
+
def extract_data(self, item: str, fields_json: str, limit: int = 100) -> dict:
|
|
75
|
+
"""Extract structured data from page."""
|
|
76
|
+
return self._call("extract_data", item, fields_json, limit)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Fetch capability."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from cmdop.services.browser.js import (
|
|
6
|
+
build_fetch_js,
|
|
7
|
+
build_fetch_all_js,
|
|
8
|
+
build_async_js,
|
|
9
|
+
parse_json_result,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from ._base import BaseCapability
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FetchCapability(BaseCapability):
|
|
16
|
+
"""HTTP fetch operations from browser context.
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
data = session.fetch.json("/api/data")
|
|
20
|
+
results = session.fetch.all({"a": "/api/a", "b": "/api/b"})
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def json(self, url: str) -> dict | list | None:
|
|
24
|
+
"""Fetch JSON from URL."""
|
|
25
|
+
js = build_fetch_js(url)
|
|
26
|
+
return parse_json_result(self._js(js))
|
|
27
|
+
|
|
28
|
+
def all(
|
|
29
|
+
self,
|
|
30
|
+
urls: dict[str, str],
|
|
31
|
+
headers: dict[str, str] | None = None,
|
|
32
|
+
credentials: bool = False,
|
|
33
|
+
) -> dict[str, Any]:
|
|
34
|
+
"""Fetch multiple URLs in parallel. Returns {id: {data, error}}."""
|
|
35
|
+
if not urls:
|
|
36
|
+
return {}
|
|
37
|
+
js = build_fetch_all_js(urls, headers, credentials)
|
|
38
|
+
# fetch_all returns via execute_js (async wrapper)
|
|
39
|
+
wrapped = build_async_js(js.replace("return ", ""))
|
|
40
|
+
result = parse_json_result(self._js(wrapped))
|
|
41
|
+
return result if isinstance(result, dict) else {}
|
|
42
|
+
|
|
43
|
+
def execute(self, code: str) -> dict | list | str | None:
|
|
44
|
+
"""Execute async JS code (can use await, fetch, etc)."""
|
|
45
|
+
js = build_async_js(code)
|
|
46
|
+
return parse_json_result(self._js(js))
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Input capability."""
|
|
2
|
+
|
|
3
|
+
from cmdop.services.browser.js import (
|
|
4
|
+
build_click_js,
|
|
5
|
+
build_press_key_js,
|
|
6
|
+
build_click_all_by_text_js,
|
|
7
|
+
build_hover_js,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from ._base import BaseCapability
|
|
11
|
+
from ._helpers import to_dict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class InputCapability(BaseCapability):
|
|
15
|
+
"""Input operations: clicks, keyboard, hover.
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
session.input.click_js(".button")
|
|
19
|
+
session.input.key("Escape")
|
|
20
|
+
session.input.click_all("See more")
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def click_js(self, selector: str, scroll_into_view: bool = True) -> bool:
|
|
24
|
+
"""Click using JavaScript. More reliable than native click."""
|
|
25
|
+
js = build_click_js(selector, scroll_into_view)
|
|
26
|
+
return to_dict(self._js(js)).get("success", False)
|
|
27
|
+
|
|
28
|
+
def key(self, key: str, selector: str | None = None) -> bool:
|
|
29
|
+
"""Press keyboard key. Keys: Escape, Enter, Tab, ArrowDown, etc."""
|
|
30
|
+
js = build_press_key_js(key, selector)
|
|
31
|
+
return to_dict(self._js(js)).get("success", False)
|
|
32
|
+
|
|
33
|
+
def click_all(self, text: str, role: str = "button") -> int:
|
|
34
|
+
"""Click all elements containing text. Returns count clicked."""
|
|
35
|
+
js = build_click_all_by_text_js(text, role)
|
|
36
|
+
return to_dict(self._js(js)).get("clicked", 0)
|
|
37
|
+
|
|
38
|
+
def hover_js(self, selector: str) -> bool:
|
|
39
|
+
"""Hover using JavaScript."""
|
|
40
|
+
js = build_hover_js(selector)
|
|
41
|
+
return to_dict(self._js(js)).get("success", False)
|
|
42
|
+
|
|
43
|
+
def hover(self, selector: str, timeout_ms: int = 5000) -> None:
|
|
44
|
+
"""Hover using native browser API."""
|
|
45
|
+
self._call("hover", selector, timeout_ms)
|
|
46
|
+
|
|
47
|
+
def mouse_move(self, x: int, y: int, steps: int = 10) -> None:
|
|
48
|
+
"""Move mouse to coordinates with human-like movement."""
|
|
49
|
+
self._call("mouse_move", x, y, steps)
|