cmdop 0.1.21__py3-none-any.whl → 0.1.23__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 +135 -85
- cmdop/_generated/rpc_messages/browser_pb2.pyi +270 -2
- cmdop/_generated/rpc_messages_pb2.pyi +25 -0
- cmdop/_generated/service_pb2.py +2 -2
- cmdop/_generated/service_pb2_grpc.py +345 -0
- cmdop/client.py +2 -8
- cmdop/services/browser/__init__.py +44 -31
- cmdop/services/browser/capabilities/__init__.py +17 -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 +45 -0
- cmdop/services/browser/capabilities/input.py +49 -0
- cmdop/services/browser/capabilities/network.py +245 -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/models.py +103 -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} +206 -6
- cmdop/services/browser/session.py +194 -0
- {cmdop-0.1.21.dist-info → cmdop-0.1.23.dist-info}/METADATA +107 -59
- {cmdop-0.1.21.dist-info → cmdop-0.1.23.dist-info}/RECORD +29 -24
- cmdop/services/browser/aio/__init__.py +0 -6
- cmdop/services/browser/aio/service.py +0 -420
- cmdop/services/browser/aio/session.py +0 -407
- 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 -644
- /cmdop/services/browser/{base/service.py → service/_helpers.py} +0 -0
- {cmdop-0.1.21.dist-info → cmdop-0.1.23.dist-info}/WHEEL +0 -0
- {cmdop-0.1.21.dist-info → cmdop-0.1.23.dist-info}/licenses/LICENSE +0 -0
cmdop/_generated/service_pb2.py
CHANGED
|
@@ -125,7 +125,7 @@ except AttributeError:
|
|
|
125
125
|
file__operations_dot_requests__pb2 = file__operations__pb2.file_operations.requests_pb2
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rservice.proto\x12\x08terminal\x1a\x14\x61gent_messages.proto\x1a\x16\x63ontrol_messages.proto\x1a\x12rpc_messages.proto\x1a\x0e\x66ile_rpc.proto\x1a\x15\x66ile_operations.proto2\
|
|
128
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rservice.proto\x12\x08terminal\x1a\x14\x61gent_messages.proto\x1a\x16\x63ontrol_messages.proto\x1a\x12rpc_messages.proto\x1a\x0e\x66ile_rpc.proto\x1a\x15\x66ile_operations.proto2\xe6,\n\x18TerminalStreamingService\x12G\n\x0f\x43onnectTerminal\x12\x16.terminal.AgentMessage\x1a\x18.terminal.ControlMessage(\x01\x30\x01\x12P\n\rCreateSession\x12\x1e.terminal.CreateSessionRequest\x1a\x1f.terminal.CreateSessionResponse\x12M\n\x0c\x43loseSession\x12\x1d.terminal.CloseSessionRequest\x1a\x1e.terminal.CloseSessionResponse\x12Y\n\x10GetSessionStatus\x12!.terminal.GetSessionStatusRequest\x1a\".terminal.GetSessionStatusResponse\x12M\n\x0cListSessions\x12\x1d.terminal.ListSessionsRequest\x1a\x1e.terminal.ListSessionsResponse\x12\x44\n\tSendInput\x12\x1a.terminal.SendInputRequest\x1a\x1b.terminal.SendInputResponse\x12G\n\nSendResize\x12\x1b.terminal.SendResizeRequest\x1a\x1c.terminal.SendResizeResponse\x12G\n\nSendSignal\x12\x1b.terminal.SendSignalRequest\x1a\x1c.terminal.SendSignalResponse\x12G\n\nGetHistory\x12\x1b.terminal.GetHistoryRequest\x1a\x1c.terminal.GetHistoryResponse\x12J\n\x0bHealthCheck\x12\x1c.terminal.HealthCheckRequest\x1a\x1d.terminal.HealthCheckResponse\x12\x62\n\x13RegisterDeviceToken\x12$.terminal.RegisterDeviceTokenRequest\x1a%.terminal.RegisterDeviceTokenResponse\x12h\n\x15UnregisterDeviceToken\x12&.terminal.UnregisterDeviceTokenRequest\x1a\'.terminal.UnregisterDeviceTokenResponse\x12V\n\x0f\x45nterBackground\x12 .terminal.EnterBackgroundRequest\x1a!.terminal.EnterBackgroundResponse\x12_\n\x12WakeFromBackground\x12#.terminal.WakeFromBackgroundRequest\x1a$.terminal.WakeFromBackgroundResponse\x12M\n\x0cQueueCommand\x12\x1d.terminal.QueueCommandRequest\x1a\x1e.terminal.QueueCommandResponse\x12\x62\n\x11\x46ileListDirectory\x12%.terminal.FileListDirectoryRpcRequest\x1a&.terminal.FileListDirectoryRpcResponse\x12G\n\x08\x46ileRead\x12\x1c.terminal.FileReadRpcRequest\x1a\x1d.terminal.FileReadRpcResponse\x12J\n\tFileWrite\x12\x1d.terminal.FileWriteRpcRequest\x1a\x1e.terminal.FileWriteRpcResponse\x12h\n\x13\x46ileCreateDirectory\x12\'.terminal.FileCreateDirectoryRpcRequest\x1a(.terminal.FileCreateDirectoryRpcResponse\x12M\n\nFileDelete\x12\x1e.terminal.FileDeleteRpcRequest\x1a\x1f.terminal.FileDeleteRpcResponse\x12G\n\x08\x46ileMove\x12\x1c.terminal.FileMoveRpcRequest\x1a\x1d.terminal.FileMoveRpcResponse\x12G\n\x08\x46ileCopy\x12\x1c.terminal.FileCopyRpcRequest\x1a\x1d.terminal.FileCopyRpcResponse\x12P\n\x0b\x46ileGetInfo\x12\x1f.terminal.FileGetInfoRpcRequest\x1a .terminal.FileGetInfoRpcResponse\x12\x62\n\x11\x46ileCreateArchive\x12%.terminal.FileCreateArchiveRpcRequest\x1a&.terminal.FileCreateArchiveRpcResponse\x12M\n\nFileSearch\x12\x1e.terminal.FileSearchRpcRequest\x1a\x1f.terminal.FileSearchRpcResponse\x12Y\n\x0eHlsGetPlaylist\x12\".terminal.HlsGetPlaylistRpcRequest\x1a#.terminal.HlsGetPlaylistRpcResponse\x12V\n\rHlsGetSegment\x12!.terminal.HlsGetSegmentRpcRequest\x1a\".terminal.HlsGetSegmentRpcResponse\x12Y\n\x0eHlsStopSession\x12\".terminal.HlsStopSessionRpcRequest\x1a#.terminal.HlsStopSessionRpcResponse\x12[\n\x16InitiateStreamingRelay\x12\x1f.terminal.StreamingRelayRequest\x1a .terminal.StreamingRelayResponse\x12H\n\nRelayChunk\x12\x1d.terminal.StreamingRelayChunk\x1a\x1b.terminal.StreamingRelayAck\x12`\n\x17GetStreamingRelayStatus\x12%.terminal.StreamingRelayStatusRequest\x1a\x1e.terminal.StreamingRelayStatus\x12\x65\n\x14\x43\x61ncelStreamingRelay\x12%.terminal.StreamingRelayCancelRequest\x1a&.terminal.StreamingRelayCancelResponse\x12\x65\n\x14SendPushNotification\x12%.terminal.SendPushNotificationRequest\x1a&.terminal.SendPushNotificationResponse\x12>\n\x07\x45xtract\x12\x18.terminal.ExtractRequest\x1a\x19.terminal.ExtractResponse\x12\x41\n\x08RunAgent\x12\x19.terminal.RunAgentRequest\x1a\x1a.terminal.RunAgentResponse\x12J\n\x0b\x43\x61ncelAgent\x12\x1c.terminal.CancelAgentRequest\x1a\x1d.terminal.CancelAgentResponse\x12\x65\n\x14\x42rowserCreateSession\x12%.terminal.BrowserCreateSessionRequest\x1a&.terminal.BrowserCreateSessionResponse\x12\x62\n\x13\x42rowserCloseSession\x12$.terminal.BrowserCloseSessionRequest\x1a%.terminal.BrowserCloseSessionResponse\x12V\n\x0f\x42rowserNavigate\x12 .terminal.BrowserNavigateRequest\x1a!.terminal.BrowserNavigateResponse\x12M\n\x0c\x42rowserClick\x12\x1d.terminal.BrowserClickRequest\x1a\x1e.terminal.BrowserClickResponse\x12J\n\x0b\x42rowserType\x12\x1c.terminal.BrowserTypeRequest\x1a\x1d.terminal.BrowserTypeResponse\x12J\n\x0b\x42rowserWait\x12\x1c.terminal.BrowserWaitRequest\x1a\x1d.terminal.BrowserWaitResponse\x12S\n\x0e\x42rowserExtract\x12\x1f.terminal.BrowserExtractRequest\x1a .terminal.BrowserExtractResponse\x12\x62\n\x13\x42rowserExtractRegex\x12$.terminal.BrowserExtractRegexRequest\x1a%.terminal.BrowserExtractRegexResponse\x12S\n\x0e\x42rowserGetHTML\x12\x1f.terminal.BrowserGetHTMLRequest\x1a .terminal.BrowserGetHTMLResponse\x12S\n\x0e\x42rowserGetText\x12\x1f.terminal.BrowserGetTextRequest\x1a .terminal.BrowserGetTextResponse\x12\x65\n\x14\x42rowserExecuteScript\x12%.terminal.BrowserExecuteScriptRequest\x1a&.terminal.BrowserExecuteScriptResponse\x12\\\n\x11\x42rowserScreenshot\x12\".terminal.BrowserScreenshotRequest\x1a#.terminal.BrowserScreenshotResponse\x12V\n\x0f\x42rowserGetState\x12 .terminal.BrowserGetStateRequest\x1a!.terminal.BrowserGetStateResponse\x12\\\n\x11\x42rowserSetCookies\x12\".terminal.BrowserSetCookiesRequest\x1a#.terminal.BrowserSetCookiesResponse\x12\\\n\x11\x42rowserGetCookies\x12\".terminal.BrowserGetCookiesRequest\x1a#.terminal.BrowserGetCookiesResponse\x12q\n\x18\x42rowserValidateSelectors\x12).terminal.BrowserValidateSelectorsRequest\x1a*.terminal.BrowserValidateSelectorsResponse\x12_\n\x12\x42rowserExtractData\x12#.terminal.BrowserExtractDataRequest\x1a$.terminal.BrowserExtractDataResponse\x12Y\n\x10\x42rowserMouseMove\x12!.terminal.BrowserMouseMoveRequest\x1a\".terminal.BrowserMouseMoveResponse\x12M\n\x0c\x42rowserHover\x12\x1d.terminal.BrowserHoverRequest\x1a\x1e.terminal.BrowserHoverResponse\x12P\n\rBrowserScroll\x12\x1e.terminal.BrowserScrollRequest\x1a\x1f.terminal.BrowserScrollResponse\x12\x65\n\x14\x42rowserNetworkEnable\x12%.terminal.BrowserNetworkEnableRequest\x1a&.terminal.BrowserNetworkEnableResponse\x12h\n\x15\x42rowserNetworkDisable\x12&.terminal.BrowserNetworkDisableRequest\x1a\'.terminal.BrowserNetworkDisableResponse\x12w\n\x1a\x42rowserNetworkGetExchanges\x12+.terminal.BrowserNetworkGetExchangesRequest\x1a,.terminal.BrowserNetworkGetExchangesResponse\x12t\n\x19\x42rowserNetworkGetExchange\x12*.terminal.BrowserNetworkGetExchangeRequest\x1a+.terminal.BrowserNetworkGetExchangeResponse\x12h\n\x15\x42rowserNetworkGetLast\x12&.terminal.BrowserNetworkGetLastRequest\x1a\'.terminal.BrowserNetworkGetLastResponse\x12\x62\n\x13\x42rowserNetworkClear\x12$.terminal.BrowserNetworkClearRequest\x1a%.terminal.BrowserNetworkClearResponse\x12\x62\n\x13\x42rowserNetworkStats\x12$.terminal.BrowserNetworkStatsRequest\x1a%.terminal.BrowserNetworkStatsResponse\x12n\n\x17\x42rowserNetworkExportHAR\x12(.terminal.BrowserNetworkExportHARRequest\x1a).terminal.BrowserNetworkExportHARResponseB\x10Z\x0eterminal/protob\x06proto3')
|
|
129
129
|
|
|
130
130
|
_globals = globals()
|
|
131
131
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -134,5 +134,5 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
134
134
|
_globals['DESCRIPTOR']._loaded_options = None
|
|
135
135
|
_globals['DESCRIPTOR']._serialized_options = b'Z\016terminal/proto'
|
|
136
136
|
_globals['_TERMINALSTREAMINGSERVICE']._serialized_start=133
|
|
137
|
-
_globals['_TERMINALSTREAMINGSERVICE']._serialized_end=
|
|
137
|
+
_globals['_TERMINALSTREAMINGSERVICE']._serialized_end=5867
|
|
138
138
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -335,6 +335,46 @@ class TerminalStreamingServiceStub(object):
|
|
|
335
335
|
request_serializer=rpc__messages_dot_browser__pb2.BrowserScrollRequest.SerializeToString,
|
|
336
336
|
response_deserializer=rpc__messages_dot_browser__pb2.BrowserScrollResponse.FromString,
|
|
337
337
|
_registered_method=True)
|
|
338
|
+
self.BrowserNetworkEnable = channel.unary_unary(
|
|
339
|
+
'/terminal.TerminalStreamingService/BrowserNetworkEnable',
|
|
340
|
+
request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkEnableRequest.SerializeToString,
|
|
341
|
+
response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkEnableResponse.FromString,
|
|
342
|
+
_registered_method=True)
|
|
343
|
+
self.BrowserNetworkDisable = channel.unary_unary(
|
|
344
|
+
'/terminal.TerminalStreamingService/BrowserNetworkDisable',
|
|
345
|
+
request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkDisableRequest.SerializeToString,
|
|
346
|
+
response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkDisableResponse.FromString,
|
|
347
|
+
_registered_method=True)
|
|
348
|
+
self.BrowserNetworkGetExchanges = channel.unary_unary(
|
|
349
|
+
'/terminal.TerminalStreamingService/BrowserNetworkGetExchanges',
|
|
350
|
+
request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesRequest.SerializeToString,
|
|
351
|
+
response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesResponse.FromString,
|
|
352
|
+
_registered_method=True)
|
|
353
|
+
self.BrowserNetworkGetExchange = channel.unary_unary(
|
|
354
|
+
'/terminal.TerminalStreamingService/BrowserNetworkGetExchange',
|
|
355
|
+
request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeRequest.SerializeToString,
|
|
356
|
+
response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeResponse.FromString,
|
|
357
|
+
_registered_method=True)
|
|
358
|
+
self.BrowserNetworkGetLast = channel.unary_unary(
|
|
359
|
+
'/terminal.TerminalStreamingService/BrowserNetworkGetLast',
|
|
360
|
+
request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetLastRequest.SerializeToString,
|
|
361
|
+
response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetLastResponse.FromString,
|
|
362
|
+
_registered_method=True)
|
|
363
|
+
self.BrowserNetworkClear = channel.unary_unary(
|
|
364
|
+
'/terminal.TerminalStreamingService/BrowserNetworkClear',
|
|
365
|
+
request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkClearRequest.SerializeToString,
|
|
366
|
+
response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkClearResponse.FromString,
|
|
367
|
+
_registered_method=True)
|
|
368
|
+
self.BrowserNetworkStats = channel.unary_unary(
|
|
369
|
+
'/terminal.TerminalStreamingService/BrowserNetworkStats',
|
|
370
|
+
request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkStatsRequest.SerializeToString,
|
|
371
|
+
response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkStatsResponse.FromString,
|
|
372
|
+
_registered_method=True)
|
|
373
|
+
self.BrowserNetworkExportHAR = channel.unary_unary(
|
|
374
|
+
'/terminal.TerminalStreamingService/BrowserNetworkExportHAR',
|
|
375
|
+
request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkExportHARRequest.SerializeToString,
|
|
376
|
+
response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkExportHARResponse.FromString,
|
|
377
|
+
_registered_method=True)
|
|
338
378
|
|
|
339
379
|
|
|
340
380
|
class TerminalStreamingServiceServicer(object):
|
|
@@ -713,6 +753,55 @@ class TerminalStreamingServiceServicer(object):
|
|
|
713
753
|
context.set_details('Method not implemented!')
|
|
714
754
|
raise NotImplementedError('Method not implemented!')
|
|
715
755
|
|
|
756
|
+
def BrowserNetworkEnable(self, request, context):
|
|
757
|
+
"""Network Capture (v2.19.0)
|
|
758
|
+
"""
|
|
759
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
760
|
+
context.set_details('Method not implemented!')
|
|
761
|
+
raise NotImplementedError('Method not implemented!')
|
|
762
|
+
|
|
763
|
+
def BrowserNetworkDisable(self, request, context):
|
|
764
|
+
"""Missing associated documentation comment in .proto file."""
|
|
765
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
766
|
+
context.set_details('Method not implemented!')
|
|
767
|
+
raise NotImplementedError('Method not implemented!')
|
|
768
|
+
|
|
769
|
+
def BrowserNetworkGetExchanges(self, request, context):
|
|
770
|
+
"""Missing associated documentation comment in .proto file."""
|
|
771
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
772
|
+
context.set_details('Method not implemented!')
|
|
773
|
+
raise NotImplementedError('Method not implemented!')
|
|
774
|
+
|
|
775
|
+
def BrowserNetworkGetExchange(self, request, context):
|
|
776
|
+
"""Missing associated documentation comment in .proto file."""
|
|
777
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
778
|
+
context.set_details('Method not implemented!')
|
|
779
|
+
raise NotImplementedError('Method not implemented!')
|
|
780
|
+
|
|
781
|
+
def BrowserNetworkGetLast(self, request, context):
|
|
782
|
+
"""Missing associated documentation comment in .proto file."""
|
|
783
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
784
|
+
context.set_details('Method not implemented!')
|
|
785
|
+
raise NotImplementedError('Method not implemented!')
|
|
786
|
+
|
|
787
|
+
def BrowserNetworkClear(self, request, context):
|
|
788
|
+
"""Missing associated documentation comment in .proto file."""
|
|
789
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
790
|
+
context.set_details('Method not implemented!')
|
|
791
|
+
raise NotImplementedError('Method not implemented!')
|
|
792
|
+
|
|
793
|
+
def BrowserNetworkStats(self, request, context):
|
|
794
|
+
"""Missing associated documentation comment in .proto file."""
|
|
795
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
796
|
+
context.set_details('Method not implemented!')
|
|
797
|
+
raise NotImplementedError('Method not implemented!')
|
|
798
|
+
|
|
799
|
+
def BrowserNetworkExportHAR(self, request, context):
|
|
800
|
+
"""Missing associated documentation comment in .proto file."""
|
|
801
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
802
|
+
context.set_details('Method not implemented!')
|
|
803
|
+
raise NotImplementedError('Method not implemented!')
|
|
804
|
+
|
|
716
805
|
|
|
717
806
|
def add_TerminalStreamingServiceServicer_to_server(servicer, server):
|
|
718
807
|
rpc_method_handlers = {
|
|
@@ -996,6 +1085,46 @@ def add_TerminalStreamingServiceServicer_to_server(servicer, server):
|
|
|
996
1085
|
request_deserializer=rpc__messages_dot_browser__pb2.BrowserScrollRequest.FromString,
|
|
997
1086
|
response_serializer=rpc__messages_dot_browser__pb2.BrowserScrollResponse.SerializeToString,
|
|
998
1087
|
),
|
|
1088
|
+
'BrowserNetworkEnable': grpc.unary_unary_rpc_method_handler(
|
|
1089
|
+
servicer.BrowserNetworkEnable,
|
|
1090
|
+
request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkEnableRequest.FromString,
|
|
1091
|
+
response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkEnableResponse.SerializeToString,
|
|
1092
|
+
),
|
|
1093
|
+
'BrowserNetworkDisable': grpc.unary_unary_rpc_method_handler(
|
|
1094
|
+
servicer.BrowserNetworkDisable,
|
|
1095
|
+
request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkDisableRequest.FromString,
|
|
1096
|
+
response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkDisableResponse.SerializeToString,
|
|
1097
|
+
),
|
|
1098
|
+
'BrowserNetworkGetExchanges': grpc.unary_unary_rpc_method_handler(
|
|
1099
|
+
servicer.BrowserNetworkGetExchanges,
|
|
1100
|
+
request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesRequest.FromString,
|
|
1101
|
+
response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesResponse.SerializeToString,
|
|
1102
|
+
),
|
|
1103
|
+
'BrowserNetworkGetExchange': grpc.unary_unary_rpc_method_handler(
|
|
1104
|
+
servicer.BrowserNetworkGetExchange,
|
|
1105
|
+
request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeRequest.FromString,
|
|
1106
|
+
response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeResponse.SerializeToString,
|
|
1107
|
+
),
|
|
1108
|
+
'BrowserNetworkGetLast': grpc.unary_unary_rpc_method_handler(
|
|
1109
|
+
servicer.BrowserNetworkGetLast,
|
|
1110
|
+
request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetLastRequest.FromString,
|
|
1111
|
+
response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetLastResponse.SerializeToString,
|
|
1112
|
+
),
|
|
1113
|
+
'BrowserNetworkClear': grpc.unary_unary_rpc_method_handler(
|
|
1114
|
+
servicer.BrowserNetworkClear,
|
|
1115
|
+
request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkClearRequest.FromString,
|
|
1116
|
+
response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkClearResponse.SerializeToString,
|
|
1117
|
+
),
|
|
1118
|
+
'BrowserNetworkStats': grpc.unary_unary_rpc_method_handler(
|
|
1119
|
+
servicer.BrowserNetworkStats,
|
|
1120
|
+
request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkStatsRequest.FromString,
|
|
1121
|
+
response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkStatsResponse.SerializeToString,
|
|
1122
|
+
),
|
|
1123
|
+
'BrowserNetworkExportHAR': grpc.unary_unary_rpc_method_handler(
|
|
1124
|
+
servicer.BrowserNetworkExportHAR,
|
|
1125
|
+
request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkExportHARRequest.FromString,
|
|
1126
|
+
response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkExportHARResponse.SerializeToString,
|
|
1127
|
+
),
|
|
999
1128
|
}
|
|
1000
1129
|
generic_handler = grpc.method_handlers_generic_handler(
|
|
1001
1130
|
'terminal.TerminalStreamingService', rpc_method_handlers)
|
|
@@ -2522,3 +2651,219 @@ class TerminalStreamingService(object):
|
|
|
2522
2651
|
timeout,
|
|
2523
2652
|
metadata,
|
|
2524
2653
|
_registered_method=True)
|
|
2654
|
+
|
|
2655
|
+
@staticmethod
|
|
2656
|
+
def BrowserNetworkEnable(request,
|
|
2657
|
+
target,
|
|
2658
|
+
options=(),
|
|
2659
|
+
channel_credentials=None,
|
|
2660
|
+
call_credentials=None,
|
|
2661
|
+
insecure=False,
|
|
2662
|
+
compression=None,
|
|
2663
|
+
wait_for_ready=None,
|
|
2664
|
+
timeout=None,
|
|
2665
|
+
metadata=None):
|
|
2666
|
+
return grpc.experimental.unary_unary(
|
|
2667
|
+
request,
|
|
2668
|
+
target,
|
|
2669
|
+
'/terminal.TerminalStreamingService/BrowserNetworkEnable',
|
|
2670
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkEnableRequest.SerializeToString,
|
|
2671
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkEnableResponse.FromString,
|
|
2672
|
+
options,
|
|
2673
|
+
channel_credentials,
|
|
2674
|
+
insecure,
|
|
2675
|
+
call_credentials,
|
|
2676
|
+
compression,
|
|
2677
|
+
wait_for_ready,
|
|
2678
|
+
timeout,
|
|
2679
|
+
metadata,
|
|
2680
|
+
_registered_method=True)
|
|
2681
|
+
|
|
2682
|
+
@staticmethod
|
|
2683
|
+
def BrowserNetworkDisable(request,
|
|
2684
|
+
target,
|
|
2685
|
+
options=(),
|
|
2686
|
+
channel_credentials=None,
|
|
2687
|
+
call_credentials=None,
|
|
2688
|
+
insecure=False,
|
|
2689
|
+
compression=None,
|
|
2690
|
+
wait_for_ready=None,
|
|
2691
|
+
timeout=None,
|
|
2692
|
+
metadata=None):
|
|
2693
|
+
return grpc.experimental.unary_unary(
|
|
2694
|
+
request,
|
|
2695
|
+
target,
|
|
2696
|
+
'/terminal.TerminalStreamingService/BrowserNetworkDisable',
|
|
2697
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkDisableRequest.SerializeToString,
|
|
2698
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkDisableResponse.FromString,
|
|
2699
|
+
options,
|
|
2700
|
+
channel_credentials,
|
|
2701
|
+
insecure,
|
|
2702
|
+
call_credentials,
|
|
2703
|
+
compression,
|
|
2704
|
+
wait_for_ready,
|
|
2705
|
+
timeout,
|
|
2706
|
+
metadata,
|
|
2707
|
+
_registered_method=True)
|
|
2708
|
+
|
|
2709
|
+
@staticmethod
|
|
2710
|
+
def BrowserNetworkGetExchanges(request,
|
|
2711
|
+
target,
|
|
2712
|
+
options=(),
|
|
2713
|
+
channel_credentials=None,
|
|
2714
|
+
call_credentials=None,
|
|
2715
|
+
insecure=False,
|
|
2716
|
+
compression=None,
|
|
2717
|
+
wait_for_ready=None,
|
|
2718
|
+
timeout=None,
|
|
2719
|
+
metadata=None):
|
|
2720
|
+
return grpc.experimental.unary_unary(
|
|
2721
|
+
request,
|
|
2722
|
+
target,
|
|
2723
|
+
'/terminal.TerminalStreamingService/BrowserNetworkGetExchanges',
|
|
2724
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesRequest.SerializeToString,
|
|
2725
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesResponse.FromString,
|
|
2726
|
+
options,
|
|
2727
|
+
channel_credentials,
|
|
2728
|
+
insecure,
|
|
2729
|
+
call_credentials,
|
|
2730
|
+
compression,
|
|
2731
|
+
wait_for_ready,
|
|
2732
|
+
timeout,
|
|
2733
|
+
metadata,
|
|
2734
|
+
_registered_method=True)
|
|
2735
|
+
|
|
2736
|
+
@staticmethod
|
|
2737
|
+
def BrowserNetworkGetExchange(request,
|
|
2738
|
+
target,
|
|
2739
|
+
options=(),
|
|
2740
|
+
channel_credentials=None,
|
|
2741
|
+
call_credentials=None,
|
|
2742
|
+
insecure=False,
|
|
2743
|
+
compression=None,
|
|
2744
|
+
wait_for_ready=None,
|
|
2745
|
+
timeout=None,
|
|
2746
|
+
metadata=None):
|
|
2747
|
+
return grpc.experimental.unary_unary(
|
|
2748
|
+
request,
|
|
2749
|
+
target,
|
|
2750
|
+
'/terminal.TerminalStreamingService/BrowserNetworkGetExchange',
|
|
2751
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeRequest.SerializeToString,
|
|
2752
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeResponse.FromString,
|
|
2753
|
+
options,
|
|
2754
|
+
channel_credentials,
|
|
2755
|
+
insecure,
|
|
2756
|
+
call_credentials,
|
|
2757
|
+
compression,
|
|
2758
|
+
wait_for_ready,
|
|
2759
|
+
timeout,
|
|
2760
|
+
metadata,
|
|
2761
|
+
_registered_method=True)
|
|
2762
|
+
|
|
2763
|
+
@staticmethod
|
|
2764
|
+
def BrowserNetworkGetLast(request,
|
|
2765
|
+
target,
|
|
2766
|
+
options=(),
|
|
2767
|
+
channel_credentials=None,
|
|
2768
|
+
call_credentials=None,
|
|
2769
|
+
insecure=False,
|
|
2770
|
+
compression=None,
|
|
2771
|
+
wait_for_ready=None,
|
|
2772
|
+
timeout=None,
|
|
2773
|
+
metadata=None):
|
|
2774
|
+
return grpc.experimental.unary_unary(
|
|
2775
|
+
request,
|
|
2776
|
+
target,
|
|
2777
|
+
'/terminal.TerminalStreamingService/BrowserNetworkGetLast',
|
|
2778
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkGetLastRequest.SerializeToString,
|
|
2779
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkGetLastResponse.FromString,
|
|
2780
|
+
options,
|
|
2781
|
+
channel_credentials,
|
|
2782
|
+
insecure,
|
|
2783
|
+
call_credentials,
|
|
2784
|
+
compression,
|
|
2785
|
+
wait_for_ready,
|
|
2786
|
+
timeout,
|
|
2787
|
+
metadata,
|
|
2788
|
+
_registered_method=True)
|
|
2789
|
+
|
|
2790
|
+
@staticmethod
|
|
2791
|
+
def BrowserNetworkClear(request,
|
|
2792
|
+
target,
|
|
2793
|
+
options=(),
|
|
2794
|
+
channel_credentials=None,
|
|
2795
|
+
call_credentials=None,
|
|
2796
|
+
insecure=False,
|
|
2797
|
+
compression=None,
|
|
2798
|
+
wait_for_ready=None,
|
|
2799
|
+
timeout=None,
|
|
2800
|
+
metadata=None):
|
|
2801
|
+
return grpc.experimental.unary_unary(
|
|
2802
|
+
request,
|
|
2803
|
+
target,
|
|
2804
|
+
'/terminal.TerminalStreamingService/BrowserNetworkClear',
|
|
2805
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkClearRequest.SerializeToString,
|
|
2806
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkClearResponse.FromString,
|
|
2807
|
+
options,
|
|
2808
|
+
channel_credentials,
|
|
2809
|
+
insecure,
|
|
2810
|
+
call_credentials,
|
|
2811
|
+
compression,
|
|
2812
|
+
wait_for_ready,
|
|
2813
|
+
timeout,
|
|
2814
|
+
metadata,
|
|
2815
|
+
_registered_method=True)
|
|
2816
|
+
|
|
2817
|
+
@staticmethod
|
|
2818
|
+
def BrowserNetworkStats(request,
|
|
2819
|
+
target,
|
|
2820
|
+
options=(),
|
|
2821
|
+
channel_credentials=None,
|
|
2822
|
+
call_credentials=None,
|
|
2823
|
+
insecure=False,
|
|
2824
|
+
compression=None,
|
|
2825
|
+
wait_for_ready=None,
|
|
2826
|
+
timeout=None,
|
|
2827
|
+
metadata=None):
|
|
2828
|
+
return grpc.experimental.unary_unary(
|
|
2829
|
+
request,
|
|
2830
|
+
target,
|
|
2831
|
+
'/terminal.TerminalStreamingService/BrowserNetworkStats',
|
|
2832
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkStatsRequest.SerializeToString,
|
|
2833
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkStatsResponse.FromString,
|
|
2834
|
+
options,
|
|
2835
|
+
channel_credentials,
|
|
2836
|
+
insecure,
|
|
2837
|
+
call_credentials,
|
|
2838
|
+
compression,
|
|
2839
|
+
wait_for_ready,
|
|
2840
|
+
timeout,
|
|
2841
|
+
metadata,
|
|
2842
|
+
_registered_method=True)
|
|
2843
|
+
|
|
2844
|
+
@staticmethod
|
|
2845
|
+
def BrowserNetworkExportHAR(request,
|
|
2846
|
+
target,
|
|
2847
|
+
options=(),
|
|
2848
|
+
channel_credentials=None,
|
|
2849
|
+
call_credentials=None,
|
|
2850
|
+
insecure=False,
|
|
2851
|
+
compression=None,
|
|
2852
|
+
wait_for_ready=None,
|
|
2853
|
+
timeout=None,
|
|
2854
|
+
metadata=None):
|
|
2855
|
+
return grpc.experimental.unary_unary(
|
|
2856
|
+
request,
|
|
2857
|
+
target,
|
|
2858
|
+
'/terminal.TerminalStreamingService/BrowserNetworkExportHAR',
|
|
2859
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkExportHARRequest.SerializeToString,
|
|
2860
|
+
rpc__messages_dot_browser__pb2.BrowserNetworkExportHARResponse.FromString,
|
|
2861
|
+
options,
|
|
2862
|
+
channel_credentials,
|
|
2863
|
+
insecure,
|
|
2864
|
+
call_credentials,
|
|
2865
|
+
compression,
|
|
2866
|
+
wait_for_ready,
|
|
2867
|
+
timeout,
|
|
2868
|
+
metadata,
|
|
2869
|
+
_registered_method=True)
|
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,17 @@
|
|
|
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
|
+
from .network import NetworkCapability
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"ScrollCapability",
|
|
12
|
+
"InputCapability",
|
|
13
|
+
"TimingCapability",
|
|
14
|
+
"DOMCapability",
|
|
15
|
+
"FetchCapability",
|
|
16
|
+
"NetworkCapability",
|
|
17
|
+
]
|
|
@@ -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)
|