国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一篇文章帶你了解-selenium工作原理詳解

這篇具有很好參考價(jià)值的文章主要介紹了一篇文章帶你了解-selenium工作原理詳解。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

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

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

測(cè)試系統(tǒng)功能——?jiǎng)?chuàng)建回歸測(cè)試檢驗(yàn)軟件功能和用戶(hù)需求。支持自動(dòng)錄制動(dòng)作和自動(dòng)生成 .Net、Java、Perl等不同語(yǔ)言的測(cè)試腳本(這里主要是針對(duì)selenium ide)
一篇文章帶你了解-selenium工作原理詳解,技術(shù)分享,軟件測(cè)試,自動(dòng)化測(cè)試,selenium,測(cè)試工具,自動(dòng)化測(cè)試

一、selenium歷程
04年,誕生了Selenium Core,Selenium Core是基于瀏覽器并且采用JavaScript編程語(yǔ)言的測(cè)試工具,運(yùn)行在瀏覽器的安全沙箱中,設(shè)計(jì)理念是將待測(cè)試產(chǎn)品、Selenium Core和測(cè)試腳本均部署到同一臺(tái)服務(wù)器上來(lái)完成自動(dòng)化測(cè)試的工作。

05年,Selenium RC誕生,就是selenium1 ,這個(gè)時(shí)候,Selenium Core其實(shí)是Selenium RC的核心。

Selenium RC讓待測(cè)試產(chǎn)品、Selenium Core和測(cè)試腳本三者分散在不同的服務(wù)器上。(測(cè)試腳本只關(guān)心將HTTP請(qǐng)求發(fā)送到指定的URL上,selenium本身不需要關(guān)心HTTP請(qǐng)求由于什么程序編程語(yǔ)言編寫(xiě)而成)

Selenium RC包括兩部分:一個(gè)是Selenium RC Server,一個(gè)是提供各種編程語(yǔ)言的客戶(hù)端驅(qū)動(dòng)來(lái)編寫(xiě)測(cè)試腳本

07年,Webdriver誕生,WebDriver的設(shè)計(jì)理念是將端到端測(cè)試與底層具體的測(cè)試工具分隔離,并采用設(shè)計(jì)模式Adapter適配器來(lái)達(dá)到目標(biāo)。WebDriver的API組織更多的是面向?qū)ο蟆?/p>

08/09年,selenium2誕生,selenium2其實(shí)是selenium rc和webdriver的合并,合并的根本原因是相互補(bǔ)充各自的缺點(diǎn)

09年,selenium3誕生,這個(gè)版本剔除了selenium rc , 主要由 selenium webdriver和selenium Grid組成, 我們?nèi)粘J褂玫钠鋵?shí)就是selenium webdriver,至于selenium grid是一個(gè)分布式實(shí)現(xiàn)自動(dòng)化測(cè)試的工具

那么今天我們就要說(shuō)說(shuō)selenium3(selenium webdriver)的工作原理,下面簡(jiǎn)稱(chēng)selenium(以上具體時(shí)間可能不太準(zhǔn)確,我也是通過(guò)網(wǎng)絡(luò)資料了解到的,拋磚引玉^-^)

二、selenium原理
我們使用Selenium實(shí)現(xiàn)自動(dòng)化測(cè)試,主要需要3個(gè)東西

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

2.瀏覽器驅(qū)動(dòng), 這個(gè)驅(qū)動(dòng)是根據(jù)不同的瀏覽器開(kāi)發(fā)的,不同的瀏覽器使用不同的webdriver驅(qū)動(dòng)程序且需要對(duì)應(yīng)相應(yīng)的瀏覽器版本,比如:geckodriver.exe(chrome)

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

三、selenium腳本
先看一個(gè)簡(jiǎn)單的代碼

