日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一篇文章带你了解-selenium工作原理详解

發布時間:2024/1/1 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一篇文章带你了解-selenium工作原理详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

Selenium是一個用于Web應用程序自動化測試工具。Selenium測試直接運行在瀏覽器中,就像真正的用戶在操作一樣。支持的瀏覽器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。

主要功能包括:測試與瀏覽器的兼容性——測試你的應用程序看是否能夠很好得工作在不同瀏覽器和操作系統之上。

測試系統功能——創建回歸測試檢驗軟件功能和用戶需求。支持自動錄制動作和自動生成 .Net、Java、Perl等不同語言的測試腳本(這里主要是針對selenium ide)

一、selenium歷程

04年,誕生了Selenium Core,Selenium Core是基于瀏覽器并且采用JavaScript編程語言的測試工具,運行在瀏覽器的安全沙箱中,設計理念是將待測試產品、Selenium Core和測試腳本均部署到同一臺服務器上來完成自動化測試的工作。

05年,Selenium RC誕生,就是selenium1 ,這個時候,Selenium Core其實是Selenium RC的核心。

Selenium RC讓待測試產品、Selenium Core和測試腳本三者分散在不同的服務器上。(測試腳本只關心將HTTP請求發送到指定的URL上,selenium本身不需要關心HTTP請求由于什么程序編程語言編寫而成)

Selenium RC包括兩部分:一個是Selenium RC Server,一個是提供各種編程語言的客戶端驅動來編寫測試腳本

07年,Webdriver誕生,WebDriver的設計理念是將端到端測試與底層具體的測試工具分隔離,并采用設計模式Adapter適配器來達到目標。WebDriver的API組織更多的是面向對象。

08/09年,selenium2誕生,selenium2其實是selenium rc和webdriver的合并,合并的根本原因是相互補充各自的缺點

09年,selenium3誕生,這個版本剔除了selenium rc , 主要由 selenium webdriver和selenium Grid組成, 我們日常使用的其實就是selenium webdriver,至于selenium grid是一個分布式實現自動化測試的工具

那么今天我們就要說說selenium3(selenium webdriver)的工作原理,下面簡稱selenium(以上具體時間可能不太準確,我也是通過網絡資料了解到的,拋磚引玉^-^)

二、selenium原理

我們使用Selenium實現自動化測試,主要需要3個東西

1.測試腳本,可以是python,java編寫的腳本程序(也可以叫做client端)

2.瀏覽器驅動, 這個驅動是根據不同的瀏覽器開發的,不同的瀏覽器使用不同的webdriver驅動程序且需要對應相應的瀏覽器版本,比如:geckodriver.exe(chrome)

3.瀏覽器,目前selenium支持市面上大多數瀏覽器,如:火狐,谷歌,IE等

三、selenium腳本

先看一個簡單的代碼

""" from selenium import webdriverdr = webdriver.Chrome() # 打開瀏覽器

執行上述代碼,我們會發現程序打開了Chrome瀏覽器(前提:你已經正確配置了chrome的驅動和對應版本)

那么selenium是如何實現這個過程的呢?ok,我們今天就通過分析源碼的方式來理解selenium的工作原理

四、源碼分析

查看weddriver源碼(按住Ctrl鍵,鼠標點擊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 from6 http://chromedriver.storage.googleapis.com/index.html7 """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

通過源碼中的44-49行發現,初始化了一個service對象,然后調用了start()方法,那么我們繼續看下一49行的start()方法到底實現了什么功能?

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 service7 or when it can't connect to the service8 """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)

我們發現9-16行其實就是執行了一個cmd命令,命令的作用就是啟動了chromedriver.exeChrome瀏覽器的驅動程序

這里我們需要注意一點: 下載的瀏覽器驅動一定要配置到環境變量中,或者放到python的根目錄下,便于程序在執行驅動的時候查找

這個過程和我們手動啟動瀏覽器驅動是一樣的效果,類似下面的結果

啟動驅動程序后,綁定端口號9515,且只允許本地訪問這個服務,其實我們可以查看一下我們本地電腦任務管理器,確實開啟了一個服務進程程序

第一步工作我們已經知道了執行測試腳本webdriver.Chrome()會自動執行chromedriver.exe驅動程序,然后開啟一個進程

五、如何打開瀏覽器

我們繼續看源碼 C:\Python36\Lib\site-packages\selenium\webdriver\chrome\webdriver.py 的51-57行代碼,調用了父類RemoteWebDriver 的初始化方法,我們看這個方法做了什么事?

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 protocol5 as defined at6 https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol7 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()

這里有一行最重要的代碼,62行self.start_session(capabilities, browser_profile) 這個方法,繼續看一下這個方法的源碼做了什么工作

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

分析這部分源碼可以發現22行是向地址localhost:9515/session發送了一個post請求,參數是json格式的,然后返回特定的響應信息給程序(這里主要就是新建了一個sessionid),最終打開了瀏覽器

ok,打開瀏覽器的操作完成了

六、如何執行對應操作

