当前位置:网站首页>An article takes you to understand the working principle of selenium in detail

An article takes you to understand the working principle of selenium in detail

2022-07-06 09:01:00 Automated test seventh uncle

Preface

Selenium Is a Web Application automation testing tools .Selenium Test runs directly in browser , It's like a real user is doing it . Supported browsers include IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera etc. .

The main functions include : Test compatibility with browser —— Test your application to see if it works well on different browsers and operating systems .

Test system functions —— Create regression tests to verify software functionality and user requirements . Support automatic recording of actions and automatic generation .Net、Java、Perl Test scripts in different languages ( This is mainly for selenium ide)

One 、selenium course

04 year , The birth of Selenium Core,Selenium Core It is browser based and adopts JavaScript Testing tools for programming languages , Run in the security sandbox of the browser , The design concept is to test the product 、Selenium Core And test scripts are deployed to the same server to complete the work of automated testing .

05 year ,Selenium RC Be born , Namely selenium1 , This is the time ,Selenium Core It's actually Selenium RC At the heart of .

Selenium RC Let the product to be tested 、Selenium Core And test scripts are scattered on different servers .( The test script only cares about HTTP The request is sent to the specified URL On ,selenium You don't need to care HTTP What programming language is the request written in )

Selenium RC It consists of two parts : One is Selenium RC Server, One is to provide client drivers of various programming languages to write test scripts

07 year ,Webdriver Be born ,WebDriver Our design idea is to separate end-to-end testing from the underlying specific testing tools , And adopt design pattern Adapter Adapter to achieve the goal .WebDriver Of API Organizations are more object-oriented .

08/09 year ,selenium2 Be born ,selenium2 It's actually selenium rc and webdriver The merger of , The root cause of merger is to complement each other's shortcomings

09 year ,selenium3 Be born , This version eliminates selenium rc , Mainly by selenium webdriver and selenium Grid form , What we use everyday is actually selenium webdriver, as for selenium grid It is a distributed tool for automated testing

So today we will talk about selenium3(selenium webdriver) How it works , Hereinafter referred to as selenium( The above specific time may not be accurate , I also learned through online materials , throw away a brick in order to get a gem ^-^)

Two 、selenium principle

We use Selenium Implement automated testing , Main needs 3 Something

1. The test script , It can be python,java Write the script ( It can also be called client End )

2. Browser driven , This driver is developed according to different browsers , Different browsers use different webdriver Driver and corresponding browser version is required , such as :geckodriver.exe(chrome)

3. browser , at present selenium Support most browsers on the market , Such as : firefox , Google ,IE etc.

3、 ... and 、selenium Script

Let's start with a simple code

"""
from selenium import webdriver


dr = webdriver.Chrome()  #  Open the browser 

Execute the above code , We will find that the program is open Chrome browser ( Premise : You have configured it correctly chrome Driver and corresponding version )

that selenium How to realize this process ?ok, Today we will understand by analyzing the source code selenium How it works

Four 、 Source code analysis

see weddriver Source code ( Hold down Ctrl key , Mouse click Chrome)

C:\Python36\Lib\site-packages\selenium\webdriver\chrome\webdriver.py

 1 class WebDriver(RemoteWebDriver):
 2     """
 3     Controls the ChromeDriver and allows you to drive the browser.
 4 
 5     You will need to download the ChromeDriver executable from
 6     http://chromedriver.storage.googleapis.com/index.html
 7     """
 8 
 9     def __init__(self, executable_path="chromedriver", port=0,
10                  options=None, service_args=None,
11                  desired_capabilities=None, service_log_path=None,
12                  chrome_options=None, keep_alive=True):
13         """
14         Creates a new instance of the chrome driver.
15 
16         Starts the service and then creates new instance of chrome driver.
17 
18         :Args:
19          - executable_path - path to the executable. If the default is used it assumes the executable is in the $PATH
20          - port - port you would like the service to run, if left as 0, a free port will be found.
21          - options - this takes an instance of ChromeOptions
22          - service_args - List of args to pass to the driver service
23          - desired_capabilities - Dictionary object with non-browser specific
24            capabilities only, such as "proxy" or "loggingPref".
25          - service_log_path - Where to log information from the driver.
26          - chrome_options - Deprecated argument for options
27          - keep_alive - Whether to configure ChromeRemoteConnection to use HTTP keep-alive.
28         """
29         if chrome_options:
30             warnings.warn('use options instead of chrome_options',
31                           DeprecationWarning, stacklevel=2)
32             options = chrome_options
33 
34         if options is None:
35             # desired_capabilities stays as passed in
36             if desired_capabilities is None:
37                 desired_capabilities = self.create_options().to_capabilities()
38         else:
39             if desired_capabilities is None:
40                 desired_capabilities = options.to_capabilities()
41             else:
42                 desired_capabilities.update(options.to_capabilities())
43 
44         self.service = Service(
45             executable_path,
46             port=port,
47             service_args=service_args,
48             log_path=service_log_path)
49         self.service.start()
50 
51         try:
52             RemoteWebDriver.__init__(
53                 self,
54                 command_executor=ChromeRemoteConnection(
55                     remote_server_addr=self.service.service_url,
56                     keep_alive=keep_alive),
57                 desired_capabilities=desired_capabilities)
58         except Exception:
59             self.quit()
60             raise
61         self._is_remote = False

Through the source code 44-49 Line discovery , I've initialized one service object , And then it calls start() Method , So let's move on to the next 49 Yes start() What function does the method realize ?

C:\Python36\Lib\site-packages\selenium\webdriver\common\service.py

 1  def start(self):
 2         """
 3         Starts the Service.
 4 
 5         :Exceptions:
 6          - WebDriverException : Raised either when it can't start the service
 7            or when it can't connect to the service
 8         """
 9         try:
10             cmd = [self.path]
11             cmd.extend(self.command_line_args())
12             self.process = subprocess.Popen(cmd, env=self.env,
13                                             close_fds=platform.system() != 'Windows',
14                                             stdout=self.log_file,
15                                             stderr=self.log_file,
16                                             stdin=PIPE)
17         except TypeError:
18             raise
19         except OSError as err:
20             if err.errno == errno.ENOENT:
21                 raise WebDriverException(
22                     "'%s' executable needs to be in PATH. %s" % (
23                         os.path.basename(self.path), self.start_error_message)
24                 )
25             elif err.errno == errno.EACCES:
26                 raise WebDriverException(
27                     "'%s' executable may have wrong permissions. %s" % (
28                         os.path.basename(self.path), self.start_error_message)
29                 )
30             else:
31                 raise
32         except Exception as e:
33             raise WebDriverException(
34                 "The executable %s needs to be available in the path. %s\n%s" %
35                 (os.path.basename(self.path), self.start_error_message, str(e)))
36         count = 0
37         while True:
38             self.assert_process_still_running()
39             if self.is_connectable():
40                 break
41             count += 1
42             time.sleep(1)
43             if count == 30:
44                 raise WebDriverException("Can not connect to the Service %s" % self.path)

We found that 9-16 OK is actually executing a cmd command , The function of the command is to start chromedriver.exeChrome Browser driver

Here we need to pay attention to : The downloaded browser driver must be configured in the environment variable , Or put it in python Under the root directory of , It is convenient for the program to find when executing the driver

This process has the same effect as manually starting the browser driver , Similar to the following results

After starting the driver , Binding port number 9515, And only allow local access to this service , In fact, we can check our local computer task manager , Indeed, a service process program is opened

The first step is to execute the test script webdriver.Chrome() Automatically chromedriver.exe The driver , Then start a process

5、 ... and 、 How to open a browser

Let's keep looking at the source code C:\Python36\Lib\site-packages\selenium\webdriver\chrome\webdriver.py Of 51-57 Line code , Called parent class RemoteWebDriver Initialization method of , Let's see what this method does ?

C:\Python36\Lib\site-packages\selenium\webdriver\remote\webdriver.py

 1 class WebDriver(object):
 2     """
 3     Controls a browser by sending commands to a remote server.
 4     This server is expected to be running the WebDriver wire protocol
 5     as defined at
 6     https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol
 7 
 8     :Attributes:
 9      - session_id - String ID of the browser session started and controlled by this WebDriver.
10      - capabilities - Dictionaty of effective capabilities of this browser session as returned
11          by the remote server. See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities
12      - command_executor - remote_connection.RemoteConnection object used to execute commands.
13      - error_handler - errorhandler.ErrorHandler object used to handle errors.
14     """
15 
16     _web_element_cls = WebElement
17 
18     def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
19                  desired_capabilities=None, browser_profile=None, proxy=None,
20                  keep_alive=False, file_detector=None, options=None):
21         """
22         Create a new driver that will issue commands using the wire protocol.
23 
24         :Args:
25          - command_executor - Either a string representing URL of the remote server or a custom
26              remote_connection.RemoteConnection object. Defaults to 'http://127.0.0.1:4444/wd/hub'.
27          - desired_capabilities - A dictionary of capabilities to request when
28              starting the browser session. Required parameter.
29          - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object.
30              Only used if Firefox is requested. Optional.
31          - proxy - A selenium.webdriver.common.proxy.Proxy object. The browser session will
32              be started with given proxy settings, if possible. Optional.
33          - keep_alive - Whether to configure remote_connection.RemoteConnection to use
34              HTTP keep-alive. Defaults to False.
35          - file_detector - Pass custom file detector object during instantiation. If None,
36              then default LocalFileDetector() will be used.
37          - options - instance of a driver options.Options class
38         """
39         capabilities = {}
40         if options is not None:
41             capabilities = options.to_capabilities()
42         if desired_capabilities is not None:
43             if not isinstance(desired_capabilities, dict):
44                 raise WebDriverException("Desired Capabilities must be a dictionary")
45             else:
46                 capabilities.update(desired_capabilities)
47         if proxy is not None:
48             warnings.warn("Please use FirefoxOptions to set proxy",
49                           DeprecationWarning, stacklevel=2)
50             proxy.add_to_capabilities(capabilities)
51         self.command_executor = command_executor
52         if type(self.command_executor) is bytes or isinstance(self.command_executor, str):
53             self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)
54         self._is_remote = True
55         self.session_id = None
56         self.capabilities = {}
57         self.error_handler = ErrorHandler()
58         self.start_client()
59         if browser_profile is not None:
60             warnings.warn("Please use FirefoxOptions to set browser profile",
61                           DeprecationWarning, stacklevel=2)
62         self.start_session(capabilities, browser_profile)
63         self._switch_to = SwitchTo(self)
64         self._mobile = Mobile(self)
65         self.file_detector = file_detector or LocalFileDetector()

Here is a line of the most important code ,62 That's ok self.start_session(capabilities, browser_profile) This method , Continue to see what the source code of this method does

 1     def start_session(self, capabilities, browser_profile=None):
 2         """
 3         Creates a new session with the desired capabilities.
 4 
 5         :Args:
 6          - browser_name - The name of the browser to request.
 7          - version - Which browser version to request.
 8          - platform - Which platform to request the browser on.
 9          - javascript_enabled - Whether the new session should support JavaScript.
10          - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object. Only used if Firefox is requested.
11         """
12         if not isinstance(capabilities, dict):
13             raise InvalidArgumentException("Capabilities must be a dictionary")
14         if browser_profile:
15             if "moz:firefoxOptions" in capabilities:
16                 capabilities["moz:firefoxOptions"]["profile"] = browser_profile.encoded
17             else:
18                 capabilities.update({'firefox_profile': browser_profile.encoded})
19         w3c_caps = _make_w3c_caps(capabilities)
20         parameters = {"capabilities": w3c_caps,
21                       "desiredCapabilities": capabilities}
22         response = self.execute(Command.NEW_SESSION, parameters)
23         if 'sessionId' not in response:
24             response = response['value']
25         self.session_id = response['sessionId']
26         self.capabilities = response.get('value')
27 
28         # if capabilities is none we are probably speaking to
29         # a W3C endpoint
30         if self.capabilities is None:
31             self.capabilities = response.get('capabilities')
32 
33         # Double check to see if we have a W3C Compliant browser
34         self.w3c = response.get('status') is None
35         self.command_executor.w3c = self.w3c

Analyzing this part of the source code can find 22 Line is to address localhost:9515/session Sent a post request , Parameter is json Format , Then return specific response information to the program ( Here is a new one sessionid), Finally opened the browser

ok, The operation of opening the browser is completed

6、 ... and 、 How to perform corresponding operations

see C:\Python36\Lib\site-packages\selenium\webdriver\chrome\webdriver.py Source code ( In the first source code 51-57 That's ok )

51         try:
52             RemoteWebDriver.__init__(
53                 self,
54                 command_executor=ChromeRemoteConnection(
55                     remote_server_addr=self.service.service_url,
56                     keep_alive=keep_alive),
57                 desired_capabilities=desired_capabilities)

Click on ChromeRemoteConnection Check the source code

 1 from selenium.webdriver.remote.remote_connection import RemoteConnection
 2 
 3 
 4 class ChromeRemoteConnection(RemoteConnection):
 5 
 6     def __init__(self, remote_server_addr, keep_alive=True):
 7         RemoteConnection.__init__(self, remote_server_addr, keep_alive)
 8         self._commands["launchApp"] = ('POST', '/session/$sessionId/chromium/launch_app')
 9         self._commands["setNetworkConditions"] = ('POST', '/session/$sessionId/chromium/network_conditions')
10         self._commands["getNetworkConditions"] = ('GET', '/session/$sessionId/chromium/network_conditions')
11         self._commands['executeCdpCommand'] = ('POST', '/session/$sessionId/goog/cdp/execute')

The first 7 Line access is localhost:9515/session Address , The first 8-11 That's ok , It defines some browsers that we use (chrome) Unique interface address , Let's take a look at the parent class RemoteConnection Inside the source code

C:\Python36\Lib\site-packages\selenium\webdriver\remote\remote_connection.py:RemoteConnection

  1 self._commands = {
  2             Command.STATUS: ('GET', '/status'),
  3             Command.NEW_SESSION: ('POST', '/session'),
  4             Command.GET_ALL_SESSIONS: ('GET', '/sessions'),
  5             Command.QUIT: ('DELETE', '/session/$sessionId'),
  6             Command.GET_CURRENT_WINDOW_HANDLE:
  7                 ('GET', '/session/$sessionId/window_handle'),
  8             Command.W3C_GET_CURRENT_WINDOW_HANDLE:
  9                 ('GET', '/session/$sessionId/window'),
 10             Command.GET_WINDOW_HANDLES:
 11                 ('GET', '/session/$sessionId/window_handles'),
 12             Command.W3C_GET_WINDOW_HANDLES:
 13                 ('GET', '/session/$sessionId/window/handles'),
 14             Command.GET: ('POST', '/session/$sessionId/url'),
 15             Command.GO_FORWARD: ('POST', '/session/$sessionId/forward'),
 16             Command.GO_BACK: ('POST', '/session/$sessionId/back'),
 17             Command.REFRESH: ('POST', '/session/$sessionId/refresh'),
 18             Command.EXECUTE_SCRIPT: ('POST', '/session/$sessionId/execute'),
 19             Command.W3C_EXECUTE_SCRIPT:
 20                 ('POST', '/session/$sessionId/execute/sync'),
 21             Command.W3C_EXECUTE_SCRIPT_ASYNC:
 22                 ('POST', '/session/$sessionId/execute/async'),
 23             Command.GET_CURRENT_URL: ('GET', '/session/$sessionId/url'),
 24             Command.GET_TITLE: ('GET', '/session/$sessionId/title'),
 25             Command.GET_PAGE_SOURCE: ('GET', '/session/$sessionId/source'),
 26             Command.SCREENSHOT: ('GET', '/session/$sessionId/screenshot'),
 27             Command.ELEMENT_SCREENSHOT: ('GET', '/session/$sessionId/element/$id/screenshot'),
 28             Command.FIND_ELEMENT: ('POST', '/session/$sessionId/element'),
 29             Command.FIND_ELEMENTS: ('POST', '/session/$sessionId/elements'),
 30             Command.W3C_GET_ACTIVE_ELEMENT: ('GET', '/session/$sessionId/element/active'),
 31             Command.GET_ACTIVE_ELEMENT:
 32                 ('POST', '/session/$sessionId/element/active'),
 33             Command.FIND_CHILD_ELEMENT:
 34                 ('POST', '/session/$sessionId/element/$id/element'),
 35             Command.FIND_CHILD_ELEMENTS:
 36                 ('POST', '/session/$sessionId/element/$id/elements'),
 37             Command.CLICK_ELEMENT: ('POST', '/session/$sessionId/element/$id/click'),
 38             Command.CLEAR_ELEMENT: ('POST', '/session/$sessionId/element/$id/clear'),
 39             Command.SUBMIT_ELEMENT: ('POST', '/session/$sessionId/element/$id/submit'),
 40             Command.GET_ELEMENT_TEXT: ('GET', '/session/$sessionId/element/$id/text'),
 41             Command.SEND_KEYS_TO_ELEMENT:
 42                 ('POST', '/session/$sessionId/element/$id/value'),
 43             Command.SEND_KEYS_TO_ACTIVE_ELEMENT:
 44                 ('POST', '/session/$sessionId/keys'),
 45             Command.UPLOAD_FILE: ('POST', "/session/$sessionId/file"),
 46             Command.GET_ELEMENT_VALUE:
 47                 ('GET', '/session/$sessionId/element/$id/value'),
 48             Command.GET_ELEMENT_TAG_NAME:
 49                 ('GET', '/session/$sessionId/element/$id/name'),
 50             Command.IS_ELEMENT_SELECTED:
 51                 ('GET', '/session/$sessionId/element/$id/selected'),
 52             Command.SET_ELEMENT_SELECTED:
 53                 ('POST', '/session/$sessionId/element/$id/selected'),
 54             Command.IS_ELEMENT_ENABLED:
 55                 ('GET', '/session/$sessionId/element/$id/enabled'),
 56             Command.IS_ELEMENT_DISPLAYED:
 57                 ('GET', '/session/$sessionId/element/$id/displayed'),
 58             Command.GET_ELEMENT_LOCATION:
 59                 ('GET', '/session/$sessionId/element/$id/location'),
 60             Command.GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW:
 61                 ('GET', '/session/$sessionId/element/$id/location_in_view'),
 62             Command.GET_ELEMENT_SIZE:
 63                 ('GET', '/session/$sessionId/element/$id/size'),
 64             Command.GET_ELEMENT_RECT:
 65                 ('GET', '/session/$sessionId/element/$id/rect'),
 66             Command.GET_ELEMENT_ATTRIBUTE:
 67                 ('GET', '/session/$sessionId/element/$id/attribute/$name'),
 68             Command.GET_ELEMENT_PROPERTY:
 69                 ('GET', '/session/$sessionId/element/$id/property/$name'),
 70             Command.GET_ALL_COOKIES: ('GET', '/session/$sessionId/cookie'),
 71             Command.ADD_COOKIE: ('POST', '/session/$sessionId/cookie'),
 72             Command.GET_COOKIE: ('GET', '/session/$sessionId/cookie/$name'),
 73             Command.DELETE_ALL_COOKIES:
 74                 ('DELETE', '/session/$sessionId/cookie'),
 75             Command.DELETE_COOKIE:
 76                 ('DELETE', '/session/$sessionId/cookie/$name'),
 77             Command.SWITCH_TO_FRAME: ('POST', '/session/$sessionId/frame'),
 78             Command.SWITCH_TO_PARENT_FRAME: ('POST', '/session/$sessionId/frame/parent'),
 79             Command.SWITCH_TO_WINDOW: ('POST', '/session/$sessionId/window'),
 80             Command.CLOSE: ('DELETE', '/session/$sessionId/window'),
 81             Command.GET_ELEMENT_VALUE_OF_CSS_PROPERTY:
 82                 ('GET', '/session/$sessionId/element/$id/css/$propertyName'),
 83             Command.IMPLICIT_WAIT:
 84                 ('POST', '/session/$sessionId/timeouts/implicit_wait'),
 85             Command.EXECUTE_ASYNC_SCRIPT: ('POST', '/session/$sessionId/execute_async'),
 86             Command.SET_SCRIPT_TIMEOUT:
 87                 ('POST', '/session/$sessionId/timeouts/async_script'),
 88             Command.SET_TIMEOUTS:
 89                 ('POST', '/session/$sessionId/timeouts'),
 90             Command.DISMISS_ALERT:
 91                 ('POST', '/session/$sessionId/dismiss_alert'),
 92             Command.W3C_DISMISS_ALERT:
 93                 ('POST', '/session/$sessionId/alert/dismiss'),
 94             Command.ACCEPT_ALERT:
 95                 ('POST', '/session/$sessionId/accept_alert'),
 96             Command.W3C_ACCEPT_ALERT:
 97                 ('POST', '/session/$sessionId/alert/accept'),
 98             Command.SET_ALERT_VALUE:
 99                 ('POST', '/session/$sessionId/alert_text'),
100             Command.W3C_SET_ALERT_VALUE:
101                 ('POST', '/session/$sessionId/alert/text'),
102             Command.GET_ALERT_TEXT:
103                 ('GET', '/session/$sessionId/alert_text'),
104             Command.W3C_GET_ALERT_TEXT:
105                 ('GET', '/session/$sessionId/alert/text'),
106             Command.SET_ALERT_CREDENTIALS:
107                 ('POST', '/session/$sessionId/alert/credentials'),
108             Command.CLICK:
109                 ('POST', '/session/$sessionId/click'),
110             Command.W3C_ACTIONS:
111                 ('POST', '/session/$sessionId/actions'),
112             Command.W3C_CLEAR_ACTIONS:
113                 ('DELETE', '/session/$sessionId/actions'),
114             Command.DOUBLE_CLICK:
115                 ('POST', '/session/$sessionId/doubleclick'),
116             Command.MOUSE_DOWN:
117                 ('POST', '/session/$sessionId/buttondown'),
118             Command.MOUSE_UP:
119                 ('POST', '/session/$sessionId/buttonup'),
120             Command.MOVE_TO:
121                 ('POST', '/session/$sessionId/moveto'),
122             Command.GET_WINDOW_SIZE:
123                 ('GET', '/session/$sessionId/window/$windowHandle/size'),
124             Command.SET_WINDOW_SIZE:
125                 ('POST', '/session/$sessionId/window/$windowHandle/size'),
126             Command.GET_WINDOW_POSITION:
127                 ('GET', '/session/$sessionId/window/$windowHandle/position'),
128             Command.SET_WINDOW_POSITION:
129                 ('POST', '/session/$sessionId/window/$windowHandle/position'),
130             Command.SET_WINDOW_RECT:
131                 ('POST', '/session/$sessionId/window/rect'),
132             Command.GET_WINDOW_RECT:
133                 ('GET', '/session/$sessionId/window/rect'),
134             Command.MAXIMIZE_WINDOW:
135                 ('POST', '/session/$sessionId/window/$windowHandle/maximize'),
136             Command.W3C_MAXIMIZE_WINDOW:
137                 ('POST', '/session/$sessionId/window/maximize'),
138             Command.SET_SCREEN_ORIENTATION:
139                 ('POST', '/session/$sessionId/orientation'),
140             Command.GET_SCREEN_ORIENTATION:
141                 ('GET', '/session/$sessionId/orientation'),
142             Command.SINGLE_TAP:
143                 ('POST', '/session/$sessionId/touch/click'),
144             Command.TOUCH_DOWN:
145                 ('POST', '/session/$sessionId/touch/down'),
146             Command.TOUCH_UP:
147                 ('POST', '/session/$sessionId/touch/up'),
148             Command.TOUCH_MOVE:
149                 ('POST', '/session/$sessionId/touch/move'),
150             Command.TOUCH_SCROLL:
151                 ('POST', '/session/$sessionId/touch/scroll'),
152             Command.DOUBLE_TAP:
153                 ('POST', '/session/$sessionId/touch/doubleclick'),
154             Command.LONG_PRESS:
155                 ('POST', '/session/$sessionId/touch/longclick'),
156             Command.FLICK:
157                 ('POST', '/session/$sessionId/touch/flick'),
158             Command.EXECUTE_SQL:
159                 ('POST', '/session/$sessionId/execute_sql'),
160             Command.GET_LOCATION:
161                 ('GET', '/session/$sessionId/location'),
162             Command.SET_LOCATION:
163                 ('POST', '/session/$sessionId/location'),
164             Command.GET_APP_CACHE:
165                 ('GET', '/session/$sessionId/application_cache'),
166             Command.GET_APP_CACHE_STATUS:
167                 ('GET', '/session/$sessionId/application_cache/status'),
168             Command.CLEAR_APP_CACHE:
169                 ('DELETE', '/session/$sessionId/application_cache/clear'),
170             Command.GET_NETWORK_CONNECTION:
171                 ('GET', '/session/$sessionId/network_connection'),
172             Command.SET_NETWORK_CONNECTION:
173                 ('POST', '/session/$sessionId/network_connection'),
174             Command.GET_LOCAL_STORAGE_ITEM:
175                 ('GET', '/session/$sessionId/local_storage/key/$key'),
176             Command.REMOVE_LOCAL_STORAGE_ITEM:
177                 ('DELETE', '/session/$sessionId/local_storage/key/$key'),
178             Command.GET_LOCAL_STORAGE_KEYS:
179                 ('GET', '/session/$sessionId/local_storage'),
180             Command.SET_LOCAL_STORAGE_ITEM:
181                 ('POST', '/session/$sessionId/local_storage'),
182             Command.CLEAR_LOCAL_STORAGE:
183                 ('DELETE', '/session/$sessionId/local_storage'),
184             Command.GET_LOCAL_STORAGE_SIZE:
185                 ('GET', '/session/$sessionId/local_storage/size'),
186             Command.GET_SESSION_STORAGE_ITEM:
187                 ('GET', '/session/$sessionId/session_storage/key/$key'),
188             Command.REMOVE_SESSION_STORAGE_ITEM:
189                 ('DELETE', '/session/$sessionId/session_storage/key/$key'),
190             Command.GET_SESSION_STORAGE_KEYS:
191                 ('GET', '/session/$sessionId/session_storage'),
192             Command.SET_SESSION_STORAGE_ITEM:
193                 ('POST', '/session/$sessionId/session_storage'),
194             Command.CLEAR_SESSION_STORAGE:
195                 ('DELETE', '/session/$sessionId/session_storage'),
196             Command.GET_SESSION_STORAGE_SIZE:
197                 ('GET', '/session/$sessionId/session_storage/size'),
198             Command.GET_LOG:
199                 ('POST', '/session/$sessionId/log'),
200             Command.GET_AVAILABLE_LOG_TYPES:
201                 ('GET', '/session/$sessionId/log/types'),
202             Command.CURRENT_CONTEXT_HANDLE:
203                 ('GET', '/session/$sessionId/context'),
204             Command.CONTEXT_HANDLES:
205                 ('GET', '/session/$sessionId/contexts'),
206             Command.SWITCH_TO_CONTEXT:
207                 ('POST', '/session/$sessionId/context'),
208             Command.FULLSCREEN_WINDOW:
209                 ('POST', '/session/$sessionId/window/fullscreen'),
210             Command.MINIMIZE_WINDOW:
211                 ('POST', '/session/$sessionId/window/minimize')
212         }

This class defines all selenium Interface address required for operation ( These interface addresses are all encapsulated in the browser driver ), Then all browser operations are realized by accessing these interfaces

among Command.GET: ('POST', '/session/$sessionId/url') This address is to visit a website url , Let's record it first, which will be useful later

ok, We know the corresponding interface address of all operations , So how to implement these interfaces to achieve various operations on the browser ? Continue to look at the source code next to the interface address definition

 1     def execute(self, command, params):
 2         """
 3         Send a command to the remote server.
 4 
 5         Any path subtitutions required for the URL mapped to the command should be
 6         included in the command parameters.
 7 
 8         :Args:
 9          - command - A string specifying the command to execute.
10          - params - A dictionary of named parameters to send with the command as
11            its JSON payload.
12         """
13         command_info = self._commands[command]
14         assert command_info is not None, 'Unrecognised command %s' % command
15         path = string.Template(command_info[1]).substitute(params)
16         if hasattr(self, 'w3c') and self.w3c and isinstance(params, dict) and 'sessionId' in params:
17             del params['sessionId']
18         data = utils.dump_json(params)
19         url = '%s%s' % (self._url, path)
20         return self._request(command_info[0], url, body=data)
21 
22     def _request(self, method, url, body=None):
23         """
24         Send an HTTP request to the remote server.
25 
26         :Args:
27          - method - A string for the HTTP method to send the request with.
28          - url - A string for the URL to send the request to.
29          - body - A string for request body. Ignored unless method is POST or PUT.
30 
31         :Returns:
32           A dictionary with the server's parsed JSON response.
33         """
34         LOGGER.debug('%s %s %s' % (method, url, body))
35 
36         parsed_url = parse.urlparse(url)
37         headers = self.get_remote_connection_headers(parsed_url, self.keep_alive)
38         resp = None
39         if body and method != 'POST' and method != 'PUT':
40             body = None
41 
42         if self.keep_alive:
43             resp = self._conn.request(method, url, body=body, headers=headers)
44 
45             statuscode = resp.status
46         else:
47             http = urllib3.PoolManager(timeout=self._timeout)
48             resp = http.request(method, url, body=body, headers=headers)
49 
50             statuscode = resp.status
51             if not hasattr(resp, 'getheader'):
52                 if hasattr(resp.headers, 'getheader'):
53                     resp.getheader = lambda x: resp.headers.getheader(x)
54                 elif hasattr(resp.headers, 'get'):
55                     resp.getheader = lambda x: resp.headers.get(x)
56 
57         data = resp.data.decode('UTF-8')
58         try:
59             if 300 <= statuscode < 304:
60                 return self._request('GET', resp.getheader('location'))
61             if 399 < statuscode <= 500:
62                 return {'status': statuscode, 'value': data}
63             content_type = []
64             if resp.getheader('Content-Type') is not None:
65                 content_type = resp.getheader('Content-Type').split(';')
66             if not any([x.startswith('image/png') for x in content_type]):
67 
68                 try:
69                     data = utils.load_json(data.strip())
70                 except ValueError:
71                     if 199 < statuscode < 300:
72                         status = ErrorCode.SUCCESS
73                     else:
74                         status = ErrorCode.UNKNOWN_ERROR
75                     return {'status': status, 'value': data.strip()}
76 
77                 # Some of the drivers incorrectly return a response
78                 # with no 'value' field when they should return null.
79                 if 'value' not in data:
80                     data['value'] = None
81                 return data
82             else:
83                 data = {'status': 0, 'value': data}
84                 return data
85         finally:
86             LOGGER.debug("Finished Request")
87             resp.close()

It can be seen mainly through execute Method call _request Methods by urilib3 The standard library sends the corresponding operation request address to the server , And then realize various browser operations

Some people will ask how opening the browser and operating the browser to achieve various actions are related ?

Actually , Opening the browser is also sending a request , The request will return a sessionid, Various interface addresses for later operations , You will also find a variable in the interface address $sessionid, It is not difficult to guess that you have used the browser to open and operate the browser sessionid Relate together , To operate in the same browser

The second step is to browse it and realize various operation principles

7、 ... and 、 simulation selenium

Now we can check the request parameters of opening the browser and accessing the home page of my blog through the following code

"""
from selenium import webdriver
import logging


logging.basicConfig(level=logging.DEBUG)  #  Print the log in the source code 
dr = webdriver.Chrome() #  Open the browser 
driver.get("https://www.cnblogs.com/linuxchao/") #  Visit my blog home page 

Output log information

DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:55695/session 
{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName": "chrome", "platformName": "any", "goog:chromeOptions": 
{"extensions": [], "args": []}}}, "desiredCapabilities": {"browserName": "chrome", "version": "", "platform": "ANY", 
"goog:chromeOptions": {"extensions": [], "args": []}}}
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 127.0.0.1
DEBUG:urllib3.connectionpool:http://127.0.0.1:55695 "POST /session HTTP/1.1" 200 830
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:51006/session/09d52393b7dfcb45b8bb9101885ce206/url 
{"url": "https://www.cnblogs.com/linuxchao/", "sessionId": "09d52393b7dfcb45b8bb9101885ce206"}
DEBUG:urllib3.connectionpool:http://127.0.0.1:51006 "POST /session/09d52393b7dfcb45b8bb9101885ce206/url HTTP/1.1" 200 72
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
Process finished with exit code 0