"""
from selenium import webdriver
dr = webdriver.Chrome()  # 打開(kāi)瀏覽器

執(zhí)行上述代碼,我們會(huì)發(fā)現(xiàn)程序打開(kāi)了Chrome瀏覽器(前提:你已經(jīng)正確配置了chrome的驅(qū)動(dòng)和對(duì)應(yīng)版本)

那么selenium是如何實(shí)現(xiàn)這個(gè)過(guò)程的呢?ok,我們今天就通過(guò)分析源碼的方式來(lái)理解selenium的工作原理

四、源碼分析
查看weddriver源碼(按住Ctrl鍵,鼠標(biāo)點(diǎn)擊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

通過(guò)源碼中的44-49行發(fā)現(xiàn),初始化了一個(gè)service對(duì)象,然后調(diào)用了start()方法,那么我們繼續(xù)看下一49行的start()方法到底實(shí)現(xiàn)了什么功能?

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)

我們發(fā)現(xiàn)9-16行其實(shí)就是執(zhí)行了一個(gè)cmd命令,命令的作用就是啟動(dòng)了chromedriver.exeChrome瀏覽器的驅(qū)動(dòng)程序

這里我們需要注意一點(diǎn): 下載的瀏覽器驅(qū)動(dòng)一定要配置到環(huán)境變量中,或者放到python的根目錄下,便于程序在執(zhí)行驅(qū)動(dòng)的時(shí)候查找

這個(gè)過(guò)程和我們手動(dòng)啟動(dòng)瀏覽器驅(qū)動(dòng)是一樣的效果,類(lèi)似下面的結(jié)果
一篇文章帶你了解-selenium工作原理詳解,技術(shù)分享,軟件測(cè)試,自動(dòng)化測(cè)試,selenium,測(cè)試工具,自動(dòng)化測(cè)試

啟動(dòng)驅(qū)動(dòng)程序后,綁定端口號(hào)9515,且只允許本地訪(fǎng)問(wèn)這個(gè)服務(wù),其實(shí)我們可以查看一下我們本地電腦任務(wù)管理器,確實(shí)開(kāi)啟了一個(gè)服務(wù)進(jìn)程程序

第一步工作我們已經(jīng)知道了執(zhí)行測(cè)試腳本webdriver.Chrome()會(huì)自動(dòng)執(zhí)行chromedriver.exe驅(qū)動(dòng)程序,然后開(kāi)啟一個(gè)進(jìn)程

五、如何打開(kāi)瀏覽器
我們繼續(xù)看源碼 C:\Python36\Lib\site-packages\selenium\webdriver\chrome\webdriver.py 的51-57行代碼,調(diào)用了父類(lèi)RemoteWebDriver 的初始化方法,我們看這個(gè)方法做了什么事?

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

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

 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

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

ok,打開(kāi)瀏覽器的操作完成了

六、如何執(zhí)行對(duì)應(yīng)操作
查看C:\Python36\Lib\site-packages\selenium\webdriver\chrome\webdriver.py源碼(第一個(gè)源碼中的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)

點(diǎn)擊ChromeRemoteConnection查看一下源碼

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

第7行訪(fǎng)問(wèn)的是localhost:9515/session地址,第8-11行,定義了一些和我們使用的瀏覽器(chrome)特有的接口地址,我們?cè)倏匆幌赂割?lèi)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         }

這個(gè)類(lèi)里面定義了所有的selenium操作需要的接口地址(這些接口地址全部封裝在瀏覽器驅(qū)動(dòng)程序中),那么所有的瀏覽器操作就是通過(guò)訪(fǎng)問(wèn)這些接口來(lái)實(shí)現(xiàn)的

其中 Command.GET: ('POST', '/session/$sessionId/url') 這個(gè)地址就是實(shí)現(xiàn)訪(fǎng)問(wèn)一個(gè)網(wǎng)址的url ,我們先記錄一下后面有用

ok,所有的操作對(duì)應(yīng)接口地址我們知道了,那么又怎樣執(zhí)行這些接口來(lái)達(dá)到在瀏覽器上實(shí)現(xiàn)各種操作呢?繼續(xù)看緊接著接口地址定義下面的源碼

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

可以看到主要是通過(guò)execute方法調(diào)用_request方法通過(guò)urilib3標(biāo)準(zhǔn)庫(kù)向服務(wù)器發(fā)送對(duì)應(yīng)操作請(qǐng)求地址,進(jìn)而實(shí)現(xiàn)了瀏覽器各種操作

有人會(huì)問(wèn)打開(kāi)瀏覽器和操作瀏覽器實(shí)現(xiàn)各種動(dòng)作是怎么關(guān)聯(lián)的呢?

其實(shí),打開(kāi)瀏覽器也是發(fā)送請(qǐng)求,請(qǐng)求會(huì)返回一個(gè)sessionid,后面操作的各種接口地址,你也會(huì)發(fā)現(xiàn)接口地址中存在一個(gè)變量$sessionid,那么不難猜測(cè)打開(kāi)瀏覽器和操作瀏覽器就是用過(guò)sessionid關(guān)聯(lián)到一起,達(dá)到在同一個(gè)瀏覽器中做操作

第二步在瀏覽其上實(shí)現(xiàn)各種操作原理也完成了

七、模擬selenium
現(xiàn)在我們可以通過(guò)下面的一段代碼查看一下打開(kāi)瀏覽器和訪(fǎng)問(wèn)我的博客首頁(yè)的請(qǐng)求參數(shù)是什么樣子的

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

輸出日志信息

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

通過(guò)執(zhí)行結(jié)果就很明顯明白selenium執(zhí)行的過(guò)程了,程序告訴RemoteWebDriver打開(kāi)一個(gè)瀏覽器(發(fā)送post請(qǐng)求,帶上請(qǐng)求參數(shù)),然后再向remote server發(fā)送執(zhí)行瀏覽器動(dòng)作的請(qǐng)求

那么為了更加深入理解selenium實(shí)現(xiàn)自動(dòng)化測(cè)試的過(guò)程,我們可以自己編寫(xiě)程序模擬一下打開(kāi)瀏覽器然后控制瀏覽器訪(fǎng)問(wèn)我的博客地址的操作過(guò)程

首先我們需要保持瀏覽器的驅(qū)動(dòng)程序打開(kāi)狀態(tài),然后編寫(xiě)如下代碼并執(zhí)行

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

執(zhí)行結(jié)果

{'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',從代碼中你也可以看到訪(fǎng)問(wèn)我的博客地址的url是使用這個(gè)參數(shù)拼接的,因?yàn)榇蜷_(kāi)瀏覽器后,后面所有的操作都是基于這個(gè)sessionid的

你還會(huì)看到Chrome瀏覽器被打開(kāi),且打開(kāi)了我的博客地址https://www.cnblogs.com/linuxchao/,這就是selenium原理的一個(gè)過(guò)程了

八、最后
前面的代碼你看不懂,也沒(méi)關(guān)系,我們?cè)賮?lái)敘述一下selenium工作的過(guò)程

1.selenium client(python等語(yǔ)言編寫(xiě)的自動(dòng)化測(cè)試腳本)初始化一個(gè)service服務(wù),通過(guò)Webdriver啟動(dòng)瀏覽器驅(qū)動(dòng)程序chromedriver.exe

2.通過(guò)RemoteWebDriver向?yàn)g覽器驅(qū)動(dòng)程序發(fā)送HTTP請(qǐng)求,瀏覽器驅(qū)動(dòng)程序解析請(qǐng)求,打開(kāi)瀏覽器,并獲得sessionid,如果再次對(duì)瀏覽器操作需攜帶此id

3.打開(kāi)瀏覽器,綁定特定的端口,把啟動(dòng)后的瀏覽器作為webdriver的remote server

3.打開(kāi)瀏覽器后,所有的selenium的操作(訪(fǎng)問(wèn)地址,查找元素等)均通過(guò)RemoteConnection鏈接到remote server,然后使用execute方法調(diào)用_request方法通過(guò)urlib3向remote server發(fā)送請(qǐng)求

4.瀏覽器通過(guò)請(qǐng)求的內(nèi)容執(zhí)行對(duì)應(yīng)動(dòng)作

5.瀏覽器再把執(zhí)行的動(dòng)作結(jié)果通過(guò)瀏覽器驅(qū)動(dòng)程序返回給測(cè)試腳本

總結(jié)

最后感謝每一個(gè)認(rèn)真閱讀我文章的人,禮尚往來(lái)總是要有的,雖然不是什么很值錢(qián)的東西,如果你用得到的話(huà)可以直接拿走:

一篇文章帶你了解-selenium工作原理詳解,技術(shù)分享,軟件測(cè)試,自動(dòng)化測(cè)試,selenium,測(cè)試工具,自動(dòng)化測(cè)試

這些資料,對(duì)于【軟件測(cè)試】的朋友來(lái)說(shuō)應(yīng)該是最全面最完整的備戰(zhàn)倉(cāng)庫(kù),這個(gè)倉(cāng)庫(kù)也陪伴上萬(wàn)個(gè)測(cè)試工程師們走過(guò)最艱難的路程,希望也能幫助到你!有需要的小伙伴可以點(diǎn)擊下方小卡片領(lǐng)取????文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-691070.html

到了這里,關(guān)于一篇文章帶你了解-selenium工作原理詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【C++】一篇文章帶你深入了解list

    【C++】一篇文章帶你深入了解list

    list是可以在常數(shù)范圍內(nèi)在任意位置進(jìn)行插入和刪除的序列式容器,并且該容器可以前后雙向迭代。 list的底層是雙向鏈表結(jié)構(gòu),雙向鏈表中每個(gè)元素存儲(chǔ)在互不相關(guān)的獨(dú)立節(jié)點(diǎn)中,在節(jié)點(diǎn)中通過(guò)指針指向其前一個(gè)元素和后一個(gè)元素。 list與forward_list非常相似:最主要的不同在

    2024年04月23日
    瀏覽(30)
  • 一篇文章帶你詳細(xì)了解axios的封裝

    一篇文章帶你詳細(xì)了解axios的封裝

    對(duì)請(qǐng)求的封裝在實(shí)際項(xiàng)目中是十分必要的,它可以讓我們統(tǒng)一處理 http 請(qǐng)求。比如做一些攔截,處理一些錯(cuò)誤等。本篇文章將詳細(xì)介紹如何封裝 axios 請(qǐng)求,具體實(shí)現(xiàn)的功能如下 基本配置 配置默認(rèn)請(qǐng)求地址,超時(shí)等 請(qǐng)求攔截 攔截 request 請(qǐng)求,處理一些發(fā)送請(qǐng)求之前做的處理,譬如給

    2024年02月07日
    瀏覽(30)
  • 【C++】一篇文章帶你深入了解string

    【C++】一篇文章帶你深入了解string

    C語(yǔ)言中,字符串是以’\\0’結(jié)尾的一些字符的集合,為了操作方便,C標(biāo)準(zhǔn)庫(kù)中提供了一些str系列的庫(kù)函數(shù),但是這些庫(kù)函數(shù)與字符串是分離開(kāi)的,不太符合OOP的思想,而且底層空間需要用戶(hù)自己管理,稍不留神可能還會(huì)越界訪(fǎng)問(wèn)。 string的文檔介紹 字符串是表示字符序列的類(lèi)

    2024年04月08日
    瀏覽(27)
  • 【C++】一篇文章帶你深入了解vector

    【C++】一篇文章帶你深入了解vector

    vector的文檔介紹 vector是表示可變大小數(shù)組的序列容器。 就像數(shù)組一樣,vector也采用的連續(xù)存儲(chǔ)空間來(lái)存儲(chǔ)元素。也就是意味著可以采用下標(biāo)對(duì)vector的元素進(jìn)行訪(fǎng)問(wèn),和數(shù)組一樣高效。但是又不像數(shù)組,它的大小是可以動(dòng)態(tài)改變的,而且它的大小會(huì)被容器自動(dòng)處理。 本質(zhì)講,

    2024年04月22日
    瀏覽(36)
  • 一篇文章帶你了解 什么是u(ustd)帶你了解他的前世今生

    一篇文章帶你了解 什么是u(ustd)帶你了解他的前世今生

    在數(shù)字貨幣的繁榮世界中,USDT無(wú)疑是其中一位重要的角色。它的前世今生,是一個(gè)從無(wú)到有,從小到大,經(jīng)歷了種種波折和爭(zhēng)議的故事。 2014年11月下旬,一個(gè)名為Realcoin的注冊(cè)地為馬恩島和香港的公司決定改變自己的名字,取名為T(mén)ether。這個(gè)決定預(yù)示著一種新的數(shù)字貨幣即將

    2024年01月23日
    瀏覽(23)
  • WAF是什么?一篇文章帶你全面了解WAF

    Web應(yīng)用程序防火墻(Web Application Firewall,WAF)是一種用于保護(hù)Web應(yīng)用程序的安全設(shè)備。Web應(yīng)用程序是指通過(guò)Web瀏覽器或其他Web客戶(hù)端訪(fǎng)問(wèn)的應(yīng)用程序。WAF的目的是保護(hù)Web應(yīng)用程序免受黑客、網(wǎng)絡(luò)攻擊和數(shù)據(jù)泄漏等安全威脅的攻擊。 在這篇文章中,我們將深入探討WAF的工作原理

    2024年02月10日
    瀏覽(23)
  • 【網(wǎng)絡(luò)安全】一篇文章帶你了解CTF那些事兒

    【網(wǎng)絡(luò)安全】一篇文章帶你了解CTF那些事兒

    CTF(Capture The Flag)中文一般譯作奪旗賽,在網(wǎng)絡(luò)安全領(lǐng)域中指的是網(wǎng)絡(luò)安全技術(shù)人員之間進(jìn)行技術(shù)競(jìng)技的一種比賽形式。CTF起源于1996年DEFCON全球黑客大會(huì),以代替之前黑客們通過(guò)互相發(fā)起真實(shí)攻擊進(jìn)行技術(shù)比拼的方式。已經(jīng)成為全球范圍網(wǎng)絡(luò)安全圈流行的競(jìng)賽形式,2013年全

    2024年02月08日
    瀏覽(24)
  • 【云原生】什么是云原生?如何學(xué)習(xí)云原生?一篇文章帶你了解云原生

    【云原生】什么是云原生?如何學(xué)習(xí)云原生?一篇文章帶你了解云原生

    云原生,相信這個(gè)名詞大家并不陌生;云原生在近期可謂是爆火,伴隨云計(jì)算的滾滾浪潮,云原生(CloudNative)的概念應(yīng)運(yùn)而生,云原生很火,火得一塌糊涂。可是現(xiàn)在很多人還是不知道什么是云原生,所以今天我們就來(lái)聊一聊近期很火的這個(gè)名詞:云原生吧 。 大家平時(shí)經(jīng)常提

    2024年02月02日
    瀏覽(31)
  • 一篇文章帶你了解什么是云計(jì)算,SaaS PaaS IaaS的區(qū)別

    一篇文章帶你了解什么是云計(jì)算,SaaS PaaS IaaS的區(qū)別

    目錄 一、本地部署 vs 云計(jì)算 彈性 運(yùn)維成本 數(shù)據(jù)安全 二、SaaS PaaS IaaS的區(qū)別 在了解云計(jì)算之前,我們先要了解什么是“計(jì)算”,支撐計(jì)算我們需要硬件基礎(chǔ)設(shè)施和軟件環(huán)境。 硬件包括服務(wù)器、存儲(chǔ)、網(wǎng)絡(luò)等...? 軟件環(huán)境包括數(shù)據(jù)庫(kù)、中間件、操作系統(tǒng)等... 云就是個(gè)地理概

    2024年04月27日
    瀏覽(32)
  • 一篇文章帶你了解抖音來(lái)客功能的使用方法和注意事項(xiàng)

    一篇文章帶你了解抖音來(lái)客功能的使用方法和注意事項(xiàng)

    抖音是近年來(lái)備受歡迎的社交媒體平臺(tái)之一,其中的“來(lái)客”功能更是讓許多人喜愛(ài)。那么什么是抖音來(lái)客呢?抖音來(lái)客是指在直播過(guò)程中,可以邀請(qǐng)其他抖音用戶(hù)進(jìn)行互動(dòng)和參與,從而增加直播的熱度和粉絲數(shù)量。下面不若與眾科技就來(lái)介紹一下抖音來(lái)客的具體使用方法和

    2024年02月08日
    瀏覽(25)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包