查看C:\Python36\Lib\site-packages\selenium\webdriver\chrome\webdriver.py源碼(第一個源碼中的51-57行)

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)

點擊ChromeRemoteConnection查看一下源碼

1 from selenium.webdriver.remote.remote_connection import RemoteConnection2 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')

第7行訪問的是localhost:9515/session地址,第8-11行,定義了一些和我們使用的瀏覽器(chrome)特有的接口地址,我們再看一下父類RemoteConnection里面源碼

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 }

這個類里面定義了所有的selenium操作需要的接口地址(這些接口地址全部封裝在瀏覽器驅動程序中),那么所有的瀏覽器操作就是通過訪問這些接口來實現的

其中 Command.GET: ('POST', '/session/$sessionId/url') 這個地址就是實現訪問一個網址的url ,我們先記錄一下后面有用

ok,所有的操作對應接口地址我們知道了,那么又怎樣執行這些接口來達到在瀏覽器上實現各種操作呢?繼續看緊接著接口地址定義下面的源碼

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 be6 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()

可以看到主要是通過execute方法調用_request方法通過urilib3標準庫向服務器發送對應操作請求地址,進而實現了瀏覽器各種操作

有人會問打開瀏覽器和操作瀏覽器實現各種動作是怎么關聯的呢?

其實,打開瀏覽器也是發送請求,請求會返回一個sessionid,后面操作的各種接口地址,你也會發現接口地址中存在一個變量$sessionid,那么不難猜測打開瀏覽器和操作瀏覽器就是用過sessionid關聯到一起,達到在同一個瀏覽器中做操作

第二步在瀏覽其上實現各種操作原理也完成了

七、模擬selenium

現在我們可以通過下面的一段代碼查看一下打開瀏覽器和訪問我的博客首頁的請求參數是什么樣子的

""" from selenium import webdriver import logginglogging.basicConfig(level=logging.DEBUG) # 打印源碼中的日志 dr = webdriver.Chrome() # 打開瀏覽器 driver.get("https://www.cnblogs.com/linuxchao/") # 訪問我的博客首頁

輸出日志信息

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

通過執行結果就很明顯明白selenium執行的過程了,程序告訴RemoteWebDriver打開一個瀏覽器(發送post請求,帶上請求參數),然后再向remote server發送執行瀏覽器動作的請求

那么為了更加深入理解selenium實現自動化測試的過程,我們可以自己編寫程序模擬一下打開瀏覽器然后控制瀏覽器訪問我的博客地址的操作過程

首先我們需要保持瀏覽器的驅動程序打開狀態,然后編寫如下代碼并執行

""" import requests# 請求地址(打開瀏覽器) driver_url = 'http://localhost:9515/session' # 打開瀏覽器的請求參數 driver_value = {"capabilities":{"firstMatch": [{}],"alwaysMatch":{"browserName":"chrome","platformName": "any","goog:chromeOptions":{"extensions": [], "args": []}}},"desiredCapabilities":{"browserName":"chrome","version": "","platform": "ANY","goog:chromeOptions": {"extensions": [],"args": []}}} # 發送求清 response_session = requests.post(driver_url, json = driver_value) print(response_session.json()) # 訪問我的博客的請求地址 (這個地址是我們上面記錄的地址) url = 'http://localhost:9515/session/'+response_session.json()['sessionId']+'/url' # 訪問我的博客的請求參數 value = {"url": "https://www.cnblogs.com/linuxchao/", "sessionId": response_session.json()['sessionId']} response_blog = requests.post(url = url,json = value) print(response_blog.json())

執行結果

