TML 中使用 <input> 元素表示單行輸入框和 <textarea> 元素表示多行文本框。
HTML中使用的 <input> 元素在 JavaScript 中對應的是 HTMLInputElement 類型。HTMLInputElement 繼承自 HTMLElement 接口:
interface HTMLInputElement extends HTMLElement {
...
}
HTMLInputElement 類型有一些獨有的屬性和方法:
而在上述介紹 HTMLInputElement 類型中的屬性時,type 屬性要特別關注一下,因為根據(jù) type 屬性的改變,可以改變<input>的屬性。
類型 | 描述 |
text | 文本輸入 |
password | 密碼輸入 |
submit | 表單數(shù)據(jù)提交 |
button | 按鈕 |
radio | 單選框 |
checkbox | 復選框 |
file | 文件 |
hidden | 隱藏的字段 |
image | 定義圖像作為提交按鈕 |
reset | 重置按鈕 |
省略 type 屬性與 type="text"效果一樣, <input> 元素顯示為文本框。
當 type 的值為text/password/number/時,會有以下屬性對 <input> 元素有效。
屬性 | 類型 | 描述 |
autocomplete | string | 字符串on或off,表示<input>元素的輸入內容可以被瀏覽器自動補全。 |
maxLength | long | 指定<input>元素允許的最多字符數(shù)。 |
size | unsigned long | 表示<input>元素的寬度,這個寬度是以字符數(shù)來計量的。 |
pattern | string | 表示<input>元素的值應該滿足的正則表達式 |
placeholder | string | 表示<input>元素的占位符,作為對元素的提示。 |
readOnly | boolean | 表示用戶是否可以修改<input>的值。 |
min | string | 表示<input>元素的最小數(shù)值或日期。 |
max | string | 表示<input>元素的最大數(shù)值或日期。 |
selectionStart | unsigned long | 表示選中文本的起始位置。如果沒有選中文本,返回光標在<input>元素內部的位置。 |
selectionEnd | unsigned long | 表示選中文本的結束位置。如果沒有選中文本,返回光標在<input>元素內部的位置。 |
selectionDirection | string | 表示選中文本的方向。可能的值包括forward、backward、none。 |
下面創(chuàng)建一個 type="text" ,一次顯示 25 個字符,但最多允許顯示 50 個字符的文本框:
<input type="text" size="25" maxlength="50" value="initial value">
HTML 使用的 <textarea> 元素在 JavaScript 中對應的是 HTMLTextAreaElement 類型。HTMLTextAreaElement類型繼承自 HTMLElement 接口:
interface HTMLTextAreaElement extends HTMLElement {
...
}
HTMLTextAreaElement 類型有一些獨有的屬性和方法:
下面創(chuàng)建一個高度為 25,寬度為 5 的 <textarea> 多行文本框。它與 <input> 不同的是,初始值顯示在 <textarea>...</textarea> 之間:
<textarea rows="25" cols="5">initial value</textarea>
注意:處理文本框值的時候最好不要使用 DOM 方法,而應該使用 value 屬性。
<input> 與 <textarea> 都支持 select() 方法,該方法用于選中文本框中的所有內容。該方法的語法為:
select(): void
下面看一個示例:
let textbox = document.forms[0].elements["input-box"];
textbox.select();
也可以在文本框獲得焦點時,選中文本框的內容:
textbox.addEventListener("focus", (event) => {
event.target.select();
});
當選中文本框中的文本或使用 select() 方法時,會觸發(fā) select 事件。
let textbox = document.forms[0].elements["textbox1"];
textbox.addEventListener("select", (event) => {
console.log(`Text selected: ${textbox.value}`);
});
HTML5 對 select 事件進行了擴展,通過 selectionStart 和 selectionEnd 屬性獲取文本選區(qū)的起點偏移量和終點偏移量。如下所示:
function getSelectedText(textbox){
return textbox.value.substring(textbox.selectionStart,
textbox.selectionEnd);
}
注意:在 IE8 及更早版本不支持這兩個屬性。
HTML5 提供了 setSelectionRange() 方法用于選中部分文本:
setSelectionRange(start, end, direction): void;
下面看一個例子:
<input type="text" id="text-sample" size="20" value="Hello World!">
<button onclick="selectText()">選中部分文本</button>
<script>
function selectText() {
let input = document.getElementById("text-sample");
input.focus();
input.setSelectionRange(4, 8); // o Wo
}
</script>
如果想要看到選中效果,必須讓文本框獲得焦點。
不同文本框經(jīng)常需要保證輸入特定類型或格式的數(shù)據(jù),或許數(shù)據(jù)需要包含特定字符或必須匹配某個特定模式。而文本框并未提供驗證功能,因此要配合 JavaScript 腳本實現(xiàn)輸入過濾功能。
有些輸入框需要出現(xiàn)或不出現(xiàn)特定字符。如果想要將輸入框變成只讀的,只需要使用 preventDefault()方法將按鍵都屏蔽:
input.addEventListener("keypress", (event) => {
event.preventDefault();
});
而要屏蔽特定字符,就需要檢查事件的 charCode 屬性。如下所示,使用正則表達式實現(xiàn)只允許輸入數(shù)字的輸入框:
input.addEventListener("keypress", (event) => {
if (!/\d/.test(event.key)) {
event.preventDefault();
}
});
還有一個問題需要處理:復制、粘貼及涉及Ctrl 鍵的其他功能。在除IE 外的所有瀏覽器中,前面代碼會屏蔽快捷鍵Ctrl+C、Ctrl+V 及其他使用Ctrl 的組合鍵。因此,最后一項檢測是確保沒有按下Ctrl鍵,如下面的例子所示:
textbox.addEventListener("keypress", (event) => {
if (!/\d/.test(String.fromCharCode(event.charCode)) &&
event.charCode > 9 &&
!event.ctrlKey){
event.preventDefault();
}
});
最后這個改動可以確保所有默認的文本框行為不受影響。這個技術可以用來自定義是否允許在文本框中輸入某些字符。
IE 是第一個實現(xiàn)了剪切板相關的事件以及通過JavaScript訪問剪切板數(shù)據(jù)的瀏覽器,其它瀏覽器在后來也都支持了相同的事件和剪切板的訪問,后來 HTML5 將其納入了規(guī)范。以下是與剪切板相關的 6 個事件:
剪切板事件的行為及相關對象會因瀏覽器而異。在 Safari、Chrome 和 Firefox 中,beforecopy、beforecut 和 beforepaste 事件只會在顯示文本框的上下文菜單時觸發(fā),但 IE 不僅在這種情況下觸發(fā),也會在 copy、cut 和 paste 事件在所有瀏覽器中都會按預期觸發(fā)。
在實際的事件發(fā)生之前,通過beforecopy、beforecut 和 beforepaste 事件可以在向剪貼板發(fā)送或從中檢索數(shù)據(jù)前修改數(shù)據(jù)。不過,取消這些事件并不會取消剪貼板操作。要阻止實際的剪貼板操作,必須取消 copy、cut和 paste 事件。
剪貼板的數(shù)據(jù)通過 clipboardData 對象來獲取,且clipboardData 對象提供 3 個操作數(shù)據(jù)的方法:
而 clipboardData 對象在 IE 中使用 window 獲取,在 Firefox、Safari 和 Chrome 中使用 event 獲取。為防止未經(jīng)授權訪問剪貼板,只能在剪貼板事件期間訪問 clipboardData 對象;IE 會在任何時候都暴露 clipboardData 對象。因此,要兼容兩者,最好在剪貼板事件期間使用該對象。
function getClipboardText(event){
var clipboardData = (event.clipboardData || window.clipboardData);
return clipboardData.getData("text");
}
function setClipboardText (event, value){
if (event.clipboardData){
return event.clipboardData.setData("text/plain", value);
} else if (window.clipboardData){
return window.clipboardData.setData("text", value);
}
}
如果文本框只有數(shù)字,那剪貼時,就需要使用paste事件檢查剪貼板上的文本是否無效。如果無效,可以取消默認行為:
input.addEventListener("paste", (event) => {
let text = getClipboardText(event);
if (!/^\d*$/.test(text)){
event.preventDefault();
}
});
注意:Firefox、Safari和Chrome只允許在onpaste事件中訪問getData()方法。
在 JavaScript 中,可以用在當前字段完成時自動切換到下一個字段的方式來增強表單字段的易用性。比如,常用手機號分為國家好加手機號。因此,我們設置 2 個文本框:
<form>
<input type="text" name="phone1" id="phone-id-1" maxlength="4">
<input type="text" name="phone2" id="phone-id-2" maxlength="11">
</form>
當文本框輸入到最大允許字符數(shù)后,就把焦點移到下一個文本框,這樣可以增加表單的易用性并加速數(shù)據(jù)輸入。如下所示:
<script>
function tabForward(event){
let target = event.target;
if (target.value.length == target.maxLength){
let form = target.form;
for (let i = 0, len = form.elements.length; i < len; i++) {
if (form.elements[i] == target) {
if (form.elements[i+1]) {
form.elements[i+1].focus();
}
return;
}
}
}
}
let inputIds = ["phone-id-1", "phone-id-2"];
for (let id of inputIds) {
let textbox = document.getElementById(id);
textbox.addEventListener("keyup", tabForward);
}
</script>
這里,tabForward() 函數(shù)通過比較用戶輸入文本的長度與 maxLength 屬性的值來檢測輸入是否達到了最大長度。如果兩者相等,就通過循環(huán)表中的元素集合找到當前文本框,并把焦點設置到下一個元素。
注意:上面的代碼只適用于之前既定的標記,沒有考慮可能存在的隱藏字段。
HTML5 新增了一些表單提交前,瀏覽器會基于指定的規(guī)則進行驗證,并在出錯時顯示適當?shù)腻e誤信息。而驗證會基于某些條件應用到表單字段中。
表單字段中添加 required 屬性,用于標注該字段是必填項,不填則無法提交。該屬性適用于<input>、<textarea>和<select>。如下所示:
<input type="text" name="account" required>
也可以通過 JavaScript 檢測對應元素的 required 屬性來判斷表單字段是否為必填項:
let isRequired = document.forms[0].elements["account"].required;
也可以檢測瀏覽器是否支持 required 屬性:
let isRequiredSupported = "required" in document.createElement("input");
注意:不同瀏覽器處理必填字段的機制不同。Firefox、Chrome、IE 和Opera 會阻止表單提交并在相應字段下面顯示有幫助信息的彈框,而Safari 什么也不做,也不會阻止提交表單。
HTML5 為 <input> 元素增加了幾個新的 type 值。如下所示:
類型 | 描述 |
number | 數(shù)字值的輸入 |
date | 日期輸入 |
color | 顏色輸入 |
range | 一定范圍內的值的輸入 |
month | 允許用戶選擇月份和年份 |
week | 允許用戶選擇周和年份 |
time | 允許用戶選擇時間(無時區(qū)) |
datetime | 允許用戶選擇日期和時間(有時區(qū)) |
datetime-local | 允許用戶選擇日期和時間(無時區(qū)) |
電子郵件地址的輸入 | |
search | 搜索(表現(xiàn)類似常規(guī)文本) |
tel | 電話號碼的輸入 |
url | URL地址的輸入 |
這些輸入表名字段應該輸入的數(shù)據(jù)類型,并且提供了默認驗證。如下所示:
<input type="email" name="email">
<input type="url" name="homepage">
要檢測瀏覽器是否支持新類型,可以在 JavaScript 中創(chuàng)建 <input> 并設置 type 屬性,之后讀取它即可。老版本中會將我只類型設置為 text,而支持的會返回正確的值。如下所示:
let input = document.createElement("input");
input.type = "email";
let isEmailSupported = (input.type == "email");
而上面介紹的幾個如 number/range/datetime/datetime-local/date/month/week/time 幾個填寫數(shù)字的類型,都可以指定 min/max/step 等幾個與數(shù)值有關的屬性。step 屬性用于規(guī)定合法數(shù)字間隔,如 step="2",則合法數(shù)字應該為 0、2、4、6,依次類推。如下所示:
<input type="number" min="0" max="100" step="5" name="count">
上面的例子是<input>中只能輸入從 0 到 100 中 5 的倍數(shù)。
也可以使用 stepUp() 和 stepDown() 方法對 <input> 元素中的值進行加減,它倆會接收一個可選參數(shù),用于表示加減的數(shù)值。如下所示:
input.stepUp(); // 加1
input.stepUp(5); // 加5
input.stepDown(); // 減1
input.stepDown(10); // 減10
HTML5 還為文本添加了 pattern 屬性,用于指定一個正則表達式。這樣就可以自己設置 <input> 元素的輸入模式了。如下所示:
<input type="text" pattern="\d+" name="count">
注意模式的開頭和末尾分別假設有^和$。這意味著輸入內容必須從頭到尾都嚴格與模式匹配。
與新增的輸入類型一樣,指定 pattern 屬性也不會阻止用戶輸入無效內容。模式會應用到值,然后瀏覽器會知道值是否有效。通過訪問 pattern 屬性可以讀取模式:
let pattern = document.forms[0].elements["count"].pattern;
使用如下代碼可以檢測瀏覽器是否支持pattern 屬性:
let isPatternSupported = "pattern" in document.createElement("input");
HTML5 新增了 checkValidity() 方法,用來檢測表單中任意給定字段是否有效。而判斷的條件是約束條件,因此必填字段如果沒有值會被視為無效,字段值不匹配 pattern 屬性也會被視為無效。如下所示:
if (document.forms[0].elements[0].checkValidity()){
// 字段有效,繼續(xù)
} else {
// 字段無效
}
要檢查整個表單是否有效,可以直接在表單上調用checkValidity()方法。這個方法會在所有字段都有效時返回true,有一個字段無效就會返回false:
if(document.forms[0].checkValidity()){
// 表單有效,繼續(xù)
} else {
// 表單無效
}
validity 屬性會返回一個ValidityState 對象,表示 <input> 元素的校驗狀態(tài)。返回的對象包含一些列的布爾值的屬性:
因此,通過 validity 屬性可以檢查表單字段的有效性,從而獲取更具體的信息,如下所示:
if (input.validity && !input.validity.valid){
if (input.validity.valueMissing){
console.log("請指定值.")
} else if (input.validity.typeMismatch){
console.log("請指定電子郵件地址.");
} else {
console.log("值無效.");
}
}
通過指定 novalidate 屬性可以禁止對表單進行任何驗證:
<form method="post" action="/signup" novalidate>
<!-- 表單元素 -->
</form>
也可以在 JavaScript 通過 noValidate 屬性設置,為 true 表示屬性存在,為 false 表示屬性不存在:
document.forms[0].noValidate = true; // 關閉驗證
如果一個表單中有多個提交按鈕,那么可以給特定的提交按鈕添加formnovalidate 屬性,指定通過該按鈕無需驗證即可提交表單:
<form method="post" action="/foo">
<!-- 表單元素 -->
<input type="submit" value="注冊提交">
<input type="submit" formnovalidate name="btnNoValidate"
value="沒有驗證的提交按鈕">
</form>
也可以使用 JavaScript 設置 formNoValidate 屬性:
// 關閉驗證
document.forms[0].elements["btnNoValidate"].formNoValidate = true;
以上總結了 <input> 和 <textarea> 兩個元素的一些功能,主要是 <input> 元素可以通過設置 type 屬性獲取不同類型的輸入框,可以通過監(jiān)聽鍵盤事件并檢測要插入的字符來控制文本框的內容。
還有一些與剪貼板相關的事件,并對剪貼的內容進行檢測。還介紹了一些 HTML5 新增的屬性和方法和新增的更多的 <input> 元素的類型,和一些與驗證相關的屬性和方法。
一種:selenium導入瀏覽器驅動,用get方法打開瀏覽器,例如:
import time from selenium import webdriver def mac(): # browser = webdriver.Chrome() # browser = webdriver.Firefox() browser = webdriver.Ie() browser.implicitly_wait(5) browser.get('http://www.baidu.com/')
第二種:通過導入python的標準庫webbrowser打開瀏覽器,例如:
import webbrowser def mac(): # web.open(‘http://www.baidu.com’,new=0,autoraise=True) # new:0/1/2 0:同一瀏覽器窗口打開 1:打開瀏覽器新的窗口,2:打開瀏覽器窗口新的tab; autoraise=True:窗口自動增長 # web.open_new_tab(‘http://www.baidu.com’) web.open_new(‘http://www.baidu.com’)
第三種:使用Splinter模塊模塊
一、Splinter 的安裝
Splinter 的使用必修依靠 Cython、lxml、selenium 這三個軟件。所以,安裝前請?zhí)崆鞍惭b Cython、lxml、selenium。
二、Splinter 的使用
這里,我給出自動登錄 126 郵箱的案例。難點是要找到頁面的賬戶、密碼、登錄的頁面元素,這里需要查看 126 郵箱登錄頁面的源碼,才能找到相關控件的 id.
例如: 輸入密碼,密碼的文本控件 id 是 pwdInput. 可以使用browser.find_by_id() 方法定位到密碼的文本框,接著使用fill() 方法,填寫密碼。至于模擬點擊按鈕,也是要先找到按鈕控件的 id, 然后使用 click() 方法。
# coding=utf-8 import time from splinter import Browser def splinter(url): browser = Browser() # login 126 email websize browser.visit(url) # wait web element loading time.sleep(5) # fill in account and password browser.find_by_id('idInput').fill('xxxxxx') browser.find_by_id('pwdInput').fill('xxxxx') # click the button of login browser.find_by_id('loginBtn').click() time.sleep(8) # close the window of brower browser.quit() if __name__ == '__main__': websize3 ='http://www.126.com' splinter(websize3)
WebDriver簡介
selenium 從 2.0 開始集成了 webdriver 的 API,提供了更簡單,更簡潔的編程接口。selenium webdriver 的目標是提供一個設計良好的面向對象的 API,提供了更好的支持進行 web-app 測試。
打開瀏覽器
在 selenium+python 自動化測試(一)–環(huán)境搭建中,運行了一個測試腳本,腳本內容如下:
from selenium import webdriver import time browser = webdriver.Chrome() browser.get("http://www.baidu.com") print(browser.title) browser.find_element_by_id("kw").send_keys("selenium") browser.find_element_by_id("su").click() time.sleep(3) browser.close()
webdriver 是一個 Web 應用程序測試自動化工具,用來驗證程序是否如預期的那樣執(zhí)行。
webdriver.Chrome():創(chuàng)建一個 Chrome 瀏覽器的 webdriver 實例
browser.get(“http://www.baidu.com“):打開”http://www.baidu.com”頁面
browser.find_element_by_id(“kw”).send_keys(“selenium”):
找到 id 為“kw”的元素,在這個頁面上為百度首頁的搜索框,在其中輸入“selenium”
browser.find_element_by_id(“su”).click():找到 id 為“su”的元素并點擊,在這個頁面上為百度首頁的“百度一下”按鈕
browser.close():退出瀏覽器
運行腳本的第一步是打開瀏覽器,使用 webdriver.Chrome() 打開谷歌瀏覽器,如果要指定其他瀏覽器,比如要使用 Firefox 或者 IE 瀏覽器,更換瀏覽器名稱就可以了
browser = webdriver.Chrome() // 打開 Chrome 瀏覽器
browser = webdriver.Firefox() // 打開 Firefox 瀏覽器
browser = webdriver.Ie() // 打開 IE 瀏覽器
第二步操作是打開頁面,使用browser.get(url)方法來打開網(wǎng)頁鏈接,例如腳本中打開百度首頁
browser.get("http://www.baidu.com")
接下來是 **print(browser.title)**,使用browser.title獲取當前頁面的title,title就是在瀏覽器 tab 上顯示的內容,例如百度首頁的標題是“百度一下,你就知道”
瀏覽器前進后退
在當前頁面打開一個新的鏈接后,如果想回退到前一個頁面,使用如下browser.back(),相當于點擊了瀏覽器的后退按鈕
和 back 操作對應的是瀏覽器前進操作browser.forward(),相當于點擊了瀏覽器的前進按鈕
browser.back() // 回到上一個頁面
browser.forward() // 切換到下一個頁面
瀏覽器運行后,如果頁面沒有最大化,可以調用browser.maximize_window()將瀏覽器最大化,相當于點擊了頁面右上角的最大化按鈕
browser.maximize_window() // 瀏覽器窗口最大化
browser.set_window_size(800, 720) // 設置窗口大小為 800*720
瀏覽器截屏操作,參數(shù)是截屏的圖片保存路徑:
browser.get_screenshot_as_file("D:/data/test.png") 屏幕截圖保存為***
browser.refresh() // 重新加載頁面, 頁面刷新
在測試腳本運行完后,一般會在最后關閉瀏覽器,有兩種方法關閉瀏覽器,close()方法用于關閉當前頁面,quit()方法關閉所有和當前測試有關的瀏覽器窗口
browser.close() // 關閉當前頁面
browser.quit() // 關閉所有由當前測試腳本打開的頁面
<h1 class="csdn_top" line-height:38px;color:#2c3033;padding:0px="" 29px;white-space:normal;"="" style="word-wrap: break-word; color: rgb(0, 0, 0); font-family: "sans serif", tahoma, verdana, helvetica; margin-top: 0px; margin-bottom: 0px; font-size: 24px;"> 頁面元素定位
要定位頁面元素,需要找到頁面的源碼。
IE 瀏覽器中,打開頁面后,在頁面上點擊鼠標右鍵,會有“查看源代碼”的選項,點擊后就會進入頁面源碼頁面,在這里就可以找到頁面的所有元素
使用 Chrome 瀏覽器打開頁面后,在瀏覽器的地址欄右側有一個圖標,點擊這個圖標后,會出現(xiàn)許多菜單項,選擇更多工具里的開發(fā)者工具,就會出現(xiàn)頁面的源碼,不同版本的瀏覽器菜單選項可能不同,但是都會在開發(fā)者工具里找到頁面的源碼
Firefox 瀏覽器打開頁面后,在右鍵菜單里也可以找到“查看頁面源代碼”的選項。在 Firefox 中,可以使用瀏覽器自帶的插件查看定位元素,在 Firefox 的附加組件里搜索 firebug 進行下載,安裝 firebug 組件后會在瀏覽器的工具欄中多出一個小蟲子的圖標,點擊這個圖標就可以打開組件查看頁面源碼,打開后如下圖所示
以百度首頁搜索頁面為例,看一下 webdriver 定位元素的八種方式
使用id定位
在頁面源碼中找到搜索輸入框的元素定義
可以看到輸入框有一個有一個 id 的屬性,調用find_element_by_id()根據(jù) id 屬性來找到元素,參數(shù)為屬性的值
input_search = browser.find_element_by_id("kw")
使用name定位
使用find_element_by_name()根據(jù) name 屬性找到元素,參數(shù)為 name 屬性的值
搜索框有一個 name=”wd”的屬性,使用 name 查找搜索輸入框元素
input_search = browser.find_element_by_name("wd")
使用className定位
使用find_element_by_class_name()根據(jù) className 屬性找到元素,參數(shù)為 className 屬性的值
搜索框有一個 class=”s_ipt”的屬性,使用 className 查找元素
input_search = browser.find_element_by_class_name("s_ipt")
使用tagName定位
使用find_element_by_tag_name()根據(jù) tagName 屬性找到元素,參數(shù)為元素標簽的名稱
每個頁面的元素都有一個 tag,搜索框的標簽為 input,有時候一個頁面里有許多相同的標簽,所以用這種方法找到的元素一般都不準確,除非這個元素使用的標簽在這個頁面里是唯一的。一般不會使用這種方式來定位元素
input_search = browser.find_element_by_class_name("input")
使用link_text定位
頁面上都會有一些文本鏈接,點擊鏈接后會打開一個新的頁面,這些可以點擊的鏈接可以使用find_element_by_link_text來定位,百度首頁上方有如下幾個元素
例如要定位“新聞”,找到元素的代碼,有一個 href 的屬性,這是點擊后打開的頁面
新聞
使用 link_text 查找元素,參數(shù)為元素的文本信息
news = browser.find_element_by_link_text("新聞")
使用partial_link_text定位
這種方式類似于 link_text 的定位方式,如果一個元素的文本過長,不需要使用文本的所有信息,可以使用其中的部分文本就可以定位
使用 partial_link_text 查找百度首頁的“新聞”元素,參數(shù)為文本信息,可以使用全部的文本,也可以使用部分文本
news = browser.find_element_by_link_text("新聞") // 使用全部文本
news = browser.find_element_by_link_text("新") // 使用部分文本
使用css selector定位
使用 css 屬性定位元素有多種方法,可以使用元素的 id、name、className,也可以使用元素的其他屬性,如果一個元素沒有上述的幾種屬性或者定位不到時,可以使用 css 來定位
還是使用百度搜索框的實例來說明 css 定位的用法
css使用元素的id定位
css 屬性使用 id 定位時,使用 #號表示元素的 id
input_search = browser.find_element_by_css_selector("#kw") // 使用元素的 id 定位
css使用元素的class定位
css 屬性使用 class 定位時,使用. 號表示元素的 class
input_search = browser.find_element_by_css_selector(".s_ipt") // 使用元素的 class 定位
css使用元素的tag定位
css 屬性使用 tagName 定位時,直接使用元素的標簽
input_search = browser.find_element_by_css_selector("input") // 使用元素的 tagName 定位
css 使用元素的其他屬性
除了上述 3 種屬性,css 屬性可以使用元素的其他屬性定位,格式如下
input_search = browser.find_element_by_css_selector("[maxlength='255']")
使用元素的maxlength屬性定位
input_search = browser.find_element_by_css_selector("[autocomplete='off']")
使用元素的autocomplete屬性定位
可以在參數(shù)中加入元素的標簽名稱
input_search = browser.find_element_by_css_selector("input#kw") // 使用元素的 id 定位
input_search = browser.find_element_by_css_selector("input.s_ipt") // 使用元素的 class 定位
input_search = browser.find_element_by_css_selector("input[maxlength='255']") // 使用元素的 maxlength 屬性定位
input_search = browser.find_element_by_css_selector("input[autocomplete='off']") // 使用元素的 autocomplete 屬性定位
css 的層級定位
當一個元素使用自身的屬性不容易定位時,可以通過它的父元素來找到它,如果父元素也不好定位,可以再通過上元素來定位,以此類推,一直找到容易定位的父元素為止,通過層級定位到需要查找的元素
通過 Firefox 的 firebug 組件查看百度首頁的源碼
通過層級來定位搜索框
input_search = browser.find_element_by_css_selector("form#form>span:nth-child(1)>input")
input_search = browser.find_element_by_css_selector("form.fm>span:nth-child(1)>input")
搜索框的父元素為 span 標簽,span 的父元素為 form,form 有 id 和 class 屬性,可以通過這兩個屬性來定位,找到 form 元素后,form 下有多個 span 標簽,所以要使用 span:nth-child(1),表示 form 下的第一個 span 標簽,這種用法很容易理解,表示第幾個孩子,最后是 span 下的 input 標簽,span 下只有一個 input,所以就可以定位到搜索框
css邏輯運算
用一個屬性來定位元素時,如果有其他元素的屬性和此元素重復,可以組合多個屬性來功共同定位
組合多個屬性定位元素定位百度搜索框
input_search = browser.find_element_by_css_selector("input[id='kw'][name='wd']")
在元素內定義的屬性,都可以使用 css 來定位,使用其他幾種方式無法定位到元素時,可以使用 css,夠強大!
使用xpath定位
XPath 是一種在 XML 文檔中定位元素的語言。因為 HTML 可以看做 XML 的一種實現(xiàn),所以 selenium 用戶可是使用這種強大語言在 web 應用中定位元素。xpath 也可以通過元素的各種屬性定位到元素
使用元素屬性定位
input_search = browser.find_element_by_xpath("//*[@id='kw']") // 通過元素 id 查找元素
input_search = browser.find_element_by_xpath("//*[@name='wd']") // 通過元素 name 查找元素
input_search = browser.find_element_by_xpath("//*[@class='s_ipt']") // 通過元素 class 查找元素
input_search = browser.find_element_by_xpath("//*[@maxlength='255']") // 通過其他屬性查找元素
input_search = browser.find_element_by_xpath("//*[@autocomplete='off']") // 通過其他屬性查找元素
前面的 * 號表示查找所有的標簽元素,可以替換為標簽名稱,更準確的定位元素
input_search = browser.find_element_by_xpath("//input[@id='kw']") // 通過元素 id 查找元素
input_search = browser.find_element_by_xpath("//input[@name='wd']") // 通過元素 name 查找元素
input_search = browser.find_element_by_xpath("//input[@class='s_ipt']") // 通過元素 class 查找元素
input_search = browser.find_element_by_xpath("//input[@maxlength='255']") // 通過其他屬性查找元素
input_search = browser.find_element_by_xpath("//input[@autocomplete='off']") // 通過其他屬性查找元素
xpath也可以通過層級來定位,定位方式
input_search = browser.find_element_by_xpath("//input[@id='form']//span[1]//input")
browser.find_element_by_xpath("//input[@class='fm']//span[1]//input")查找效果和通過 css 的層級定位是相同的,意思是 form 元素下面的第一個 span 元素的 input 標簽子元素xpath的邏輯元素通過and運算符來組合元素屬性
input_search = browser.find_element_by_xpath("//input[@id='kw' and name='wd']")
屬性匹配
xpath 中還有一種更強大的定位方式,通過模糊匹配元素的屬性
news = browser.find_element_by_xpath("//a[contains(text(), '新聞')]")
查找text中包含"新聞"的元素
input_search = browser.find_element_by_xpath("//input[contains(@id, 'kw']")
查找id中包含"kw"的元素
input_search = browser.find_element_by_xpath("//input[starts-with(@id, 'k']")
查找id以"k"開頭的元素
input_search = browser.find_element_by_xpath("//input[ends-with(@id, 'w']")
查找id以"w"結尾的元素
input_search = browser.find_element_by_xpath("//input[matchs(@id, 'k*']")
利用正則表達式查找元素
上面介紹了查找頁面元素的八種方法,通過這些方式找到的都是單個元素,如果需要批量查找元素,還有和上面方式對應的八種復數(shù)形式
find_elements_by_id
find_elements_by_name
find_elements_by_class_name
find_elements_by_tag_name
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_css_selector
find_elements_by_xpath
這8種方法查找到的是一組元素,返回的是list,可以通過索引來操作元素
例如頁面上的復選框和單選框,或者頁面上有多個屬相相同的輸入框,這些屬性相同的一組元素,可以批量獲取,然后過濾出需要操作的元素,選擇其中的一個或者多個進行操作
通過百度首頁搜索“selenium”關鍵字,會出現(xiàn)許多搜索結果,這些搜索結果具有相同的屬性,不同的是屬性的值不同,定位這些元素時,可以使用批量定位的方法
看下面的代碼
這是搜索 selenium 關鍵字后的頁面結果,每一個搜索結果都是可點擊的鏈接,定位這些元素的方法:
search_results = browser.find_elements_by_css_selector("h.t>a")
search_results[3].click() // 通過索引點擊第 4 條搜索結果
第二個例子
checkbox
checkbox1
checkbox2
checkbox3
這個頁面上有 3 個復選框,打開后如下圖所示:
操作復選框
// 查找所有的復選框并點擊
checkboxs = browser.find_element_by_xpath('input[@type="checkbox"]')
返回一個 list
for checkbox in checkboxs:
checkbox.click()
// 點擊最后一個復選框
checkboxs[2].click()
from selenium import webdriver
browser=webdriver.Firefox()
browser.get(r’http://www.baidu.com/’)
print(‘browser attributes:’)
print(dir(browser))
elem=browser.find_element_by_id(‘kw’)
print(‘WebElement attributes:’)
print(dir(elem))
瀏覽器屬性:
driver attributes:
[‘NATIVE_EVENTS_ALLOWED’, ‘class’, ‘delattr’, ‘dict’, ‘doc’, ‘format’, ‘getattribute’, ‘hash’, ‘init’, ‘module’, ‘new’, ‘reduce’, ‘reduce_ex’, ‘repr’, ‘setattr’, ‘sizeof’, ‘str’, ‘subclasshook’, ‘weakref’, ‘_file_detector’, ‘_is_remote’, ‘_mobile’, ‘_switch_to’, ‘_unwrap_value’, ‘_wrap_value’, ‘add_cookie’, ‘application_cache’, ‘back’, ‘binary’, ‘capabilities’, ‘close’, ‘command_executor’, ‘create_web_element’, ‘current_url’, ‘current_window_handle’, ‘delete_all_cookies’, ‘delete_cookie’, ‘desired_capabilities’, ‘error_handler’, ‘execute’, ‘execute_async_script’, ‘execute_script’, ‘file_detector’, ‘find_element’, ‘find_element_by_class_name’, ‘find_element_by_css_selector’, ‘find_element_by_id’, ‘find_element_by_link_text’, ‘find_element_by_name’, ‘find_element_by_partial_link_text’, ‘find_element_by_tag_name’, ‘find_element_by_xpath’, ‘find_elements’, ‘find_elements_by_class_name’, ‘find_elements_by_css_selector’, ‘find_elements_by_id’, ‘find_elements_by_link_text’, ‘find_elements_by_name’, ‘find_elements_by_partial_link_text’, ‘find_elements_by_tag_name’, ‘find_elements_by_xpath’, ‘firefox_profile’, ‘forward’, ‘get’, ‘get_cookie’, ‘get_cookies’, ‘get_log’, ‘get_screenshot_as_base64’, ‘get_screenshot_as_file’, ‘get_screenshot_as_png’, ‘get_window_position’, ‘get_window_size’, ‘implicitly_wait’, ‘log_types’, ‘maximize_window’, ‘mobile’, ‘name’, ‘orientation’, ‘page_source’, ‘profile’, ‘quit’, ‘refresh’, ‘save_screenshot’, ‘session_id’, ‘set_page_load_timeout’, ‘set_script_timeout’, ‘set_window_position’, ‘set_window_size’, ‘start_client’, ‘start_session’, ‘stop_client’, ‘switch_to’, ‘switch_to_active_element’, ‘switch_to_alert’, ‘switch_to_default_content’, ‘switch_to_frame’, ‘switch_to_window’, ‘title’, ‘w3c’, ‘window_handles’]
調用說明:
driver. 屬性值
變量說明:
1.driver.current_url:用于獲得當前頁面的 URL
2.driver.title:用于獲取當前頁面的標題
3.driver.page_source: 用于獲取頁面 html 源代碼
4.driver.current_window_handle: 用于獲取當前窗口句柄
5.driver.window_handles: 用于獲取所有窗口句柄
函數(shù)說明:
1.driver.find_element*(): 定位元素,
2.driver.get(url): 瀏覽器加載 url。
實例:driver.get(“http//:www.baidu.com”)
3.driver.forward():瀏覽器向前(點擊向前按鈕)。
4.driver.back():瀏覽器向后(點擊向后按鈕)。
5.driver.refresh():瀏覽器刷新(點擊刷新按鈕)。
6.driver.close():關閉當前窗口,或最后打開的窗口。
7.driver.quit(): 關閉所有關聯(lián)窗口,并且安全關閉 session。
8.driver.maximize_window(): 最大化瀏覽器窗口。
9.driver.set_window_size(寬,高):設置瀏覽器窗口大小。
10.driver.get_window_size():獲取當前窗口的長和寬。
11.driver.get_window_position():獲取當前窗口坐標。
12.driver.get_screenshot_as_file(filename): 截取當前窗口。
實例:driver.get_screenshot_as_file(‘D:/selenium/image/baidu.jpg’)
13.driver.implicitly_wait(秒):隱式等待,通過一定的時長等待頁面上某一元素加載完成。
若提前定位到元素,則繼續(xù)執(zhí)行。若超過時間未加載出,則拋出 NoSuchElementException 異常。
實例:driver.implicitly_wait(10) #等待 10 秒
14.driver.switch_to_frame(id 或 name 屬性值):切換到新表單 (同一窗口)。若無 id 或屬性值,可先通過 xpath 定位到 iframe,再將值傳給 switch_to_frame()
15.driver.switch_to.parent_content(): 跳出當前一級表單。該方法默認對應于離它最近的 switch_to.frame() 方法。
16.driver.switch_to.default_content(): 跳回最外層的頁面。
17.driver.switch_to_window(窗口句柄):切換到新窗口。
18.driver.switch_to.window(窗口句柄): 切換到新窗口。
19.driver.switch_to_alert(): 警告框處理。處理 JavaScript 所生成的 alert,confirm,prompt.
20.driver.switch_to.alert(): 警告框處理。
21.driver.execute_script(js): 調用 js。
22.driver.get_cookies(): 獲取當前會話所有 cookie 信息。
23.driver.get_cookie(cookie_name):返回字典的 key 為“cookie_name”的 cookie 信息。
實例:driver.get_cookie(“NET_SessionId”)
24.driver.add_cookie(cookie_dict): 添加 cookie。“cookie_dict”指字典對象,必須有 name 和 value 值。
25.driver.delete_cookie(name,optionsString): 刪除 cookie 信息。
26.driver.delete_all_cookies(): 刪除所有 cookie 信息。
頁面元素屬性:
WebElement attributes:
[‘class’, ‘delattr’, ‘dict’, ‘doc’, ‘eq’, ‘format’, ‘getattribute’, ‘hash’, ‘init’, ‘module’, ‘ne’, ‘new’, ‘reduce’, ‘reduce_ex’, ‘repr’, ‘setattr’, ‘sizeof’, ‘str’, ‘subclasshook’, ‘weakref’, ‘_execute’, ‘_id’, ‘_parent’, ‘_upload’, ‘_w3c’, ‘clear’, ‘click’, ‘find_element’, ‘find_element_by_class_name’, ‘find_element_by_css_selector’, ‘find_element_by_id’, ‘find_element_by_link_text’, ‘find_element_by_name’, ‘find_element_by_partial_link_text’, ‘find_element_by_tag_name’, ‘find_element_by_xpath’, ‘find_elements’, ‘find_elements_by_class_name’, ‘find_elements_by_css_selector’, ‘find_elements_by_id’, ‘find_elements_by_link_text’, ‘find_elements_by_name’, ‘find_elements_by_partial_link_text’, ‘find_elements_by_tag_name’, ‘find_elements_by_xpath’, ‘get_attribute’, ‘id’, ‘is_displayed’, ‘is_enabled’, ‘is_selected’, ‘location’, ‘location_once_scrolled_into_view’, ‘parent’, ‘rect’, ‘screenshot’, ‘screenshot_as_base64’, ‘screenshot_as_png’, ‘send_keys’, ‘size’, ‘submit’, ‘tag_name’, ‘text’, ‘value_of_css_property’]
調用說明:
driver.find_element*. 屬性值
或
element=driver.find_element*
element. 屬性值
變量說明:
1.element.size: 獲取元素的尺寸。
2.element.text:獲取元素的文本。
3.element.tag_name: 獲取標簽名稱。
函數(shù)說明:
1.element.clear(): 清除文本。
2.element.send_keys(value): 輸入文字或鍵盤按鍵(需導入 Keys 模塊)。
3.element.click():單擊元素。
4.element.get_attribute(name): 獲得屬性值
5.element.is_displayed(): 返回元素結果是否可見(True 或 False)
6.element.is_selected(): 返回元素結果是否被選中(True 或 False)
7.element.find_element*(): 定位元素,用于二次定位。
網(wǎng)頁自動化最基本的要求就是要定位到各個元素,然后才能對該元素進行各種操作(輸入,點擊,清除,提交等)。
以百度搜索輸入框為例,具體說明各個定位方式的用法:
(通過 chrome 瀏覽器查看元素或者搜狐瀏覽器的 firebug 查看,即可看到 html 源碼)
注意點:第三行的元素是灰色的,該元素是不可定位到的,下方會說明。
1
2
3
4
5
6
7
8
1. 通過 id 定位元素
如果 id 不是動態(tài)的,一個頁面的 id 是唯一的。最簡單的定位方式。
使用:find_element_by_id(“id_vaule”)
實例:find_element_by_id(“kw”)
注意點:有些 id 值是動態(tài)變化的,則不能使用該方法定位。如下:id 就是動態(tài)的,每次進入頁面,該 id 都會改變
郵箱帳號或手機號
2. 通過 class_name 定位元素
classname 有可能重復哦。
使用:find_element_by_class_name(“class_name_vaule”)
實例:find_element_by_class_name(“s_ipt”)
3. 通過 tag_name 定位元素
標簽名字最容易重復,不過,當定位一組數(shù)據(jù)時,可使用。
使用:find_element_by_tag_name(“tag_name_vaule”)
實例:find_element_by_tag_name(“input”)
注意點:當定位一組元素時:可勾選一組復選框。如下:
find_element_by_tag_name(“input”)
checkbox
checkbox1
checkbox2
checkbox3
4. 通過 name 定位元素
name 有可能會重復哦。
使用:find_element_by_name(“name_vaule”)
實例:find_element_by_name(“wd”)
5. 通過 link 文字精確定位元素
登錄
使用:find_element_by_link_text(“text_vaule”)
實例:find_element_by_link_text(“登錄”)
6. 通過 link 文字模糊定位元素
使用:find_element_by_partial_link_text(“部分 text_vaule”)
實例:find_element_by_partial_link_text(“登”)
7. 通過 CSS 定位元素
CSS(Cascading Style Sheets)是一種語言,它用來描述 HTML 和 XML 文檔的表現(xiàn)。CSS 可以較為靈活的選擇控件的任意屬性,一般情況下會比 XPath 快。且語法也比較簡潔。
使用:find_element_by_css_selector(“CSS”)
實例:
7.1 通過 id 屬性定位元素
#號表示通過 id 屬性來定位元素
find_element_by_css_selector(“#kw”)
7.2 通過 class 屬性定位元素
. 號表示通過 class 屬性來定位元素
find_element_by_css_selector(“.s_ipt”)
7.3 通過標簽名定位元素
find_element_by_css_selector(“input”)
7.4 通過屬性定位元素(挺常用的)
find_element_by_css_selector(“[name=‘wd’]”)
find_element_by_css_selector(“[maxlength=‘255’]”)
屬性值包含某個值
屬性值包含 wd:適用于由空格分隔的屬性值。
find_element_by_css_selector(“[name~=‘wd’]”)
7.5 父子定位元素
查找有父親元素的標簽名為 span,它的所有標簽名叫 input 的子元素
**find_element_by_css_selector(“span>input”) **
7.6 組合定位元素
標簽名 #id 屬性值:指的是該 input 標簽下 id 屬性為 kw 的元素
find_element_by_css_selector(“input#kw”)
標簽名.class 屬性值:指的是該 input 標簽下 class 屬性為 s_ipt 的元素
find_element_by_css_selector(“input.s_ipt”)
標簽名 [屬性 =’屬性值‘]:指的是該 input 標簽下 name 屬性為 wd 的元素
find_element_by_css_selector(“input[name=‘wd’]”)
父元素標簽名 > 標簽名.class 屬性值:指的是 span 下的 input 標簽下 class 屬性為 s_ipt 的元素
find_element_by_css_selector(“span>input.s_ipt”)
多個屬性組合定位元素(挺常用的)
指的是 input 標簽下 id 屬性為 kw 且 name 屬性為 wd 的元素
find_element_by_css_selector(“input.s_ipt[name=‘wd’]”)
指的是 input 標簽下 name 屬性為 wd 且 maxlength 為 255 的元素
find_element_by_css_selector(“input[name=‘wd’][maxlength='255']”)
8. 通過 XPath 定位元素
XPath 是一種 XML 文檔中定位元素的語言。該定位方式也是比較常用的定位方式。
使用:find_element_by_xpath(“XPath”)
8.1 通過屬性定位元素
find_element_by_xpath(“// 標簽名 [@屬性 =‘屬性值’]”)
id 屬性:find_element_by_xpath(“//input[@id=‘kw’]”)
?
class 屬性:find_element_by_xpath(“//input[@class=‘s_ipt’]”)
name 屬性:find_element_by_xpath(“//input[@name=‘wd’]”)
maxlength 屬性:find_element_by_xpath(“//input[@maxlength=‘255’]”)
8.2 通過標簽名定位元素
指所有 input 標簽元素 find_element_by_xpath(“//input”)
8.3 父子定位元素
查找有父親元素的標簽名為 span,它的所有標簽名叫 input 的子元素
find_element_by_xpath(“//span/input”)
8.4 根據(jù)元素內容定位元素(非常實用)
find_element_by_xpath(“//p[contains(text(),‘京公網(wǎng)’)]”)
京公網(wǎng)安備 11000002000001 號
注:contains 的另一種用法
//**input[contains(@class,‘s’)] **說明 class 屬性包含 s 的元素。
8.5 組合定位元素
// 父元素標簽名 / 標簽名的屬性值:指的是 span 下的 input 標簽下 class 屬性為 s_ipt 的元素
find_element_by_xpath(“//span/input[@class=‘s_ipt’]”)
多個屬性組合定位(挺常用的)
指的是 input 標簽下 id 屬性為 kw 且 name 屬性為 wd 的元素
find_element_by_xpath(“//input[@class=‘s_ipt’ and @name=‘wd’]”)
指的是 p 標簽下內容包含“京公網(wǎng)”且 id 屬性為 jgwab 的元素
find_element_by_xpath(“//p[contains(text(),‘京公網(wǎng)’)and @id=‘jgwab’]”)
比較懶惰的方法:
使用搜狐瀏覽器的 firebug 工具,復制 XPath 路徑,不過這種方式對層級要求高,到時候自己再修改下。
9. 通過 By 定位元素
使用:find_element(定位的類型,具體定位方式)
定位的類型包括 By.ID,By.NAME,By.CLASS_NAME,By.TAG_NAME,By.LINK_TEXT,By.PARTIAL_LINK_TEXT,By.XPATH,By.CSS_SELECTOR
具體定位方式參考上方 1-8 的說明。
實例:find_element(By.ID,‘kw’)
注意:使用 By 定位方式,需先導入 By 類。
from selenium.webdriver.common.by import By
10. 具體實例說明
下方例子是登陸 126 郵件,然后發(fā)送郵件。
1 # coding=utf-8
2 '''
3 Created on 2016-7-27
4 @author: Jennifer
5 Project: 發(fā)送郵件
6 '''
7 from selenium import webdriver
8 import time
9
10 from test_5_2_public import Login # 由于公共模塊文件命名為 test_5_2_public
11 driver=webdriver.Firefox()
12 driver.implicitly_wait(30)
13 driver.get(r’http://www.126.com/‘) # 字符串加 r,防止轉義。
14 time.sleep(3)
15 driver.switch_to.frame(‘x-URS-iframe’)
16 #調用登錄模塊
17 Login().user_login(driver)
18 time.sleep(10)
19 #發(fā)送郵件
20 #點擊發(fā)件箱
21 #_mail_component_61_61 是動態(tài) id,所以不能用于定位
22 #driver.find_element_by_css_selector(’#_mail_component_61_61>span.oz0’).click()
23 #不能加 u"//span[contains(text(),u’寫 信’)]“,否則定位不到。
24 #以下定位是查找 span 標簽有個文本(text)包含(contains)‘寫 信’ 的元素,該定位方法重要
25 **driver.find_element_by_xpath(”//span[contains(text(),‘寫 信’)]“).click()**
26 #填寫收件人
27 #driver.find_element_by_class_name(‘nui-editableAddr-ipt’).send_keys(r’xxx@doov.com.cn’)
28 driver.find_element_by_class_name(‘nui-editableAddr-ipt’).send_keys(r’xxx@163.com’)
29 #填寫主題
30 #通過 and 連接更多的屬性來唯一地標志一個元素
31 **driver.find_element_by_xpath(”//input[@class=‘nui-ipt-input’ and @maxlength=‘256’]“).send_keys(u’自動化測試’)**
32 #填寫正文
33 #通過 switch_to_frame() 將當前定位切換到 frame/iframe 表單的內嵌頁面中
34 driver.switch_to_frame(driver.find_element_by_class_name(‘APP-editor-iframe’))
35 #在內嵌頁面中定位郵件內容位置
36 emailcontext=driver.find_element_by_class_name(‘nui-scroll’)
37 #填寫郵件內容
38** emailcontext.send_keys(u’這是第一封自動化測試郵件’)**
39 #通過 switch_to().default_content() 跳回最外層的頁面
40 #注:不要寫成 switch_to().default_content(), 否則報 AttributeError: SwitchTo instance has no call method
41 driver.switch_to.default_content()
42 #driver.switch_to.parent_frame()
43 #點擊發(fā)送
44 time.sleep(3)
45 #有可能存在元素不可見(查看元素是灰色的),會報 ElementNotVisibleException 錯誤
46 #包含發(fā)送二字的元素很多,所以還得再加上其他限制
47 #sendemails=driver.find_element_by_xpath(”//span[contains(text(),‘發(fā)送’)]“)
48 **sendemails=driver.find_element_by_xpath(”//span[contains(text(),‘發(fā)送’)and @class=‘nui-btn-text’]")**
49 time.sleep(3)
50
51 #校驗郵件是否發(fā)送成功
52 try:
53 assert ‘發(fā)送成功’ in driver.page_source
54 except AssertionError:
55 print ‘郵件發(fā)送成功’
56 else:
57 print ‘郵件發(fā)送失敗’
58
59 #調用退出模塊
60 Login().user_logout(driver)
元素定位說明:
1. 代碼 22 行,定位不到是因為 id 是動態(tài)的,所以需采取其他方式定位元素。
2. 代碼 25 行,是根據(jù)元素內容來定位的,具體用法詳看 8.4.
3. 代碼 28 行,是根據(jù) class 名來定位元素的,由于該值在該頁面上是唯一的,所以可以用它來定位。
4. 代碼 31 行,是使用邏輯運算符 and 連接更多的屬性從而唯一的標志一個元素,具體用法詳看 8.5.
5. 代碼 34 行,由于使用內嵌的 iframe 框架,所以需要先使用 switch_to_frame() 移到該表單上,才能定位該表單上的元素,非常重要,否則無論怎么定位都會報“NoSuchElementException”,找不到該元素。
6. 代碼 41 行,跳出 iframe 框架,當框架內的動作操作完畢后,需要使用 switch_to.default_content 跳出 iframe 框架, 非常重要。
7. 代碼 47 行,由于內容包括“發(fā)送”的元素中包含不可見元素(html 查看元素可以看到此行是灰色的),這樣有可能定位到不可見元素,會報“ElementNotVisibleException”。
8. 代碼 48 行,是使用邏輯運算符 and 連接更多的屬性從而唯一的標志一個元素,具體用法詳看 8.5. 這樣可以排除掉那個不可見元素。
1.Frame/Iframe 原因定位不到元素:
這個是最常見的原因,首先要理解下 frame 的實質,frame 中實際上是嵌入了另一個頁面,而 webdriver 每次只能在一個頁面識別,因此需要先定位到相應的 frame,對那個頁面里的元素進行定位。
?
解決方案:
?
如果 iframe 有 name 或 id 的話,直接使用 switch_to_frame(“name 值”) 或 switch_to_frame(“id 值”)。
?
?如下:
driver=webdriver.Firefox()
driver.get(r’http://www.126.com/’)
driver.switch_to_frame(‘x-URS-iframe’) # 需先跳轉到 iframe 框架
username=driver.find_element_by_name(‘email’)
username.clear()
如果 iframe 沒有 name 或 id 的話,則可以通過下面的方式定位:
#先定位到 iframe
elementi= driver.find_element_by_class_name(‘APP-editor-iframe’)
#再將定位對象傳給 switch_to_frame() 方法
driver.switch_to_frame(elementi)
如果完成操作后,
?可以通過 switch_to.parent_content()方法跳出當前 iframe,或者還可以通過 switch_to.default_content() 方法跳回最外層的頁面。
?
2.Xpath 描述錯誤原因:
?
由于 Xpath 層級太復雜,容易犯錯。但是該定位方式能夠有效定位絕大部分的元素,建議掌握。
解決方案:
?
2.1 可以使用 Firefox 的 firePath,復制 xpath 路徑。該方式容易因為層級改變而需要重新編寫過 xpath 路徑,不建議使用,初學者可以先復制路徑,然后嘗試去修改它。
?
2.2 提高下寫 xpath 的水平。
如何檢驗編寫的 Xpath 是否正確?編寫好 Xpath 路徑,可以直接復制到搜狐瀏覽器的 firebug 查看 html 源碼,通過 Xpath 搜索:如下紅色框,若無報錯,則說明編寫的 Xpath 路徑?jīng)]錯。
?
**find_element_by_xpath(“//input[@id=‘kw’]”) **
?
?
?3. 頁面還沒有加載出來,就對頁面上的元素進行的操作:
這種情況一般說來,可以設置等待,等待頁面顯示之后再操作,這與人手工操作的原理一樣:
3.1 設置等待時間;缺點是需要設置較長的等待時間,案例多了測試就很慢;
3.2 設置等待頁面的某個元素出現(xiàn),比如一個文本、一個輸入框都可以,一旦指定的元素出現(xiàn),就可以做操作。
3.3 在調試的過程中可以把頁面的 html 代碼打印出來,以便分析。
?
解決方案:
導入時間模塊。
import time
time.sleep(3)
4. 動態(tài) id 定位不到元素:
解決方案:
如果發(fā)現(xiàn)是動態(tài) id,直接用 xpath 定位或其他方式定位。
?
??
5. 二次定位,如彈出框登錄
?
如百度登錄彈出框登錄百度賬號,需先定位到百度彈出框,然后再定位到用戶名密碼登錄。
#coding=utf-8
'''
Created on 2016-7-20
@author: Jennifer
Project: 登錄百度賬號
'''
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get(“http://www.baidu.com/”)
time.sleep(3)
#點擊登錄:有些 name 為 tj_login 的元素為不可見的,點擊可見的那個登錄按鈕即可。
#否則會報:ElementNotVisibleException
element0=driver.find_elements_by_name(“tj_login”)
for ele0 in element0:
if ele0.is_displayed():
ele0.click()
#在登錄彈出框,需先定位到登錄彈出框
#否則會報:NoSuchElementException
element1=driver.find_element_by_class_name(“tang-content”)
element11=element1.find_element_by_id(“TANGRAM__PSP_8__userName”)
element11.clear()
element11.send_keys(“登錄名”)
element2=element1.find_element_by_id(“TANGRAM__PSP_8__password”)
element2.clear()
element2.send_keys(“密碼”)
element3=element1.find_element_by_id(“TANGRAM__PSP_8__submit”)
element3.click()
element3.submit()
try:
assert “登錄名” in driver.page_source
except AssertionError:
print “登錄失敗”
else:
print “登錄成功”
time.sleep(3)
finally:
print “測試記錄:已測試”
driver.close()
6. 不可見元素定位
如上百度登錄代碼,通過名稱為 tj_login 查找的登錄元素,有些是不可見的,所以加一個循環(huán)判斷,找到可見元素(is_displayed())點擊登錄即可。
. 事件委托
什么是事件委托?用現(xiàn)實中的理解就是:有100 個學生同時在某天中午收到快遞,但這
100 個學生不可能同時站在學校門口等,那么都會委托門衛(wèi)去收取,然后再逐個交給學生。
而在jQuery 中,我們通過事件冒泡的特性,讓子元素綁定的事件冒泡到父元素(或祖先元素)
上,然后再進行相關處理即可。
如果一個企業(yè)級應用做報表處理,表格有2000 行,每一行都有一個按鈕處理。如果用
之前的.bind()處理,那么就需要綁定2000 個事件,就好比2000 個學生同時站在學校門口等
快遞,不斷會堵塞路口,還會發(fā)生各種意外。這種情況放到頁面上也是一樣,可能導致頁面
極度變慢或直接異常。而且,2000 個按鈕使用ajax 分頁的話,.bind()方法無法動態(tài)綁定尚
未存在的元素。就好比,新轉學的學生,快遞員無法驗證他的身份,就可能收不到快遞。
//HTML 部分
<div style="background:red;width:200px;height:200px;" id="box">
<input type="button" value="按鈕" class="button" />
</div>
//使用.bind()不具備動態(tài)綁定功能,只有點擊原始按鈕才能生成
$('.button').bind('click', function () {
$(this).clone().appendTo('#box');
});
//使用.live()具備動態(tài)綁定功能,jQuery1.3 使用,jQuery1.7 之后廢棄,jQuery1.9 刪除
$('.button').live('click', function () {
$(this).clone().appendTo('#box');
});
.live()原理就是把click 事件綁定到祖先元素$(document)上,而只需要給$(document)綁
定一次即可,而非2000 次。然后就可以處理后續(xù)動態(tài)加載的按鈕的單擊事件。在接受任何
事件時,$(document)對象都會檢查事件類型(event.type)和事件目標(event.target),如果click
事件是.button,那么就執(zhí)行委托給它的處理程序。.live()方法已經(jīng)被刪除,無法使用了。需
要測試使用的話,需要引入向下兼容插件。
//.live()無法使用鏈接連綴調用,因為參數(shù)的特性導致
$('#box').children(0).live('click', function () {
$(this).clone().appendTo('#box');
});
在上面的例子中,我們使用了.clone()克隆。其實如果想把事件行為復制過來,我們只
需要傳遞true 即可:.clone(true)。這樣也能實現(xiàn)類似事件委托的功能,但原理卻截然不同。
一個是復制事件行為,一個是事件委托。而在非克隆操作下,此類功能只能使用事件委托。
$('.button').live('click', function () {
$('<input type="button" value="復制的" class="button" />').appendTo('#box');
});
當我們需要停止事件委托的時候,可以使用.die()來取消掉。
$('.button').die('click');
由于.live()和.die()在jQuery1.4.3 版本中廢棄了,之后推出語義清晰、減少冒泡傳播層次、
又支持鏈接連綴調用方式的方法:.delegate()和.undelegate()。但這個方法在jQuery1.7 版本中
被.on()方法整合替代了。
$('#box').delegate('.button', 'click', function () {
$(this).clone().appendTo('#box');
});
$('#box').undelegate('.button','click');
//支持連綴調用方式
$('div').first().delegate('.button', 'click', function () {
$(this).clone().appendTo('div:first');
});
注意:.delegate()需要指定父元素,然后第一個參數(shù)是當前元素,第二個參數(shù)是事件方
式,第三個參數(shù)是執(zhí)行函數(shù)。和.bind()方法一樣,可以傳遞額外參數(shù)。.undelegate()和.unbind()
方法一樣可以直接刪除所有事件,比如:.undelegate('click')。也可以刪除命名空間的事件,
比如:.undelegate('click.abc')。
注意:.live()和.delegate()和.bind()方法一樣都是事件綁定,那么區(qū)別也很明顯,用途上
遵循兩個規(guī)則:1.在DOM 中很多元素綁定相同事件時;2.在DOM 中尚不存在即將生成的
元素綁定事件時;我們推薦使用事件委托的綁定方式,否則推薦使用.bind()的普通綁定。
二.on、off 和one
目前綁定事件和解綁的方法有三組共六個。由于這三組的共存可能會造成一定的混亂,
為此jQuery1.7 以后推出了.on()和.off()方法徹底摒棄前面三組。
//替代.bind()方式
$('.button').on('click', function () {
alert('替代.bind()');
});
//替代.bind()方式,并使用額外數(shù)據(jù)和事件對象
$('.button').on('click', {user : 'Lee'}, function (e) {
alert('替代.bind()' + e.data.user);
});
//替代.bind()方式,并綁定多個事件
$('.button').on('mouseover mouseout', function () {
alert('替代.bind()移入移出!');
});
//替代.bind()方式,以對象模式綁定多個事件
$('.button').on({
mouseover : function () {
alert('替代.bind()移入!');
},
mouseout : function () {
alert('替代.bind()移出!');
}
});
//替代.bind()方式,阻止默認行為并取消冒泡
$('form').on('submit', function () {
return false;
});
或
$('form').on('submit', false);
//替代.bind()方式,阻止默認行為
$('form').on('submit', function (e) {
e.preventDefault();
});
//替代.bind()方式,取消冒泡
$('form').on('submit', function (e) {
e.stopPropagation();
});
//替代.unbind()方式,移除事件
$('.button').off('click');
$('.button').off('click', fn);
$('.button').off('click.abc');
//替代.live()和.delegate(),事件委托
$('#box').on('click', '.button', function () {
$(this).clone().appendTo('#box');
});
//替代.die()和.undelegate(),取消事件委托
$('#box').off('click', '.button');
注意:和之前方式一樣,事件委托和取消事件委托也有各種搭配方式,比如額外數(shù)據(jù)、
命名空間等等,這里不在贅述。
不管是.bind()還是.on(),綁定事件后都不是自動移除事件的,需要通過.unbind()和.off()
來手工移除。jQuery 提供了.one()方法,綁定元素執(zhí)行完畢后自動移除事件,可以方法僅觸
發(fā)一次的事件。
//類似于.bind()只觸發(fā)一次
$('.button').one('click', function () {
alert('one 僅觸發(fā)一次!');
});
//類似于.delegate()只觸發(fā)一次
$('#box).one('click', 'click', function () {
alert('one 僅觸發(fā)一次!');
});
三:例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <script src="js/jquery-1.8.3.js"></script> <script> $(function () { // 動態(tài)添加的不起作用 $(".me1").click(function () { alert("jQuery click綁定事件"); }); // 動態(tài)添加的不起作用 $(".me2").bind('click', function () { alert("jQuery bind綁定事件"); }); // 動態(tài)添加的起作用, jquery 1.9on取代live $('.me3').live('click', function () { // $('.me3').on('click', function () { alert("jQuery live綁定事件."); }); $('.me4').on('click', function () { alert("jQuery on綁定事件."); }); //動態(tài)添加的不起作用 $('#live').live('click', function () { alert("事件委托"); }); }); </script> <title>Title</title> </head> <body> <input type="button" value="onclick" class="me1"> <input type="button" value="bind" class="me2"> <input type="button" value="live" class="me3"> <input type="button" value="on" class="me4"> <input type="button" value="增加標簽" class="me11" onclick="addOne()"> <div id="live"> <p>AAA</p> <p>AAA</p> <p>AAA</p> <p>AAA</p> <p>AAA</p> </div> <script> function addOne() { $('body').append($('<br/><input type="button" value="動態(tài)加的onclick不起作用" class="me1">')); $('body').append($('<input type="button" value="動態(tài)加的bind不起作用" class="me2">')); $('body').append($('<input type="button" value="動態(tài)加的live不起作用" class="me3">')); $('body').append($('<input type="button" value="動態(tài)加的on不起作用" class="me4">')); } </script> </body> </html>
結果:紅線圈的點擊可以彈框
改進:使on可以委托(js加的也起作用)
先將事件綁定到body身上再過濾到.me4(也就是事件在class為me4身上)
$('body').on('click','.me4', function () { alert("jQuery on綁定事件."); });
改進:on綁定多個事件并進行委托:
參數(shù)中寫多個事件,根據(jù)事件類型進行判斷(下面效果是實現(xiàn)hover()函數(shù))
$("body").on("mouseover mouseout",'.el_unflod',function(event){ if(event.type == "mouseover"){ // 鼠標懸浮 alert("鼠標懸停") }else if(event.type == "mouseout"){ // 鼠標離開 } })
四:總結
bind:綁定事件,頁面初始化綁定,可以同時綁定多個,JS動態(tài)添加的元素不起作用。而且用unbind()去掉事件只能去掉bind綁定的事件,對于標簽種寫的onclick屬性之類的事件需要調用removeAttr刪除屬性才可以去掉事件,切記在bind事件之前去掉元素的onclick屬性等事件。
onclick: 綁定事件,頁面初始化綁定,一次綁定一個,JS動態(tài)添加的元素不起作用,bind的簡便寫法
live: 事件委托,也是事件綁定,JS動態(tài)加入的元素仍然起作用(事件委托:動態(tài)添加的元素仍然有事件)
on: 綁定事件,也是綁定事件(功能更強大),運用上述方法可以實現(xiàn)委托,動態(tài)添加的元素仍然有事件。
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。