目錄:導讀
概述
python+selenium環(huán)境安裝
使用selenium啟動瀏覽器
selenium頁面加載等待和檢測
使用time.sleep()等待
使用implicitly_wait設(shè)置最長等待時間
使用WebDriverWait設(shè)置等待條件
檢測document是否加載完成
selenium元素定位和讀取
查找元素
dom元素交互
查找元素失敗處理
selenium交互控制
ActionChains動作鏈
模擬鼠標事件
模擬鍵盤輸入事件
警告框處理
selenium瀏覽器控制
基本常用api
selenium讀取和加載cookie
selenium打開新的標簽頁窗口
selenium一些問題記錄
獲取隱藏元素的文本內(nèi)容
瀏覽器崩潰WebDriverException異常處理
selenium抓取頁面請求數(shù)據(jù)
寫在最后
Selenium自動化測試教程地址:https://www.bilibili.com/video/BV17G4y1Z74z/?
概述
selenium
是網(wǎng)頁應(yīng)用中最流行的自動化測試工具,可以用來做自動化測試或者瀏覽器爬蟲等。官網(wǎng)地址為:selenium。相對于另外一款web自動化測試工具QTP來說有如下優(yōu)點:
- 免費開源輕量級,不同語言只需要一個體積很小的依賴包
- 支持多種系統(tǒng),包括Windows,Mac,Linux
- 支持多種瀏覽器,包括Chrome,F(xiàn)ireFox,IE,safari,opera等
- 支持多語言,包括Java,C,python,c#等主流語言
- 支持分布式測試用例執(zhí)行
python+selenium環(huán)境安裝
首先需要安裝python(推薦3.7+)環(huán)境,然后直接用pip install selenium
安裝依賴包即可。
另外還需要下載瀏覽器相應(yīng)的webdriver
驅(qū)動程序,注意下載的驅(qū)動版本一定要匹配瀏覽器版本。
- Firefox瀏覽器驅(qū)動:geckodriver
- Chrome瀏覽器驅(qū)動:chromedriver
- IE瀏覽器驅(qū)動:IEDriverServer
- Edge瀏覽器驅(qū)動:MicrosoftWebDriver
- Opera瀏覽器驅(qū)動:operadriver
下載以后可以把驅(qū)動程序加到環(huán)境變量,這樣使用時就不用手動指定驅(qū)動程序路徑。
使用selenium啟動瀏覽器
可以在python中使用下面的代碼啟動一個Chrome
瀏覽器,然后控制這個瀏覽器的行為或者讀取數(shù)據(jù)。
from selenium import webdriver
# 啟動Chrome瀏覽器,要求chromedriver驅(qū)動程序已經(jīng)配置到環(huán)境變量
# 將驅(qū)動程序和當前腳本放在同一個文件夾也可以
driver = webdriver.Chrome()
# 手動指定驅(qū)動程序路徑
driver = webdriver.Chrome(r'D:/uusama/tools/chromedriver.exe')
driver = webdriver.Ie() # Internet Explorer瀏覽器
driver = webdriver.Edge() # Edge瀏覽器
driver = webdriver.Opera() # Opera瀏覽器
driver = webdriver.PhantomJS() # PhantomJS
driver.get('http://uusama.com') # 打開指定路徑的頁面
啟動的時候還可以設(shè)置啟動參數(shù),比如下面的代碼實現(xiàn)啟動時添加代理,并且忽略https
證書校驗。
from selenium import webdriver
# 創(chuàng)建chrome啟動選項對象
options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=127.0.0.1:16666") # 設(shè)置代理
options.add_argument("---ignore-certificate-errors") # 設(shè)置忽略https證書校驗
options.add_experimental_option("excludeSwitches", ["enable-logging"]) # 啟用日志
# 設(shè)置瀏覽器下載文件時保存的默認路徑
prefs = {"download.default_directory": get_download_dir()}
options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(options=options)
一些非常有用的啟動選項,下面使用的options = webdriver.ChromeOptions()
:
-
options.add_argument("--proxy-server=127.0.0.1:16666")
: 設(shè)置代理,可以結(jié)合mitmproxy
進行抓包等 -
option.add_experimental_option('excludeSwitches', ['enable-automation'])
: 設(shè)置繞過selenium
檢測 -
options.add_argument("---ignore-certificate-errors")
: 設(shè)置忽略https證書校驗 -
options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
: 設(shè)置不請求圖片模式加快頁面加載速度 -
chrome_options.add_argument('--headless')
: 設(shè)置無頭瀏覽器
selenium頁面加載等待和檢測
使用selenium打開頁面以后,還不能立刻操作,需要等到待處理頁面元素加載完成,這時就需要檢測和等待頁面元素加載。
使用time.sleep()等待
最簡單的方法就是打開頁面以后,使用time.sleep()
強制等待一定時間,該方法只能設(shè)置一個固定時間等待,如果頁面提前加載完成,則會空等阻塞。
from time import sleep
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('http://uusama.con')
time.sleep(10)
print('load finish')
使用implicitly_wait設(shè)置最長等待時間
另外還可以使用implicitly_wait
設(shè)置最長等待時間,如果在給定時間內(nèi)頁面加載完成或者已經(jīng)超時,才會執(zhí)行下一步。該方法會等到所有資源全部加載完成,也就是瀏覽器標簽欄的loading圖表不再轉(zhuǎn)才會執(zhí)行下一步。有可能頁面元素已經(jīng)加載完成,但是js或者圖片等資源還未加載完成,此時還需要等待。
另需注意使用implicitly_wait
只需設(shè)置一次,且對整個driver
生命周期都起作用,凡是遇到頁面正在加載都會阻塞。
示例如下:
from selenium import webdriver
driver = webdriver.Chrome()
driver.implicitly_wait(30) # 設(shè)置最長等30秒
driver.get('http://uusama.com')
print(driver.current_url)
driver.get('http://baidu.com')
print(driver.current_url)
使用WebDriverWait設(shè)置等待條件
使用WebDriverWait
(selenium.webdriver.support.wait.WebDriverWait)能夠更加精確靈活地設(shè)置等待時間,WebDriverWait
可在設(shè)定時間內(nèi)每隔一段時間檢測是否滿足某個條件,如果滿足條件則進行下一步操作,如果超過設(shè)置時間還不滿足,則拋出TimeoutException
異常,其方法聲明如下:
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
其中各參數(shù)含義如下:
-
driver
:瀏覽器驅(qū)動 -
timeout
:最長超時時間,默認以秒為單位 -
poll_frequency
:檢測的間隔(步長)時間,默認為0.5秒
-
ignored_exceptions
:忽略的異常,即使在調(diào)用until()
或until_not()
的過程中拋出給定異常也不中斷
WebDriverWait()
一般配合until()
或until_not()
方法使用,表示等待阻塞直到返回值為True
或者False
,需要注意這兩個方法的參數(shù)都需是可調(diào)用對象,即方法名稱,可以使用expected_conditions
模塊中的方法或者自己封裝的方法。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
driver = webdriver.Chrome()
driver.get("http://baidu.com")
# 判斷id為`input`的元素是否被加到了dom樹里,并不代表該元素一定可見,如果定位到就返回WebElement
element = WebDriverWait(driver, 5, 0.5).until(expected_conditions.presence_of_element_located((By.ID, "s_btn_wr")))
# implicitly_wait和WebDriverWait都設(shè)置時,取二者中最大的等待時間
driver.implicitly_wait(5)
# 判斷某個元素是否被添加到了dom里并且可見,可見代表元素可顯示且寬和高都大于0
WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.ID, 'su')))
# 判斷元素是否可見,如果可見就返回這個元素
WebDriverWait(driver,10).until(EC.visibility_of(driver.find_element(by=By.ID, value='kw')))
下面列出expected_conditions
常用的一些方法:
-
title_is
: 判斷當前頁面title是否精確等于預(yù)期 -
title_contains
: 判斷當前頁面title是否包含預(yù)期字符串 -
presence_of_element_located
: 判斷某個元素是否被加到了dom樹里,并不代表該元素一定可見 -
visibility_of_element_located
: 判斷某個元素是否可見(元素非隱藏,并且元素的寬和高都不等于0) -
visibility_of
: 跟上面的方法做一樣的事情,只是上面的方法要傳入locator,這個方法直接傳定位到的element就好了 -
presence_of_all_elements_located
: 判斷是否至少有1個元素存在于dom樹中。舉個例子,如果頁面上有n個元素的class都是'column-md-3',那么只要有1個元素存在,這個方法就返回True -
text_to_be_present_in_element
: 判斷某個元素中的text是否包含了預(yù)期的字符串 -
text_to_be_present_in_element_value
: 判斷某個元素中的value屬性是否包含了預(yù)期的字符串 -
frame_to_be_available_and_switch_to_it
: 判斷該frame是否可以switch進去,如果可以的話,返回True并且switch進去,否則返回False -
invisibility_of_element_located
: 判斷某個元素中是否不存在于dom樹或不可見 -
element_to_be_clickable
: 判斷某個元素中是否可見并且是enable的,這樣的話才叫clickable -
staleness_of
: 等某個元素從dom樹中移除,注意,這個方法也是返回True或False -
element_to_be_selected
: 判斷某個元素是否被選中了,一般用在下拉列表 -
element_selection_state_to_be
: 判斷某個元素的選中狀態(tài)是否符合預(yù)期 -
element_located_selection_state_to_be
: 跟上面的方法作用一樣,只是上面的方法傳入定位到的element,而這個方法傳入locator
檢測document是否加載完成
另外還可以使用driver.execute_script('return document.readyState;') == 'complete'
來檢測document
是否加載完成。
注意document
加載完成,是不包括那種異步加載ajax請求動態(tài)渲染dom的,這種需要使用WebDriverWait
檢測某個元素是否渲染完成。
selenium元素定位和讀取
查找元素
selenium提供了一系列api方便獲取chrome中的元素,這些API都返回WebElement
對象或其列表,如:
-
find_element_by_id(id)
: 查找匹配id的第一個元素 -
find_element_by_class_name()
: 查找匹配class
的第一個元素 -
find_elements_by_xpath()
: 查找匹配xpath
的所有元素 -
find_elements_by_css_selector()
: 查找匹配css選擇器的所有元素
其實可以看WebDriver
類里面的實現(xiàn)源碼,其核心實現(xiàn)都是調(diào)用兩個基本函數(shù):
-
find_element(self, by=By.ID, value=None)
: 查找匹配策略的第一個元素 -
find_elements(self, by=By.ID, value=None)
: 查找匹配策略的所有元素
其中by
參數(shù)可以是ID
,?CSS_SELECTOR
,?CLASS_NAME
,?XPATH
等。下面舉幾個簡單的例子:
- 通過xpath查詢包含文本
登錄
的第一個元素:?find_element_by_xpath("http://*[contains(text(),'登錄')]")
- 查詢包含類名
refresh
的所有元素:?find_elements_by_class_name('refresh')
- 查詢
table
表格的第二行:?find_element_by_css_selector('table tbody > tr:nth(2)')
dom元素交互
上面介紹的元素查找結(jié)果WebElement
對象,常用的api有:
-
element.text
: 返回元素的文本內(nèi)容(包括所有后代節(jié)點的內(nèi)容),注意如果元素display=none
則返回為空字符串 -
element.screenshot_as_png
: 元素的截圖 -
element.send_keys("input")
: 元素輸入框輸入input
字符串 -
element.get_attribute('data-v')
: 獲取data-v
名稱屬性值,除了自定義節(jié)點屬性,還可以獲取如textContent
等屬性 -
element.is_displayed()
: 判斷元素是否用戶可見 -
element.clear()
: 清除元素文本 -
element.click()
: 點擊元素,如果元素不可點擊會拋出ElementNotInteractableException
異常 -
element.submit()
: 模擬表單提交
查找元素失敗處理
如果找不到指定元素,則會拋出NoSuchElementException
異常,而且需要注意,display=none
的元素是可以獲取到的,凡是在dom
節(jié)點中的元素都可以獲取到。
而且實際使用的時候要注意一些js代碼動態(tài)創(chuàng)建的元素,可能需要輪詢獲取或者監(jiān)控。
一個檢查是否存在指定元素的方法如下:
def check_element_exists(xpath):
try:
driver.find_element_by_xpath(xpath)
except NoSuchElementException:
return False
return True
selenium交互控制
ActionChains動作鏈
webdriver通過ActionChains
對象來模擬用戶操作,該對象表示一個動作鏈路隊列,所有操作會依次進入隊列但不會立即執(zhí)行,直到調(diào)用perform()
方法時才會執(zhí)行。其常用方法如下:
-
click(on_element=None)
: 單擊鼠標左鍵 -
click_and_hold(on_element=None)
: 點擊鼠標左鍵,不松開 -
context_click(on_element=None)
: 點擊鼠標右鍵 -
double_click(on_element=None)
: 雙擊鼠標左鍵 -
send_keys(*keys_to_send)
: 發(fā)送某個鍵到當前焦點的元素 -
send_keys_to_element(element, *keys_to_send)
: 發(fā)送某個鍵到指定元素 -
key_down(value, element=None)
: 按下某個鍵盤上的鍵 -
key_up(value, element=None)
: 松開某個鍵 -
drag_and_drop(source, target)
: 拖拽到某個元素然后松開 -
drag_and_drop_by_offset(source, xoffset, yoffset)
: 拖拽到某個坐標然后松開 -
move_by_offset(xoffset, yoffset)
: 鼠標從當前位置移動到某個坐標 -
move_to_element(to_element)
: 鼠標移動到某個元素 -
move_to_element_with_offset(to_element, xoffset, yoffset)
: 移動到距某個元素(左上角坐標)多少距離的位置 -
perform()
: 執(zhí)行鏈中的所有動作 -
release(on_element=None)
: 在某個元素位置松開鼠標左鍵
模擬鼠標事件
下面代碼模擬鼠標移動,點擊,拖拽等操作,注意操作時需要等待一定時間,否則頁面還來不及渲染。
from time import sleep
from selenium import webdriver
# 引入 ActionChains 類
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://www.baidu.cn")
action_chains = ActionChains(driver)
target = driver.find_element_by_link_text("搜索")
# 移動鼠標到指定元素然后點擊
action_chains.move_to_element(target).click(target).perform()
time.sleep(2)
# 也可以直接調(diào)用元素的點擊方法
target.click()
time.sleep(2)
# 鼠標移動到(10, 50)坐標處
action_chains.move_by_offset(10, 50).perform()
time.sleep(2)
# 鼠標移動到距離元素target(10, 50)處
action_chains.move_to_element_with_offset(target, 10, 50).perform()
time.sleep(2)
# 鼠標拖拽,將一個元素拖動到另一個元素
dragger = driver.find_element_by_id('dragger')
action.drag_and_drop(dragger, target).perform()
time.sleep(2)
# 也可以使用點擊 -> 移動來實現(xiàn)拖拽
action.click_and_hold(dragger).release(target).perform()
time.sleep(2)
action.click_and_hold(dragger).move_to_element(target).release().perform()
模擬鍵盤輸入事件
通過send_keys
模擬鍵盤事件,常用有:
-
send_keys(Keys.BACK_SPACE)
: 刪除鍵(BackSpace) -
send_keys(Keys.SPACE)
: 空格鍵(Space) -
send_keys(Keys.TAB)
: 制表鍵(Tab) -
send_keys(Keys.ESCAPE)
: 回退鍵(Esc) -
send_keys(Keys.ENTER)
: 回車鍵(Enter) -
send_keys(Keys.F1)
: 鍵盤 F1 -
send_keys(Keys.CONTROL,'a')
: 全選(Ctrl+A) -
send_keys(Keys.CONTROL,'c')
: 復(fù)制(Ctrl+C) -
send_keys(Keys.CONTROL,'x')
: 剪切(Ctrl+X) -
send_keys(Keys.CONTROL,'v')
: 粘貼(Ctrl+V)
示例:定位到輸入框,然后輸入內(nèi)容
# 輸入框輸入內(nèi)容
driver.find_element_by_id("kw").send_keys("uusamaa")
# 模擬回車刪除多輸入的一個字符a
driver.find_element_by_id("kw").send_keys(Keys.BACK_SPACE)
警告框處理
用于處理調(diào)用alert
彈出的警告框。
-
driver.switch_to_alert()
: 切換到警告框 -
text
:返回alert/confirm/prompt
中的文字信息,比如js調(diào)用alert('failed')
則會獲取failed
字符串 -
accept()
:接受現(xiàn)有警告框 -
dismiss()
:關(guān)閉現(xiàn)有警告框 -
send_keys(keysToSend)
:將文本發(fā)送至警告框
selenium瀏覽器控制
基本常用api
下面列出一些非常實用的瀏覽器控制api:
-
driver.current_url
: 獲取當前活動窗口的url -
driver.switch_to_window("windowName")
: 移動到指定的標簽窗口 -
driver.switch_to_frame("frameName")
: 移動到指定名稱的iframe
-
driver.switch_to_default_content()
: 移動到默認文本內(nèi)容區(qū) -
driver.maximize_window()
: 將瀏覽器最大化顯示 -
driver.set_window_size(480, 800)
: 設(shè)置瀏覽器寬480、高800顯示 -
driver.forword()
,?driver.back()
: 瀏覽器前進和后退 -
driver.refresh()
: 刷新頁面 -
driver.close()
: 關(guān)閉當前標簽頁 -
driver.quiit()
: 關(guān)閉整個瀏覽器 -
driver.save_screenshot('screen.png')
: 保存頁面截圖 -
driver.maximize_window()
: 將瀏覽器最大化顯示 -
browser.execute_script('return document.readyState;')
: 執(zhí)行js腳本
selenium讀取和加載cookie
使用get_cookies
和add_cookie
可以實現(xiàn)將cookie緩存到本地,然后啟動時加載,這樣可以保留登錄態(tài)。實現(xiàn)如下
import os
import json
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.baidu.cn")
# 讀取所有cookie并保存到文件
cookies = driver.get_cookies()
cookie_save_path = 'cookie.json'
with open(cookie_save_path, 'w', encoding='utf-8') as file_handle:
json.dump(cookies, file_handle, ensure_ascii=False, indent=4)
# 從文件讀取cookie并加載到瀏覽器
with open(cookie_save_path, 'r', encoding='utf-8') as file_handle:
cookies = json.load(file_handle)
for cookie in cookies:
driver.add_cookie(cookie)
selenium打開新的標簽頁窗口
使用driver.get(url)
會默認在第一個標簽窗口打開指定連接,點擊頁面中的_blank
的鏈接時也會打開一個新的標簽窗口。
還可以用下面的方式手動打開一個指定頁面的標簽窗口,需要注意打開新窗口或者關(guān)閉以后,還需要手動調(diào)用switch_to.window
切換當前活動的標簽窗口,否則會拋出NoSuchWindowException
異常。
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.baidu.cn")
new_tab_url = 'http://uusama.com'
driver.execute_script(f'window.open("{new_tab_url}", "_blank");')
time.sleep(1)
# 注意:必須調(diào)用switch_to.window手動切換window,否則會找不到tab view
# 聚焦到新打開的tab頁面,然后關(guān)閉
driver.switch_to.window(driver.window_handles[1])
time.sleep(2)
driver.close() # 關(guān)閉當前窗口
# 手動回到原來的tab頁面
driver.switch_to.window(driver.window_handles[0])
time.sleep(1)
除了使用execute_script
外,還可以使用模擬打開新tab頁按鍵的方式新建一個標簽頁窗口:
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
ActionChains(driver).key_down(Keys.CONTROL).send_keys('t').key_up(Keys.CONTROL).perform()
selenium一些問題記錄
獲取隱藏元素的文本內(nèi)容
如果一個元素是隱藏的,即display=none
,雖然可以通過find_element
查找到該元素,但是用element.text
屬性是獲取不到該元素文本內(nèi)容的,其值是空字符串,這時可以用下面的方式獲?。?/p>
element = driver.find_element_by_id('uusama')
driver.execute_script("return arguments[0].textContent", element)
driver.execute_script("return arguments[0].innerHTML", element)
# 相應(yīng)的也可以把隱藏的元素設(shè)置為非隱藏
driver.execute_script("arguments[0].style.display = 'block';", element)
瀏覽器崩潰WebDriverException異常處理
比如在Chrome
中長時間運行一個頁面會出現(xiàn)Out Of Memory
內(nèi)存不足的錯誤,此時WebDriver
會拋出WebDriverException
異常,基本所有api都會拋出這個異常,這個時候需要捕獲并進行特殊處理。
我的處理方式是記錄頁面的一些基本信息,比如url,cookie等,并定期寫入到文件中,如果檢測到該異常,則重啟瀏覽器并且加載url和cookie等數(shù)據(jù)。
selenium抓取頁面請求數(shù)據(jù)
網(wǎng)上有通過driver.requests
或者通過解析日志來獲取頁面請求的方式,但是我感覺都不是很好使。最后使用mitmproxy
代理進行抓包處理,然后啟動selenium
時填入代理來實現(xiàn)。
proxy.py
為在mitmproxy
基礎(chǔ)上封裝的自定義代理請求處理,其代碼如下:
import os
import gzip
from mitmproxy.options import Options
from mitmproxy.proxy.config import ProxyConfig
from mitmproxy.proxy.server import ProxyServer
from mitmproxy.tools.dump import DumpMaster
from mitmproxy.http import HTTPFlow
from mitmproxy.websocket import WebSocketFlow
class ProxyMaster(DumpMaster):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def run(self, func=None):
try:
DumpMaster.run(self, func)
except KeyboardInterrupt:
self.shutdown()
def process(url: str, request_body: str, response_content: str):
# 抓包請求處理,可以在這兒轉(zhuǎn)存和解析數(shù)據(jù)
pass
class Addon(object):
def websocket_message(self, flow: WebSocketFlow):
# 監(jiān)聽websockt請求
pass
def response(self, flow: HTTPFlow):
# 避免一直保存flow流,導致內(nèi)存占用飆升
# flow.request.headers["Connection"] = "close"
# 監(jiān)聽http請求響應(yīng),并獲取請求體和響應(yīng)內(nèi)容
url = flow.request.url
request_body = flow.request
response_content = flow.response
# 如果返回值是壓縮的內(nèi)容需要進行解壓縮
if response_content.data.content.startswith(b'\x1f\x8b\x08'):
response_content = gzip.decompress(response_content.data.content).decode('utf-8')
Addon.EXECUTOR.submit(process, url, request_body, response_content)
def run_proxy_server():
options = Options(listen_host='0.0.0.0', listen_port=16666)
config = ProxyConfig(options)
master = ProxyMaster(options, with_termlog=False, with_dumper=False)
master.server = ProxyServer(config)
master.addons.add(Addon())
master.run()
if __name__ == '__main__':
with open('proxy.pid', mode='w') as fin:
fin.write(os.getpid().__str__())
run_proxy_server()
在使用mitmproxy
過程中,隨著時間推移proxy.py
會出現(xiàn)占用內(nèi)存飆升的問題,在github的issue區(qū)有人也遇到過,有說是因為http連接keep-alive=true
請求會一直保存不會釋放,導致請求越多越占用內(nèi)存,然后通過添加flow.request.headers["Connection"] = "close"
來手動關(guān)閉連接,我加了以后有一定緩解,但還是不能從根本上解決。
最后通過寫入proxy.pid
記錄代理程序進程,然后用另外一個程序定時重啟proxy.py
來解決內(nèi)存泄漏的問題。
寫在最后
如果你覺得文章還不錯,請大家?點贊、分享、留言?下,因為這將是我持續(xù)輸出更多優(yōu)質(zhì)文章的最強動力!
看到這篇文章的人有覺得我的理解有誤的地方,也歡迎評論和探討~
你也可以加入下方的的群聊去和同行大神交流切磋文章來源:http://www.zghlxwxcb.cn/news/detail-743996.html
?
文章來源地址http://www.zghlxwxcb.cn/news/detail-743996.html
到了這里,關(guān)于測試員進階必看系列 “ python自動化測試工具selenium使用指南 ”的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!