{'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

上面的返回信息中最重要的信息是'sessionId': '25144efef880dcce53e4e6f60c342e9d',從代碼中你也可以看到訪問我的博客地址的url是使用這個參數拼接的,因為打開瀏覽器后,后面所有的操作都是基于這個sessionid的

你還會看到Chrome瀏覽器被打開,且打開了我的博客地址https://www.cnblogs.com/linuxchao/,這就是selenium原理的一個過程了

八、最后

前面的代碼你看不懂,也沒關系,我們再來敘述一下selenium工作的過程

1.selenium client(python等語言編寫的自動化測試腳本)初始化一個service服務,通過Webdriver啟動瀏覽器驅動程序chromedriver.exe

2.通過RemoteWebDriver向瀏覽器驅動程序發送HTTP請求,瀏覽器驅動程序解析請求,打開瀏覽器,并獲得sessionid,如果再次對瀏覽器操作需攜帶此id

3.打開瀏覽器,綁定特定的端口,把啟動后的瀏覽器作為webdriver的remote server

3.打開瀏覽器后,所有的selenium的操作(訪問地址,查找元素等)均通過RemoteConnection鏈接到remote server,然后使用execute方法調用_request方法通過urlib3向remote server發送請求

4.瀏覽器通過請求的內容執行對應動作

5.瀏覽器再把執行的動作結果通過瀏覽器驅動程序返回給測試腳本

總結

今天的文章就分享到這里了喲,喜歡的小伙伴可以點贊收藏關注評論喲。

?

總結

以上是生活随笔為你收集整理的一篇文章带你了解-selenium工作原理详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

99精品视频免费在线观看 | 一区二区中文字幕在线观看 | 精品欧美乱码久久久久久 | 久久视频这里有久久精品视频11 | 91.dizhi永久地址最新 | 成人av免费电影 | 精品久久久久免费极品大片 | 久久资源在线 | 九九日韩 | 久久久久久久久久久久电影 | 91在线一区二区 | 一区二区三区三区在线 | a级片韩国| 日韩在线观看一区二区 | 久久一区二区三区四区 | 精品一区二区三区久久 | 91免费网站在线观看 | 亚洲精品在线免费观看视频 | 一区二区三区四区精品 | 久草免费福利在线观看 | 麻豆91在线播放 | 久久夜色精品国产欧美一区麻豆 | 久久精品一区二区三区四区 | 亚洲永久精品在线观看 | 色99之美女主播在线视频 | 激情网站网址 | 日韩高清在线观看 | 日韩在线观看第一页 | 久草久草视频 | 日日夜夜狠狠 | 久久在线电影 | 中文久久精品 | 天天干,天天射,天天操,天天摸 | 天天爱综合 | 免费在线观看中文字幕 | 国产精品网红直播 | 婷婷久久一区 | 色av资源网 | 91久久在线观看 | 在线看小早川怜子av | 国产高清中文字幕 | 热九九精品 | 亚洲精品国产精品国 | 91精品999 | 国产又粗又猛又爽又黄的视频先 | 免费在线h | 精品不卡av | 狠狠狠色丁香婷婷综合久久五月 | 99这里只有精品99 | 久久久www成人免费精品张筱雨 | 免费看av在线 | 91亚洲成人 | 麻豆视频在线观看 | 五月婷久久 | 欧美一区成人 | 日日精品 | 日日插日日干 | 国产精美视频 | 99视频这里只有 | 成人免费视频在线观看 | 超碰97中文 | 亚洲国产成人高清精品 | 欧美大片在线观看一区 | 国产日韩中文在线 | 久久精品国产亚洲a | 黄色免费网站 | 最新日本中文字幕 | 婷婷开心久久网 | 黄a在线| av天天澡天天爽天天av | 成 人 黄 色 片 在线播放 | 国产亚洲精品久久久久久大师 | www.国产在线观看 | 日产乱码一二三区别免费 | 成人国产精品久久久 | 深夜成人av | 久久精品久久久久电影 | 91大神dom调教在线观看 | 在线观看完整版免费 | 国产日本在线播放 | 人人爽人人澡 | 天天天在线综合网 | 一区二区三区久久 | 91av蜜桃 | 久久成人一区二区 | 国产一区二区免费在线观看 | 在线观看国产一区二区 | 久草视频在 | 亚洲国产合集 | 久草国产视频 | 丁香花在线观看视频在线 | 色小说在线 | 久草视频在线新免费 | 91丨九色丨蝌蚪丨对白 | 成人在线视频论坛 | 国产精品成久久久久 | 不卡的av| 四川妇女搡bbbb搡bbbb搡 | 色婷婷久久久 | 444av| www色网站 | 91.麻豆视频| 日韩一二三在线 | 婷婷激情久久 | 国产福利在线免费观看 | 成人免费电影 | 国产麻豆电影在线观看 | 99热国内精品 | 亚洲在线a | 亚洲国产欧美在线人成大黄瓜 | 久久天天躁 | 天天操天天添天天吹 | 色天天综合网 | 成人av日韩 | 97超碰在线免费观看 | 天天色天天操天天爽 | 欧美日韩视频在线观看一区二区 | 国产免费观看久久黄 | 日本一区二区三区免费观看 | 亚洲久草网 | 久久不卡电影 | 伊人激情综合 | 人人爽人人乐 | 精品少妇一区二区三区在线 | 啪一啪在线 | 欧美另类高潮 | 国产精品嫩草在线 | 日韩乱码在线 | 999视频精品 | 黄色小说视频在线 | 天天久久综合 | 色黄视频免费观看 | 成人91视频| 91天天视频| 日韩精品大片 | 在线成人观看 | 久久 一区| 久久久穴 | 国产欧美日韩一区 | 国产日韩亚洲 | 91久久精品日日躁夜夜躁国产 | 久久99电影 | 美女视频免费精品 | 亚洲精品国偷拍自产在线观看蜜桃 | 天天射日 | 91精品日韩 | 日日夜夜精品网站 | 欧美激情视频一区二区三区 | 99电影 | 中国一级片视频 | 亚洲视频在线视频 | aaa亚洲精品一二三区 | 一区 在线观看 | 成人一级片在线观看 | 欧美在线视频一区二区三区 | 最新在线你懂的 | 精品中文字幕在线播放 | 国产精品专区在线 | 国产精品尤物视频 | 久艹视频在线免费观看 | 黄色一级性片 | 激情av网| 亚洲男男gⅴgay双龙 | 国产精品久久毛片 | 五月天丁香综合 | 欧美午夜精品久久久久久浪潮 | 四虎影视精品永久在线观看 | 久草在线国产 | 99久久国产免费,99久久国产免费大片 | 日本大尺码专区mv | 麻豆mv在线观看 | 97精品国产 | 亚洲三级影院 | 国产精品久久久电影 | 亚洲伊人成综合网 | 欧美国产日韩一区 | 国内成人精品2018免费看 | 国产日韩在线视频 | 欧美日韩午夜 | 欧美日韩伦理一区 | 99精品在线播放 | 国产免费不卡av | 国产精品久久中文字幕 | 国产精品毛片一区二区在线 | 人人看人人爱 | 青青草华人在线视频 | 久久综合国产伦精品免费 | 麻豆果冻剧传媒在线播放 | 日韩女同av| 亚洲一区二区观看 | 欧美日韩精品在线免费观看 | 香蕉视频国产在线观看 | 久久久国产网站 | 日韩电影一区二区在线 | av东方在线 | 99爱精品视频 | 狠狠婷婷| 欧美日本在线视频 | 欧美成人性战久久 | 九九九九色 | 天天操天天干天天综合网 | 日日爱影视| 欧美a视频 | 日韩一区二区三区在线观看 | 91成熟丰满女人少妇 | 国产原创av片 | 色综合久久五月天 | 毛片视频网址 | av高清影院| 人人插人人澡 | 二区视频在线 | 99视频网址 | 欧美日韩不卡一区 | 黄色福利视频网站 | 黄色片网站大全 | 中文字幕在线免费97 | 91人人爽人人爽人人精88v | 久久免费视频在线观看30 | 91一区在线观看 | 国产91九色蝌蚪 | 亚洲视频第一页 | 亚洲成aⅴ人片久久青草影院 | 你操综合 | 中文字幕超清在线免费 | av在线网站免费观看 | 亚洲乱码中文字幕综合 | 超碰.com| 99国产成+人+综合+亚洲 欧美 | 性色va| 欧美成人性网 | 日韩欧美久久 | 亚洲精品66| 四虎成人精品永久免费av | 国产又粗又猛又爽又黄的视频免费 | 色噜噜狠狠狠狠色综合久不 | 国产在线精品一区二区三区 | 九九久| 在线超碰av| 色多多视频在线观看 | 国产一线二线三线性视频 | 97成人精品视频在线观看 | 日韩欧美精品在线观看视频 | 五月天堂网 | 久久99久久久久久 | 久久久久久久99 | 福利网在线 | 国产a级免费 | 日韩成人不卡 | 公开超碰在线 | 五月激情视频 | 国产免费嫩草影院 | 国产黄视频在线观看 | 亚洲最大免费成人网 | 91人人在线 | 国产高清视频免费在线观看 | 中文在线a天堂 | 91精品国产综合久久久久久久 | 久久国产精品区 | a天堂一码二码专区 | 国产中文字幕大全 | 国产 成人 久久 | 欧美性生活小视频 | 国产成人久久精品一区二区三区 | 999热视频 | 亚洲四虎在线 | 91成人在线视频观看 | 国产视频一区在线播放 | 国产在线最新 | av中文字幕在线观看网站 | 欧美激情精品久久久 | 欧美亚洲国产精品久久高清浪潮 | 欧美色图亚洲图片 | 中文字幕在线一二 | 伊在线视频 | 中文字幕黄网 | 天天操天天操天天操天天操 | 国产精品手机在线 | 玖玖在线精品 | 天天插一插 | 久久人91精品久久久久久不卡 | 最新中文字幕视频 | 久久久久欠精品国产毛片国产毛生 | 日韩肉感妇bbwbbwbbw | 欧美在线视频免费 | 91丨九色丨蝌蚪丰满 | av 一区二区三区四区 | 久久福利 | 九九久久久久久久久激情 | 91看国产| 国产精品久久久久久久久久久久午 | 天天干天天色2020 | 六月丁香婷婷久久 | 日日天天狠狠 | 中文永久免费观看 | 国产免费区 | 日韩欧美一区二区三区在线观看 | 亚洲三区在线 | 一级黄毛片 | 最新日韩在线观看视频 | 中文字幕第一页在线视频 | 国产精品久久网站 | 久久久久久蜜桃一区二区 | 高潮久久久 | 免费美女久久99 | 国产精品九九九九九 | 国产又粗又猛又黄又爽 | 99精品免费网 | 免费a网| 超级碰99| av网站在线免费观看 | 国产精品福利在线观看 | 亚州av成人 | 久草| 伊人射| 精品国产成人在线影院 | 日韩色视频在线观看 | 色综合www | 九九久久久久久久久激情 | 久久综合久色欧美综合狠狠 | 午夜国产一区二区三区四区 | 日日夜夜精品视频天天综合网 | 日韩av午夜在线观看 | 91丨精品丨蝌蚪丨白丝jk | 最新国产精品拍自在线播放 | 在线视频精品播放 | 亚洲欧美日韩精品久久奇米一区 | 国产高清视频在线 | 热99在线 | 中文有码在线视频 | 狠狠五月婷婷 | 亚洲视频久久久久 | av中文字幕电影 | 色婷婷激情综合 | 日本久久久影视 | 超碰99在线 | japanesefreesex中国少妇 | 一级电影免费在线观看 | 热久久最新地址 | 久久96国产精品久久99软件 | 波多野结衣电影久久 | 美女视频网站久久 | 成人av高清在线观看 | 精品视频在线播放 | 国产精品18久久久久久首页狼 | 黄色av高清| 91热爆视频| 黄色一及电影 | 久久国产精品色av免费看 | 久久久久久国产精品999 | 色黄www小说 | 国产免费二区 | 亚洲欧洲精品在线 | 91在线影视| 国产视频在线免费 | 久久99亚洲精品久久 | 国产美女精品视频免费观看 | 香蕉视频在线播放 | 国产96视频 | 91精品视频观看 | 国产美女免费看 | www欧美xxxx| www.五月婷婷.com | 麻豆果冻剧传媒在线播放 | 天天综合久久 | 精品一区二区亚洲 | 在线电影 一区 | 中文字幕精品一区二区精品 | 婷婷丁香久久五月婷婷 | 国产日韩欧美在线免费观看 | 亚洲日本一区二区在线 | 五月天综合在线 | 伊人五月天.com | 亚洲动漫在线观看 | 丰满少妇高潮在线观看 | 激情欧美日韩一区二区 | 国产美女视频 | 99久久精品免费看国产一区二区三区 | 婷婷色伊人 | 久久在草 | 91福利在线导航 | 天天综合网天天综合色 | 免费视频区 | 66av99精品福利视频在线 | 国产精品自在线拍国产 | 成人黄色电影免费观看 | 中文字幕在线一区二区三区 | 在线观看91av| 天天摸夜夜添 | 99精品在线视频观看 | 天天色 天天 | 欧美综合在线视频 | 免费黄色网址网站 | 国产午夜精品久久 | 一区二区三区在线免费播放 | 18性欧美xxxⅹ性满足 | 国产黄色片久久久 | 国产精品毛片一区视频 | 中文字幕av网站 | 国产高清久久 | 国产一区二区高清视频 | 亚洲精品乱码久久久久v最新版 | 青草视频网 | 欧美日韩性 | 日韩欧美一区二区在线观看 | 欧美aaa级片 | 2024国产精品视频 | 深夜成人av | 成人一级| 国产精品99久久久久人中文网介绍 | 日韩av进入 | 日韩在线视频一区二区三区 | 精品久久一区二区三区 | 日本久久高清视频 | 日韩高清免费在线 | 四虎影视成人精品国库在线观看 | 亚洲国产精品视频 | 亚洲视频h | 国内精品久久影院 | 久久精品视频网 | 国产一二区免费视频 | 91最新在线 | 人人藻人人澡人人爽 | 亚洲美女免费精品视频在线观看 | 中文字幕日韩国产 | 色中色资源站 | 国产视频精选 | 国产原创av在线 | 91在线产啪| 最近乱久中文字幕 | a精品视频| 国产精品手机在线播放 | 日韩在线二区 | 久久精品亚洲 | 亚洲免费av片 | 欧美国产精品久久久久久免费 | 欧美另类xxx | 久久久久久久综合色一本 | 久久久久久毛片精品免费不卡 | 久久不卡日韩美女 | 成年人免费观看在线视频 | 欧美一区二区日韩一区二区 | 免费观看成人av | www.夜夜操 | 成人18视频| 国内精品在线观看视频 | 黄色av免费看 | 婷婷久久一区 | 久久免费片 | 成人久久国产 | 欧美日韩三级在线观看 | 日韩精选在线观看 | 午夜久久久久久久久久久 | 伊人久久国产 | 91女子私密保健养生少妇 | 久久久国产一区 | 日韩视频在线一区 | 99色人| 国内精品久久久久久久久久 | 日日干日日色 | 国产一级片久久 | 中文字幕亚洲精品在线观看 | 99视屏| 国产精品精品久久久久久 | 久久精品一区 | 婷婷精品国产欧美精品亚洲人人爽 | 亚洲精品久久久久久久不卡四虎 | 欧美精品久久久久久久久免 | 欧美日韩一区久久 | 在线看国产视频 | 久久情网| 国产精品色婷婷视频 | 中文区中文字幕免费看 | 五月婷婷丁香网 | 国产成人久久精品一区二区三区 | 久久精品视| 国产精品久久久久婷婷 | 亚洲天天综合 | 欧美性天天 | 久久国内精品视频 | 亚洲精品自拍视频在线观看 | 97视频免费在线观看 | 欧美日韩精品在线观看视频 | 国产在线免费观看 | 日韩a在线| 久久a免费视频 | 免费欧美| 国产三级精品三级在线观看 | 国产九九热 | 在线观看精品国产 | 亚洲国产精品va在线看黑人 | 五月开心婷婷网 | 久草线| 国产成人三级在线 | 欧美日韩高清一区 | 狠狠干婷婷色 | 日韩欧美一区二区三区在线观看 | 亚州黄色一级 | 久久免费成人精品视频 | 99精品99| 欧美激情视频一二三区 | 久久综合九色综合久久久精品综合 | 精品你懂的 | 久久中文字幕在线视频 | 日韩av中文字幕在线 | 五月天天色 | 91成熟丰满女人少妇 | 国产黑丝一区二区 | 国产自制av| 麻豆视频国产 | 日韩a级黄色片 | 在线观看黄网 | 国产精品一区二区三区四 | 亚洲午夜精品一区二区三区电影院 | 国产69精品久久app免费版 | 在线观看av片 | 四虎5151久久欧美毛片 | 国产网站在线免费观看 | 在线看国产视频 | 中文字幕在线观看第三页 | 麻豆传媒视频在线免费观看 | www日韩精品| 91视频久久久久 | 91久久在线观看 | 欧美精品国产综合久久 | 国产69精品久久app免费版 | 国产欧美精品xxxx另类 | 国产精品一二三 | 久久精品爱爱视频 | 中文字幕在线观看完整 | 91午夜精品 | 欧美一级片免费在线观看 | av网址最新| 99久久99视频只有精品 | 99自拍视频在线观看 | 亚洲粉嫩av | 91.麻豆视频 | 久久久久这里只有精品 | 黄色一集片 | 亚洲丁香日韩 | 国产精品麻豆免费版 | 久久开心激情 | 久久视频一区二区 | 日韩在线视频二区 | 亚洲综合少妇 | 日韩中文字幕在线 | 亚洲波多野结衣 | 久草在线资源观看 | 最近最新最好看中文视频 | 免费在线一区二区 | 久久夜靖品 | 992tv成人免费看片 | 香蕉久草在线 | 黄色免费看片网站 | 欧美激情xxxx性bbbb | 久久精品人人做人人综合老师 | 激情丁香月 | 久久99久| 久久高清免费视频 | 国产精品久久久久久久免费大片 | 伊人在线视频 | 四虎在线观看网址 | 国产夫妻自拍av | 久久久精品一区二区 | 狠狠干.com | 免费视频区 | 97人人澡人人添人人爽超碰 | 日韩有码网站 | 久色网| 欧美精品国产综合久久 | 国产亚洲精品免费 | 欧美十八 | 日韩综合视频在线观看 | 中文字幕二区三区 | 99免费在线视频 | 成人av亚洲 | 久久综合天天 | 久久亚洲人 | 日本中文字幕视频 | 亚洲精品久久在线 | 国产精品黄色 | 美女福利视频在线 | 婷婷五月在线视频 | 久久久久久久久久久精 | 久99久精品| 三级视频片 | 久久久久久久久久影视 | 亚洲一级黄色片 | 人九九精品 | 国产中文欧美日韩在线 | 在线观看中文av | 久久人人射 | 久久久久亚洲精品国产 | 麻豆成人精品 | 久久狠狠一本精品综合网 | 一区二区三区在线播放 | 国产免费一区二区三区最新6 | 国产成人黄色在线 | 区一区二区三在线观看 | 国产又粗又猛又色 | 在线观看免费日韩 | 日韩av片免费在线观看 | 一本一本久久a久久 | 国产一级免费av | 日本久久不卡视频 | 日本最新高清不卡中文字幕 | 天天干天天天天 | 成人网444ppp | 国产一级不卡视频 | 伊人永久在线 | 天天干天天做天天操 | 手机在线小视频 | 成人精品视频 | 热九九精品| 在线中文字幕视频 | 伊人干综合 | 亚洲精品在线二区 | 91黄视频在线 | av高清一区 | 日韩黄色影院 | 91超在线 | 青青五月天 | 在线观看黄色av | 亚洲一区网站 | 91视频在线观看免费 | 欧美久久综合 | 六月丁香社区 | 亚洲精品中文字幕在线观看 | 天天操天天操天天 | 欧美国产高清 | 在线观看岛国av | 青青草在久久免费久久免费 | 国产资源免费在线观看 | 亚洲欧美日韩不卡 | 欧美激情精品久久久久 | 欧美三级高清 | 韩国精品一区二区三区六区色诱 | 国产精品一区二区久久国产 | 91丨九色丨国产在线观看 | 五月激情丁香图片 | 一区二区三区三区在线 | 91豆麻精品91久久久久久 | 久久久久高清毛片一级 | 97精品国产aⅴ | 在线观看涩涩 | 狠狠久久 | 日韩a在线观看 | 国产高清在线 | 亚洲资源在线网 | 久久福利影视 | 在线成人免费电影 | 人人澡人摸人人添学生av | 日狠狠 | 日本精品免费看 | 在线免费观看欧美日韩 | 日韩欧美国产免费播放 | 久久黄色网页 | .国产精品成人自产拍在线观看6 | 欧美日韩二区在线 | av不卡中文 | 久久狠狠一本精品综合网 | 国产亚洲免费观看 | 国产不卡在线视频 | av看片网址 | 性日韩欧美在线视频 | www.在线观看av | 精品1区二区 | 亚洲少妇xxxx | 日韩三级一区 | 亚洲午夜久久久久久久久电影网 | 午夜精品一区二区三区视频免费看 | 日韩av成人免费看 | 2021国产精品视频 | 日韩高清在线一区 | 日韩在线观看第一页 | 亚洲成av人片在线观看 | 亚洲无人区小视频 | 色视频国产直接看 | 在线免费亚洲 | 欧美一区二区三区激情视频 | 国产亚州av | 成人黄色片免费看 | 五月婷婷综合在线观看 | 91麻豆精品久久久久久 | 97精品超碰一区二区三区 | 97视频网站 | 91一区啪爱嗯打偷拍欧美 | 五月婷婷欧美视频 | 亚洲精品在线观看中文字幕 | 黄色毛片视频 | 色a在线观看 | 最新一区二区三区 | 91高清免费| 欧美在线free | 天天综合亚洲 | av免费黄色 | 欧美aⅴ在线观看 | 久久精品视频5 | 91大神精品视频在线观看 | av+在线播放在线播放 | 国产一区在线观看视频 | 在线v | 成人羞羞视频在线观看免费 | 成人国产精品久久久久久亚洲 | 人人精品久久 | 国产自偷自拍 | 97在线成人 | 99视频在线免费观看 | 久久久久婷 | 天天插天天干 | 片网址| 奇米影视999 | 五月婷婷,六月丁香 | 国产理论一区二区三区 | 黄色录像av | 国产一级片观看 | 97成人精品区在线播放 | 久久人人97超碰com | 亚洲欧美视频网站 | 久久视| 91视频久久久久 | 久久久久久久久久久免费视频 | 国产亚洲一区二区在线观看 | 国产精品久久久久久久久久久久午夜 | 成片免费观看视频 | 久久久久成人精品免费播放动漫 | 一区二区三区视频网站 | 国产又黄又猛又粗 | 最新av网站在线观看 | 99视频国产精品 | 欧美综合在线视频 | 国产一区高清在线 | 精品久久久免费视频 | 久久久私人影院 | 91麻豆精品| 午夜.dj高清免费观看视频 | 国产精品欧美日韩 | 中文字幕丰满人伦在线 | 国产精品久久久久久久免费大片 | 久久精品免费看 | 狠狠成人 | 国产精品久久av | 日韩午夜精品 | www日韩欧美| 国产亲近乱来精品 | 黄色网免费 | 国产馆在线播放 | 久久久久久综合网天天 | 国产一级黄 | 精品国产一区二区三区久久久久久 | 狠狠色噜噜狠狠狠狠 | 天天色天天艹 | 国产成人精品a | 日韩精品无码一区二区三区 | 国产精品美女视频网站 | 亚洲日本va在线观看 | 亚洲 欧美 另类人妖 | 亚洲激情精品 | 国产精品免费看久久久8精臀av | 中文字幕一区二区三区在线视频 | 日韩av资源在线观看 | 日本精品视频在线播放 | 97色国产 | 日产av在线播放 | 亚洲精品国产精品国自 | 日韩欧美精选 | 高清有码中文字幕 | 81精品国产乱码久久久久久 | 91av免费在线观看 | 成人午夜毛片 | a天堂最新版中文在线地址 久久99久久精品国产 | aaa日本高清在线播放免费观看 | 久草视频在线资源 | 国产精品免费久久久久 | 久久久久高清毛片一级 | 国产一区二区在线免费播放 | 日日操天天操狠狠操 | 国产精品永久 | 99精品99| 天堂网一区 | 日韩一区正在播放 | 天天操夜操 | 亚洲 综合 国产 精品 | 国产精品久久久久高潮 | 欧美成人精品三级在线观看播放 | 日韩欧美在线不卡 | 国产黄色视| 国产小视频在线免费观看视频 | 亚洲精品午夜aaa久久久 | 欧美精品日韩 | 黄色免费在线看 | 成人午夜电影久久影院 | 国产一级免费观看视频 | 在线欧美a | 国产福利91精品张津瑜 | 极品久久久 | 中文字幕日韩在线播放 | 亚洲 欧美 日韩 综合 | 99热国产精品 | 91高清完整版在线观看 | 久草在线视频中文 | 99精品系列 | 久久免费视频在线观看 | 日韩av在线资源 | 久久影院精品 | 99热这里只有精品1 av中文字幕日韩 | 亚洲自拍偷拍色图 | 亚洲成人免费在线观看 | 色香蕉在线视频 | 成人av资源在线 | 亚洲好视频 | 久久久精品久久日韩一区综合 | 亚洲国产精彩中文乱码av | 99精品视频免费观看视频 | 狠狠狠的干 | 久久精品看片 | 在线成人国产 | 免费看的av片 | 日日操夜夜操狠狠操 | 免费看一级特黄a大片 | ww视频在线观看 | 美女国内精品自产拍在线播放 | 午夜成人影视 | 免费观看第二部31集 | 五月天久久狠狠 | 五月天堂色 | 91中文字幕在线观看 | 亚洲日本中文字幕在线观看 | 亚洲精品中文字幕视频 | 97超碰在线免费 | 涩涩网站在线播放 | 人人插人人艹 | 国产午夜精品福利视频 | 国产高清视频网 | www看片网站| 久久97久久 | 亚洲手机天堂 | 在线观看电影av | 尤物九九久久国产精品的分类 | 欧美日韩免费在线观看视频 | 国产精品久久久久久婷婷天堂 | 免费中文字幕 | 四虎成人精品永久免费av九九 | aaa日本高清在线播放免费观看 | 免费中文字幕 | 色综合色综合色综合 | 久久亚洲欧美日韩精品专区 | 日批视频国产 | 久久观看最新视频 | 91成年人视频 | 伊人在线视频 | 丁香午夜 | 欧美成人在线网站 | 四虎影视精品永久在线观看 | 国产精品一区二区三区观看 | 免费观看性生交 | 欧美一区在线观看视频 | 久久亚洲精品电影 | a√天堂资源 | 国产精品99爱 | 九九视频在线播放 | 手机成人在线 | 高清视频一区二区三区 | 国产精品免费久久久久久久久久中文 | 丁香六月五月婷婷 | 日韩视频一区二区在线 | av久久久| 奇米影视8888在线观看大全免费 | 国产精品伦一区二区三区视频 | 在线视频一区观看 | 亚洲免费婷婷 | 欧美亚洲久久 | 免费成人在线网站 | 欧美国产日韩一区 | 亚洲视频免费 | 色综合天天| 国产精品正在播放 | 18+视频网站链接 | 国产一区播放 | 一区二区三区四区五区六区 | 免费高清在线视频一区· | 91porny九色在线播放 | 久久久久久久久久久影院 | 深爱开心激情 | 人人爽人人爽人人爽学生一级 | 99爱精品视频 | 日本中文字幕在线免费观看 | 日韩欧美国产视频 | 久草新在线 | 日日日视频 | 欧美色综合天天久久综合精品 | 高清av中文字幕 | 国产91综合一区在线观看 | 成人动漫一区二区 | 91成版人在线观看入口 | 国产精品久久久久久久久毛片 | 精品高清视频 | 99国内精品久久久久久久 | 一级黄色片在线免费看 | 黄色av免费 | 亚洲精品在线观看视频 | se视频网址| 亚洲91中文字幕无线码三区 | 手机成人免费视频 | 夜夜骑日日 | 国产黄色播放 | 日本成人中文字幕在线观看 | 国产精品自产拍在线观看桃花 | 国产麻豆精品一区二区 | 欧美性久久久久久 | av中文天堂在线 | 免费欧美高清视频 | 人人艹人人 | 91在线资源 | 精品久久久久国产免费第一页 | 精品国模一区二区三区 | 激情婷婷亚洲 | 国产91区 | 婷婷精品在线 | 亚洲一区精品二人人爽久久 | 日韩大片在线看 | 99se视频在线观看 | jizz999| 久久看毛片 | 99视频精品 | 亚洲高清在线 | 91av免费看 | 欧美极品裸体 | 日韩在线观看的 | 中文字幕在线影院 | 成人在线视频网 | 93久久精品日日躁夜夜躁欧美 | 免费观看的黄色 | 色全色在线资源网 | 黄色小说在线免费观看 | 天天操天天干天天插 | 亚洲精品一区二区网址 | 久久草网| 国产99久久久久久免费看 | 一区二区三区四区不卡 | 青草视频在线 | 国产视频久久久 | 麻豆视频免费在线播放 | 91cn国产在线 | 日韩在线播放av | 久久久99国产精品免费 | 亚洲精品影院在线观看 | 黄p网站在线观看 | 在线一二三四区 | 国产久草在线观看 | 中国精品少妇 | 一区二区影院 | 久久久久中文 | 91成人破解版 | 久久久久久高潮国产精品视 | 国产精品一区二区精品视频免费看 | 国产在线第三页 | 成人av影视 | .精品久久久麻豆国产精品 亚洲va欧美 | 在线精品一区二区 | 亚洲成人影音 | 久久综合干 | 91看片看淫黄大片 | 在线免费观看视频一区二区三区 | 99精品国产亚洲 | 久久99国产精品免费 | 久久三级视频 | 日韩在线观看一区二区三区 | 中文字幕视频网站 | 国内精品久久久久久久影视麻豆 | 国产视频在线免费观看 | 婷婷中文字幕 | 91精品视频免费观看 | 久久精品三 | 国产人成精品一区二区三 | 在线观看黄网 | 在线视频 影院 | 精品人人人人 | 人人草在线视频 | 亚洲精品短视频 | 91人网站 | 天天射天天 | 久久综合亚洲鲁鲁五月久久 | 国产一区二区在线看 | 一区二区中文字幕在线观看 | 日本精品视频一区二区 | 免费视频久久久 | 日韩中文字幕在线看 | 亚州国产精品视频 | 91精品视频免费看 | 麻豆精品91 | 亚洲女同videos | 超碰在线人人艹 | 日韩欧美一区二区在线观看 | 国产精品99久久免费观看 | www.久久99 | 久久www免费人成看片高清 | 黄色小网站在线观看 | 亚洲国产精品电影 |