譯:selenium webdriver (python)
2013-06-16 01:24 ?蟲師 閱讀( ... ) 評論( ... ) 編輯 收藏
如果翻譯的很爛,原文檔地址:
http://docs.seleniumhq.org/docs/03_webdriver.jsp#firefox-driver
?
?
?
selenium?webdriver
注:?我們不斷的更新這份文檔,使這份文檔更加正確和完善;這份文檔相對來講也是比較準確的。
?
webdriver的簡介
硒2.0的主要新功能是集成的webdriver的API。webdriver的設計除了解決一些seleniumr-RC?API的一些限制,與webdriver?的整合,將提供一個更簡單,更簡潔的編程接口。selenium?webdriver會更好地支持動態的網頁,頁面本身被重新加載頁面元素可能更改。webdriver的目標是提供一個設計良好的面向對象的API,提供了更好的支持現代先進的web-app測試。
?
WebDriver與Selenium-RC相比,是如何來驅動瀏覽器的?
selenium?RC?的工作方式是為每一個支持的瀏覽器注入JavaScript函數,能過瀏覽器加載,然后在瀏覽器中使用javascripts來驅動AUT。
webdriver的不使用這種技術,它直接調用每個瀏覽器內置的自動化支持;對于不同瀏覽器的調用取決于瀏覽器本身,每個瀏覽器驅動的信息將會在后面的章節介紹。
?
webdriver?與selenium--server
?
你可能不需要selenium-server,這要看你怎么用selenium-webdriver了;如果你只使用webdriver的API?,那么是不需要selenium-server?的;如果你的測試和瀏覽器在同一臺機器上運行,并且只使用webdriver的API?,那么也是不需要selenium-server的,webdriver?將直接運行瀏覽器。
但在有些情況下,?Selenium-WebDriver是需要用到Selenium-Server?的:
?
·?您正在使用Selenium-Grid測試分發到多臺機器或虛擬機(VM)。
·?你連接到一臺遠程的計算機上,在一個特定有瀏覽器版本上運行
·?你不想用java(Python,?C#,?or?Ruby)綁定,而想用HtmlUnit?Driver
?
?
設置selenium?webdriver項目
?
要安裝selenium?之后需要建立一個項目,這樣就可以使用selenium寫程序了你如何做到這一點取決于你的編程語言和開發環境。?( 這里只介紹python的環境配置 )
?
Python
?
如果您正在使用Python測試自動化,那么你可能已經熟悉在Python開發。那么你可以使用下面的命令添加selenium到Python環境。
pip?install?selenium
?
?
關于更具體的環境配置可以參考我這篇文檔:
http://www.cnblogs.com/fnng/archive/2013/05/29/3106515.html
?
關于python開發的學習超出了本文的范圍,你可以通過python資源(官方文檔及其它相關資料、書籍)來快速的幫助你使用python進行自動化。
?
從selenium?1.0遷移
?
對于那些誰已經使用Selenium?1.0編寫的測試套件的同學,我們已經提供了如何遷移到Selenium?2.0的提示。??Selenium?2.0的主要開發人員,寫了一篇文章從Selenium?1.0遷移。我們作為附錄。
?
從Selenium?RC遷移到selenium?webdriver:
http://docs.seleniumhq.org/docs/appendix_migrating_from_rc_to_webdriver.jsp#migrating-to-webdriver-reference
?
?
selenium?webdriver的API介紹
?
?注:這里只貼python語言的代碼
webdriver的是一個Web應用程序測試自動化工具,用來驗證程序是否如預期的那樣執行。它的目的是提供一個友好的API,比selenium?RC(1.0)API更容易使用,這將有助于使你的測試腳本更容易閱讀和維護。它不依賴于任何特定的測試框架,所以它可以用戶單元測試或者一個老式的“main”方法中。本節介紹webdriver的API,下面讓我們來幫助你熟悉它。
如果你已經設置了項目,你就會發現,webdriver的作用跟其它庫一樣:它是完全獨立的,你通常在使用之前不需要啟動任何額外的進程,或者運行任何安裝程序,如果使用Selenium-RC則要到代理服務器。
?
注:需要額外的驅動來使腳本在不同環境下運行:Chrome?Driver,?Opera?Driver,?Android?Driver?andiPhone?Driver
現在我們來寫一些代碼。打開瀏覽器,輸入谷歌網頁,并在搜索框內輸入“Cheese”?點擊搜索,最后關閉瀏覽器。
from
selenium
import
webdriver
from
selenium.common.exceptions
import
TimeoutException
from
selenium.webdriver.support.ui
import
WebDriverWait
#
available since 2.4.0
from
selenium.webdriver.support
import
expected_conditions as EC
#
available since 2.26.0
#
Create a new instance of the Firefox driver
driver =
webdriver.Firefox()
#
go to the google home page
driver.get(
"
http://www.google.com
"
)
#
find the element that's name attribute is q (the google search box)
inputElement = driver.find_element_by_name(
"
q
"
)
#
type in the search
inputElement.send_keys(
"
Cheese!
"
)
#
submit the form (although google automatically searches now without submitting)
inputElement.submit()
#
the page is ajaxy so the title is originally this:
print
driver.title
try
:
#
we have to wait for the page to refresh, the last thing that seems to be updated is the title
WebDriverWait(driver, 10).until(EC.title_contains(
"
cheese!
"
))
#
You should see "cheese! - Google Search"
print
driver.title
finally
:
driver.quit()
在下面的章節中,您將了解更多有關如何使用webdriver的東西,如如何使用瀏覽器的前進和后退功能(這在selenium?1.0中不能被很好的支持);以及如何使用框架和窗口測試網站。我們將會提供了更深入的討論和范例。
?
?
Selenium?webdriver的API命令和操作
?
取回頁面
你可能使用webdriver想要做的第一件事是導航到一個頁面,通過“get”可以輕松的做到之一點
driver.get("http://www.google.com")
?
webdriver的運行依賴于幾個因素:包括操作系統/瀏覽器的組合,有時可能需要等待頁面加載。webdriver的在某些情況下,可能需要控制返回頁面的開始與加載時間。為了確保腳本的穩定性,需要等待的元素(S)在頁面中存在的?顯性和隱性的等待。
?
定位UI元素(WebElements)
?
參考:
http://www.cnblogs.com/fnng/archive/2012/01/12/2321117.html
自動化要想模擬用戶(人)的行為操作,首先需要識別并定位UI上的元素,每個元素都有特定屬性,webdriver就是通過識別元素的屬性來定位元素。
我們可以通過下面的一些屬性或方法來定定位元素:
?
ID?
?
這是最有效和最優選的方式來定位一個元素。常見的陷阱,開發人員可以為元素設置非唯一的ID?,或通過自動生成ID?,應該避免這種情況。
如何通過ID的方式定位一個元素,看下面這樣的例子:
"coolestWidgetEvah " >...
?
?
By?class?name
?
“class?”是指DOM元素的屬性。但在實際使用中有很多相同類名的DOM元素,在發現多個相同類名的元素時,程序會默認選擇最先找到的第一個元素。
如何通過類名找到一個元素,看下面的例子:
class
=
"
cheese
"
>
Cheddar
class
=
"
cheese
"
>
Gouda
cheeses
= driver.find_elements_by_class_name(
"
cheese
"
)
or
from
selenium.webdriver.common.by
import
By
cheeses
= driver.find_elements(By.CLASS_NAME,
"
cheese
"
)
?
?
By?tag?name?
?
DOM標簽名稱的元素。
具體方式如下面的例子:
frame
= driver.find_element_by_tag_name(
"
iframe
"
)
or
from
selenium.webdriver.common.by
import
By
frame
= driver.find_element(By.TAG_NAME,
"
iframe
"
)
By name
?
?
?
查找并匹配元素的name屬性
?
具體方式如下面的例子:
" cheese " type= " text " /> cheese = driver.find_element_by_name( " cheese " ) or from selenium.webdriver.common.by import By cheese = driver.find_element(By.NAME, " cheese " ) By link text
?
?
?
通過鏈接文本找到元素匹配
?
例子如下:
" http://www.google.com/search?q=cheese " >cheese> cheese = driver.find_element_by_link_text( " cheese " ) or from selenium.webdriver.common.by import By cheese = driver.find_element(By.LINK_TEXT, " cheese " )
By Partial Link Text
?
?
?
通過查找部分鏈接文件匹配元素
?
例子如下:
" http://www.google.com/search?q=cheese " >search for cheese> cheese = driver.find_element_by_partial_link_text( " cheese " ) or from selenium.webdriver.common.by import By cheese = driver.find_element(By.PARTIAL_LINK_TEXT, " cheese " )
?
?
?
By?CSS?
?
通過CSS的定位策略。默認情況下本機瀏覽器支持CSS定位,所以,請參考W3C?CSS選擇器
注意:不是所有瀏覽器對CSS的支持都是一樣的,可能在一個瀏覽器中運行良好,切換到另一個瀏覽器則不然。
具體用法如下:
"food " > class = " dairy " >milk class = " dairy aged " >cheese
cheese = driver.find_element_by_css_selector( " #food span.dairy.aged " ) or from selenium.webdriver.common.by import By cheese = driver.find_element(By.CSS_SELECTOR, " #food span.dairy.aged " ) By XPATH
?
在高的級別上,盡可能的使用一個瀏覽器原生的webdriver?XPath?的功能。在一些沒有本地的XPath支持的瀏覽器,我們已經提供了我們自己的實現。這可能會導致一些意想不到的行為,除非你知道各種XPath引擎的差異。
驅動 |
標簽和屬性名稱 |
屬性值 |
本地的XPath支持 |
HtmlUnit?Driver |
小寫 |
當他們出現在HTML |
是 |
Internet?Explorer?Driver |
小寫 |
當他們出現在HTML |
沒有 |
Firefox?Driver |
不區分大小寫 |
當他們出現在HTML |
是 |
?
這點抽象,對于下面這段HTML?代碼來說:
" text " name= " example " /> " text " name= " other " /> inputs = driver.find_elements_by_xpath( " //input " ) or from selenium.webdriver.common.by import By inputs = driver.find_elements(By.XPATH, " //input " )
?
?
不同驅動對大小寫的支持:
XPath?expression |
HtmlUnit?Driver |
Firefox?Driver |
Internet?Explorer?Driver |
//input |
1?(“example”) |
2 |
2 |
//INPUT |
0 |
2 |
0 |
?
HTML元素有時并不需要顯式地聲明,因為他們默認為已知值的屬性。例如,“input”的標簽并不需要的“type”屬性,因為它默認為“text”。webdriver使用XPath時,你不應該期望能夠對這些隱含的屬性相匹配。
?
?
使用JavaScript?
?
你可以執行任意javascript來找到一個元素,只要你返回一個DOM元素,它將自動轉換為一個WebElement對象。
簡單的例子,在頁面上加載了jQuery:
element = driver.execute_script(
"
return $('.cheese')[0]
"
)
?
在頁面上的每一個標簽查找所有輸入元素:
labels = driver.find_elements_by_tag_name(
"
label
"
)
inputs
=
driver.execute_script(
"
var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){
"
+
"
inputs.push(document.getElementById(labels[i].getAttribute('for'))); } return inputs;
"
, labels)
?
?
?
用戶輸入-填寫表單
?
我們已經看到了如何將文字輸入到一個文本或文本字段,但其他元素?您可以“切換”復選框的狀態,你可以使用“點擊”設置類似選擇的選項標記。處理SELECT標簽是不是太糟糕:
select = driver.find_element_by_tag_name(
"
select
"
)
allOptions
= select.find_elements_by_tag_name(
"
option
"
)
for
option
in
allOptions:
print
"
Value is:
"
+ option.get_attribute(
"
value
"
)
option.click()
?
找到頁面上第一個“select”的元素,并通過每個選項依次循環,打印出它們的值。你會發現,這不是最有效處理SELECT元素的方式。在webdriver的支持類中,有一個名為“select”,它提供了一些有用的方法,來處理這些交互。
#
available since 2.12
from
selenium.webdriver.support.ui
import
Select
select
= Select(driver.find_element_by_tag_name(
"
select
"
))
select.deselect_all()
select.select_by_visible_text(
"
Edam
"
)
?
?
從頁面上第一個選擇開始取消所有選項,從第一個選擇頁面上的所有選項,然后選擇顯示的文本與“Edam”?的選項。
當你完成填寫表格,你可能要提交。我們需要找到“提交”按鈕,然后單擊它:
driver.find_element_by_id(
"
submit
"
).click()
?
另外,有方便的方法可以在webdriver的每個元素上的“提交”。如果調用此表單內的元素,webdriver通過的DOM按順序找到封閉的形式,然后調用該提交。如果該元素不是一種形式,那么會拋出NoSuchElementException異常:
element.submit()
?
?
?
移動Windows和框架(Frames)
?
一些web應用程序有許多框架或多個窗口。通過webdriver的“switchTo”方法可以對他們呢進行移動操作。
driver.switch_to_window(
"
windowName
"
)
?
?
調用驅動程序現在解釋為被定向到特定的窗口。但是如何知道窗口的名字?以JavaScript或鏈接的方式打開它看看:
" somewhere.html " target= " windowName " >Click here to open a new window
?
?
另外,你也可以通過“window?handle”的“switchTo().window()”方法。認識到這一點,那么就可以遍歷所有打開的窗口,像這樣:
for
handle
in
driver.window_handles:
driver.switch_to_window(handle)
?
?
還可以切換從frames到frames(或到iframe中):
driver.switch_to_frame(
"
frameName
"
)
?
?
訪問子frames由一個圓點分隔的路徑,并且可以通過其索引指定frames。是:
driver.switch_to_frame(
"
frameName.0.child
"
)
would?go?to?the?frame?named?“child”?of?the?first?subframe?of?the?frame?called?“frameName”.All?frames?are?evaluated?as?if?from?*top*. ----- 實在不知道這個怎么翻譯
?
?
彈出對話框
?
Selenium?2.0測試版一開始,內置有處理彈出對話框支持。當你觸發一個動作,打開一個彈出框,您將得到以下提醒:
alert =
driver.switch_to_alert()
#
usage: alert.dismiss(), etc.
這將返回當前打開的警報對象。有了這個對象,你現在可以接受,拒絕,讀取其內容,甚至類型會得到一個提示。這個接口同樣適用警告,確認和提示。參考到的JavaDoc?或RubyDocs的的更多信息。
?
?
導航:歷史和位置
?
此前,我們介紹了webdriver的導航使用“get”命令
(driver.get(“http://www.example.com”)),我們在有些情況下是要用到導航欄前進和頭退功能:
driver.get(
"
http://www.example.com
"
)
#
python doesn't have driver.navigate
?
?
重申:“navigate().to()”?和?“get()”??的效果是一樣的。一個只是很多比其他更容易輸入!
你可以隨意的使用瀏覽器歷史記錄中后退和前進功能:
driver.forward()
driver.back()
?請注意,此功能完全依賴于底層瀏覽器。當你調用這些方法時,在不同的瀏覽器下可能會發生意想不到的事情
?
?
Cookies
?
你可能會非常感興趣了解如何使用Cookie。首先,你需要知道cookie有效期。如果您想先預設的cookie,然后再開始與網站進行交互,你的主頁很大/且需要一段時間來加載,一個辦法是找到一個更小的網頁來代替,通常404頁小(http://example.com/some404page)
#轉到正確的域
driver.get(
"
http://www.example.com
"
)
#現在在這里的整個域設置的cookie,
#這里的cookie的名稱是
'
key
'
,它的值是
'
value
'
的
driver.add_cookie({
'
name
'
:
'
key
'
,
'
value
'
:
'
value
'
,
'
path
'
:
'
/
'
})
#
additional keys that can be passed in are:
#
'domain' -> String,
#
'secure' -> Boolean,
#
'expiry' -> Milliseconds since the Epoch it should expire.
# 現在的輸出當前URL的所有可用的cookies
for
cookie
in
driver.get_cookies():
print
"
%s -> %s
"
% (cookie[
'
name
'
], cookie[
'
value
'
])
#
You can delete cookies in 2 ways
#
By name
driver.delete_cookie(
"
CookieName
"
)
#
Or all of them
driver.delete_all_cookies()
?
?
?
更改用戶代理
?
這是很容易與Firefox的驅動程序:
?
拖放
?
下面是一個例子使用執行拖放動作類。本地事件事件需要被激活。
from
selenium.webdriver.common.action_chains
import
ActionChains
element
= driver.find_element_by_name(
"
source
"
)
target
= driver.find_element_by_name(
"
target
"
)
ActionChains(driver).drag_and_drop(element, target).perform()
?
驅動程序的細節和權衡
?
?
Selenium?webdriver的驅動程序
?
?
參考:
http://www.cnblogs.com/fnng/archive/2012/02/10/2345187.html
?
?
?
webdriver的對于不同瀏覽器通過不同的接口實現;下面介紹這幾種實現方式:
?
HtmlUnit的驅動程序
?
這是目前最快,最輕量級的實施webdriver測試。正如它的名字所暗示的,這是基于HtmlUnit的。HtmlUnit是一個java實現基于web瀏覽器,沒有圖形用戶界面。對于任何語言綁定(Java以外)Selenium服務器需要使用此驅動程序。
用法
driver = webdriver.Remote(
"
http://localhost:4444/wd/hub
"
, webdriver.DesiredCapabilities.HTMLUNIT))
?
?
優點
·?在Webdriver執行自動化最快的方式
·?一個純Java的解決方案,因此它是獨立于平臺的。
·?支持JavaScript的
缺點
·?模擬其他瀏覽器的JavaScript行為(見下文)
?
?
HtmlUnit驅動器JavaScript?
?
沒有流行的瀏覽器使用JavaScript引擎,使用HtmlUnit(Rhino)。
如果你使用HtmlUnit測試JavaScript?,相比其他瀏覽?結果可能會不一樣。
?
當我們說“JavaScript”,其實我們說的是“JavaScript和DOM”。雖然DOM是由W3C定義的,每個瀏覽器都有自己特點和差異,HtmlUnit?有一套完整的實現DOM的方案,能很好的支持JavaScript?,但有別與其他瀏覽器,和W3C標準的主流瀏覽器的DOM的實現存在差異,盡管其模仿其有他瀏覽器的能力。
在webdriver?,我們選擇使用HtmlUnit來測試Javascript?,不過這樣存在問題和風險,但有越來越多的網站依賴于JavaScript?,我們采取了保守的做法,HtmlUnit默認情況下禁用JavaScript?。在webdriver的HtmlUnit的每個版本,我們重新評估這一決定:我們希望在一些點上HtmlUnit的默認情況下啟用JavaScript。
?
?
啟用JavaScript?
?
啟用JavaScript的支持是很容易的:
driver
= webdriver.Remote(
"
http://localhost:4444/wd/hub
"
, webdriver.DesiredCapabilities.HTMLUNITWITHJS)
?
?
?
?
這將導致HtmlUnit的驅動程序默認情況下,模擬火狐3.6的JavaScript進行處理。
?
?
Firefox?Driver
?
用Firefox的插件來控制火狐瀏覽器,firefox?配置文件使用selenium.xpi(插件)。默認情況下,需要修改一些設置(see?the?source?to?see?which?ones),火狐驅動是能夠運行在Windows,Mac,Linux上進行測試。目前在版本3.6,10(這個版本早過時了)
用法
driver = webdriver.Firefox()
?
?
優點
·?在一個真正的瀏覽器上運行,并支持JavaScript的
·?速度比Internet?Explorer的驅動程序快
缺點
·?比HtmlUnit的驅動程序慢
修改火狐簡介
假設你想要修改的用戶代理字符串(如上述),但你已經有了一個欺騙Firefox的配置文件,它包含許多有用的擴展。有兩種方式獲得此配置文件。假設使用Firefox的配置文件管理器(火狐?ProfileManager),已創建配置:
另外,如果配置文件尚未在Firefox注冊:
當我們正在開發firefox?啟動的特性,我們能夠正常使用。
正如我們在Firefox?Driver,開發功能,我們能夠使用。例如,直到我們感覺本機事件為Linux上的Firefox是穩定的,他們是默認情況下禁用。要啟用它們:
profile =
webdriver.FirefoxProfile()
profile.native_events_enabled
=
True
driver
= webdriver.Firefox(profile)
?
信息
請參閱火狐部分維基頁面的最新最先進的信息。
?
?
Internet?Explorer?Driver
?
該驅動程序控制.dll,因而只適用于Windows操作系統。每個selenium釋放它的核心功能在xp下測試IE版本6,7和8,在Windows7下測試IE?9。
用法
driver = webdriver.Ie()
?
?
優點
·?運行在一個真正的瀏覽器支持JavaScript與最終用戶看到的所有的行為一致
缺點
·?顯然,Internet?Explorer?Driver只能在Windows上工作!
·?相對緩慢(盡管仍然是相當快速的)
·?本身不支持XPath的大多數版本。自動注入,這是明顯慢于其他瀏覽器和進行比較時,在同一瀏覽器的CSS選擇器變慢。
·?本身不支持CSS版本6和7。
·?CSS選擇器在IE?8和9是本地的,但這些瀏覽器不完全支持CSS3
信息
維基頁面的最先進的最新信息,請參閱Internet?Explorer的部分。請特別注意所需的配置部分。
?
?
Chrome驅動
?
Chrome驅動程序維護/支持Chrome?項目本身。webdriver的工作與Chrome通過的chromedriver二進制(Chrome項目的下載頁面上找到)。你需要有兩個chromedriver和安裝一個版本的Chrome瀏覽器。為了webdriver的自動找到,chromedriver需要要放在系統的路徑上。Chrome瀏覽器本身由chromedriver在默認安裝路徑找到。這些都可以通過環境變量覆蓋。?有關更多信息,請參閱維基。
用法
driver = webdriver.Chrome()
?
?
優點
·?在一個真正的瀏覽器上運行,并支持JavaScript的
·?因為Chrome是基于Webkit的瀏覽器,Chrome?Driver會允許您驗證您的網站在Safari的測試效果。需要注意的是,因為瀏覽器使用其自己的V8?JavaScript引擎,而不是Safari瀏覽器的Nitro引擎,JavaScript的執行可能會有所不同。
缺點
·?比HtmlUnit的驅動程序慢
·?
信息
最先進的最新信息,請參閱我們的wiki。更多信息,也可以找到下載頁面
?
獲取與Chrome驅動程序運行
鉻驅動程序可執行文件下載?,并按照其他的wiki頁面上的說明
Opera?Driver
見歌劇院驅動器在上使用Opera驅動程序的信息的selenium維基wiki文章。
iPhone?Driver
查看iPhone的驅動selenium維基上使用Mac的iOS驅動程序的信息,wiki文章。
Android?Driver
查看Android的驅動程序?硒selenium維基采用了Android驅動程序的信息,wiki文章。
?
?
混合使用webdriver和RC技術
?
Webdriver替換selenium?RC?
webdriver的Java版本的selenium?RC?API提供了一種實現。這意味著,你可以使用Selenium-RC?API和使用底層webdriver的技術。這主要是用于向后兼容。它允許那些使用selenium?RC?API的用戶使用webdriver覆蓋現有的測試套件。它提供幫助緩解遷移到selenium?webdriver。此外,允許一個人使用這兩個API,在相同的測試代碼。
Selenium?webdriver的使用是這樣的:
優點
·?webdriver的和selenium的API允許并排存在
·?webdriver的遷移管理機制提供了一個簡單的Selenium?RC?API
·?不需要獨立的Selenium?RC服務器的運行
缺點
·?不能支持每一個方法
·?更多先進的selenium使用(using?“browserbot”?or?other?built-in?JavaScript?methods?from?Selenium?Core)可能無法正常工作
·?由于底層實現差異,有些方法可能會比較慢
備份webdriver與selenium
webdriver的盡可能多兼容selenium?RC對瀏覽器的支持,同時仍然提供支持使用webdriver的API,所以為了您可以利用SeleneseCommandExecutor
Safari是支持這種方式,用下面的代碼(確保禁用彈出窗口攔截功能):
這種方法目前有一些主要限制,尤其是findElements并不如預期般運作。此外,繁重的驅動瀏覽器,因為我們使用的是selenium?的核心,你的JavaScript沙箱限制。
運行獨立Selenium服務器使用RemoteDrivers?
從selenium?的下載頁下載服務器獨立
拆開IEDriverServer和(或)chromedriver,并把它們在$?PATH?/%PATH%?-?Selenium服務器上的一個目錄,這是應該能夠IE?/?Chrome的處理請求,而無需額外的修改。
啟動服務器的命令行
java -jar
/selenium-server-standalone-
.jar
?
?
如果你想使用原生的事件功能,表明在命令行上的選項
Dwebdriver.enable.native.events = 1
?
?
對于其他命令行選項,執行
java -jar
/selenium-server-standalone-
.jar -help
?
?
為了正常工作,應該允許以下端口傳入的TCP連接:??4444,7054-5(or?twice?as?many?ports?as?the?number?of?concurrent?instances?you?plan?to?run)。在Windows下,你可能需要以及疏通各種應用。
?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