It is obvious through the implementation results selenium The process of execution , The program tells RemoteWebDriver Open a browser ( send out post request , Bring the request parameters ), And then remote server Send a request to perform a browser action

So for a deeper understanding selenium Realize the process of automated testing , We can write our own program to simulate the operation process of opening the browser and then controlling the browser to access my blog address

First, we need to keep the browser driver open , Then write the following code and execute

"""
import requests


#  Request address ( Open the browser )
driver_url = 'http://localhost:9515/session'
#  Open the request parameters of the browser 
driver_value = {"capabilities":
                    {"firstMatch": [{}],
                     "alwaysMatch":
                         {"browserName":
                              "chrome",
                          "platformName": "any",
                          "goog:chromeOptions":
                              {"extensions": [], "args": []}}},
                "desiredCapabilities":
                    {"browserName":
                         "chrome",
                     "version": "",
                     "platform": "ANY",
                     "goog:chromeOptions": {"extensions": [],
                                            "args": []}}}
#  Send clear 
response_session = requests.post(driver_url, json = driver_value)
print(response_session.json())
#  The requested address to visit my blog  ( This address is the address we recorded above )
url = 'http://localhost:9515/session/'+response_session.json()['sessionId']+'/url'
#  Request parameters for accessing my blog 
value = {"url": "https://www.cnblogs.com/linuxchao/", "sessionId": response_session.json()['sessionId']}
response_blog = requests.post(url = url,json = value)
print(response_blog.json())

Execution results

{'sessionId': '25144efef880dcce53e4e6f60c342e9d', 'status': 0, 'value': 
{'acceptInsecureCerts': False, 'acceptSslCerts': False, 'applicationCacheEnabled': False, 
'browserConnectionEnabled': False, 'browserName': 'chrome', 'chrome': 
{'chromedriverVersion': '2.39.562718 (9a2698cba08cf5a471a29d30c8b3e12becabb0e9)', 
'userDataDir': 'C:\\Users\\v-xug\\AppData\\Local\\Temp\\scoped_dir9944_25238'}, 
'cssSelectorsEnabled': True, 'databaseEnabled': False, 'handlesAlerts': True, 
'hasTouchScreen': False, 'javascriptEnabled': True, 'locationContextEnabled': True, 
'mobileEmulationEnabled': False, 'nativeEvents': True, 'networkConnectionEnabled': False, 
'pageLoadStrategy': 'normal', 'platform': 'Windows NT', 'rotatable': False, 'setWindowRect': True,
'takesHeapSnapshot': True, 'takesScreenshot': True, 'unexpectedAlertBehaviour': '', 'version': '75.0.3770.100', 'webStorageEnabled': True}}
{'sessionId': '25144efef880dcce53e4e6f60c342e9d', 'status': 0, 'value': None}

Process finished with exit code 0

The most important information in the above return information is 'sessionId': '25144efef880dcce53e4e6f60c342e9d', You can also see from the code that you can visit my blog address url It is spliced with this parameter , Because after opening the browser , All the following operations are based on this sessionid Of

You will see Chrome The browser is opened , And opened my blog address https://www.cnblogs.com/linuxchao/, This is it. selenium A process of principle

8、 ... and 、 Last

You can't understand the previous code , It doesn't matter , Let's talk about it again selenium Process of work

1.selenium client(python And so on ) Initialize a service service , adopt Webdriver Launch browser driver chromedriver.exe

2. adopt RemoteWebDriver Send... To browser driver HTTP request , Browser driver parsing request , Open the browser , And get sessionid, If you want to operate the browser again, you need to carry this id

3. Open the browser , Binding specific ports , Take the launched browser as webdriver Of remote server

3. After opening the browser , be-all selenium The operation of ( Access address , Find elements, etc ) All pass RemoteConnection link to remote server, And then use execute Method call _request Methods by urlib3 towards remote server Send a request

4. The browser performs the corresponding action through the requested content

5. The browser then returns the result of the action to the test script through the browser driver

summary

That's all for today's article , Favorite friends can like collections and follow comments .

 

原网站

版权声明
本文为[Automated test seventh uncle]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207060856581320.html