Web自動化 - 選擇操作元素 1

文章轉自 白月黑羽教Python

所有的 UI (用戶界面)操作 的自動化,都需要選擇界面元素。

選擇界面元素就是:先讓程序能找到你要操作的界面元素。

先找到元素,才能操作元素。

選擇元素的方法

程序 怎麼才能找到 要操作的 web 界面元素?

方法就是要根據這個 web 元素的 特徵 去選擇。

元素的特徵怎麼查看?

可以使用瀏覽器的開發者工具欄幫我們查看、選擇web 元素。

請大家安裝最新版的Chrome瀏覽器(可以百度搜索下載)。

用chrome瀏覽器訪問百度,按F12後,點擊下圖箭頭處的Elements標籤,即可查看頁面對應的HTML 元素

然後,再點擊 最左邊的圖標,如下所示

之後,滑鼠在界面上點擊哪個元素,就可以查看該元素對應的html標籤內容了。

比如,前面的圖的高亮處,就是百度搜索輸入框對應的input元素。

根據 元素的id 屬性選擇元素

大家仔細看上面的 input元素 內容,會發現它有一個屬性叫id。

我們可以把 id 想像成元素的編號, 是用來在html中標記該元素的。 根據規範, 如果元素有id ,這個id 必須是當前html中唯一的。

所以如果元素有id, 根據id選擇元素是最簡單高效的方式。

下面的代碼,就是用selenium 訪問百度,並且在輸入框中搜索 黑羽魔巫宗

大家可以運行一下看看。

from selenium import webdriver# 創建 WebDriver 實例對象,指明使用chrome瀏覽器驅動driver = webdriver.Chrome(rd:webdriverschromedriver.exe)# WebDriver 實例對象的get方法 可以讓瀏覽器打開指定網址driver.get(https://www.baidu.com)# 根據id選擇元素,返回的就是該元素對應的WebElement對象element = driver.find_element_by_id(kw)# 通過該 WebElement對象,就可以對頁面元素進行操作了# 比如輸入字元串到 這個 輸入框里element.send_keys(黑羽魔巫宗
)

其中

driver = webdriver.Chrome(rd:webdriverschromedriver.exe)

返回的是 WebDriver 實例對象,我們可以通過這個實例對象來操控瀏覽器,比如 打開網址、選擇界面元素等。

下面的代碼

driver.find_element_by_id(kw)

就是使用 WebDriver 實例對象 的方法find_element_by_id, 這個方法就是 根據輸入框元素的 id 值 『kw』 來選擇到元素。

選擇到元素之後, find_element_by_id 方法會返回一個 WebElement, 我們通過這個對象就可以操控對應的界面元素。

比如 send_keys 方法就是在對應的元素中輸入字元串,

而 click 方法就可以點擊該元素。

根據 class屬性、tag名 選擇元素

除了根據元素的id ,我們還可以根據元素的class 屬性選擇元素。

大家請訪問這個網址 python3.vip/doc/tutoria

這個網址對應的html內容 有如下的部分

<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <title>白月黑羽測試網頁1</title> <style> .animal {color: red;} </style> </head> <body> <div class="plant"><span>土豆</span></div> <div class="plant"><span>洋蔥</span></div> <div class="plant"><span>白菜</span></div> <div class="animal"><span>獅子</span></div> <div class="animal"><span>老虎</span></div> <div class="animal"><span>山羊</span></div> </body></html>

所有的植物元素都有個class屬性 值為 plant。

所有的動物元素都有個class屬性 值為 animal。

如果我們要選擇所有的 動物, 就可以使用方法 find_elements_by_class_name

driver.find_elements_by_class_name(animal)

注意

find_elements_by_class_name 方法返回的是找到的符合條件的所有元素 (這裡有3個元素), 放在一個列表中返回。

而如果我們使用 find_element_by_class_name (注意少了一個s) 方法, 就只會返回第一個元素。

大家可以運行如下代碼看看。

from selenium import webdriver# 創建 WebDriver 實例對象,指明使用chrome瀏覽器驅動driver = webdriver.Chrome(rd:webdriverschromedriver.exe)# WebDriver 實例對象的get方法 可以讓瀏覽器打開指定網址driver.get(http://www.python3.vip/doc/tutorial/python/code/sample1.html)# 根據 class name 選擇元素,返回的是 一個列表# 裡面 都是class 屬性值為 animal的元素對應的 WebElement對象elements = driver.find_elements_by_class_name(animal)# 取出列表中的每個 WebElement對象,列印出其text屬性的值# text屬性就是該 WebElement對象對應的元素在網頁中的文本內容for element in elements: print(element.text)

如果我們把

elements = driver.find_elements_by_class_name(animal)

去掉一個s ,改為

element = driver.find_element_by_class_name(animal) print(element.text)

那麼返回的就是第一個class 屬性為 animal的元素, 也就是這個元素

<div class="animal"><span>獅子</span></div>

類似的,我們可以通過方法 find_elements_by_tag_name ,選擇所有的tag名為 div的元素,如下所示

from selenium import webdriver# 創建 WebDriver 實例對象,指明使用chrome瀏覽器驅動driver = webdriver.Chrome(rd:webdriverschromedriver.exe)# WebDriver 實例對象的get方法 可以讓瀏覽器打開指定網址driver.get(http://www.python3.vip/doc/tutorial/python/code/sample1.html)# 根據 tag name 選擇元素,返回的是 一個列表# 裡面 都是 tag 名為 div 的元素對應的 WebElement對象elements = driver.find_elements_by_tag_name(div)# 取出列表中的每個 WebElement對象,列印出其text屬性的值# text屬性就是該 WebElement對象對應的元素在網頁中的文本內容for element in elements: print(element.text)

等待界面元素出現

在我們進行網頁操作的時候, 有的元素內容不是可以立即出現的, 可能會等待一段時間。

比如 百度搜索一個詞語, 我們點擊搜索後, 瀏覽器需要把這個搜索請求發送給百度伺服器, 百度伺服器進行處理後,把搜索結果返回給我們。

只是通常百度伺服器的處理比較快,我們感覺好像是立即出現了搜索結果。

百度搜索的每個結果 對應的界面元素 其ID 分別是數字 1, 2 ,3, 4 。。。

如下

那麼我們可以試試用如下代碼 來將 第一個搜索結果裡面的文本內容 列印出來

from selenium import webdriverdriver = webdriver.Chrome(rd:webdriverschromedriver.exe)driver.get(https://www.baidu.com)element = driver.find_element_by_id(kw)element.send_keys(黑羽魔巫宗
)# id 為 1 的元素 就是第一個搜索結果element = driver.find_element_by_id(1)# 列印出 第一個搜索結果的文本字元串print (element.text)

如果大家去運行一下,就會發現有如下異常拋出

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"id","selector":"1"}

NoSuchElementException 的意思就是在當前的網頁上 找不到該元素, 就是找不到 id 為 1 的元素。

為什麼呢?

因為我們的代碼執行的速度比 百度伺服器響應的速度 快。

百度還沒有來得及 返回搜索結果,我們就執行了如下代碼

element = driver.find_element_by_id(1)

在那短暫的瞬間, 網頁上是沒有用 id為1的元素的 (因為還沒有搜索結果呢)。自然就會報告錯誤 id為1 的元素不存在了。

那麼怎麼解決這個問題呢?

很多聰明的讀者可以想到, 點擊搜索後, 用sleep 來 等待幾秒鐘, 等百度伺服器返回結果後,再去選擇 id 為1 的元素, 就像下面這樣

from selenium import webdriverdriver = webdriver.Chrome(rd:webdriverschromedriver.exe)driver.get(https://www.baidu.com)element = driver.find_element_by_id(kw)element.send_keys(黑羽魔巫宗
)# 等待 2 秒from time import sleepsleep(2)# 2 秒 過後,再去搜索element = driver.find_element_by_id(1)# 列印出 第一個搜索結果的文本字元串print (element.text)

大家可以運行一下,基本是可以的,不會再報錯了。

但是這樣的方法 有個很大的問題,就是設置等待多長時間合適呢?

這次百度網站反應可能比較快,我們等了一秒鐘就可以了。

但是誰知道下次他的反應是不是還這麼快呢?百度也曾經出現過伺服器癱瘓的事情。

可能有的讀者說,我乾脆sleep比較長的時間, 等待 20 秒, 總歸可以了吧?

這樣也有很大問題,假如一個自動化程序裡面需要10次等待, 就要花費 200秒。 而可能大部分時間, 伺服器反映都是很快的,根本不需要等20秒, 這樣就造成了大量的時間浪費了。

Selenium提供了一個更合理的解決方案,是這樣的:

當發現元素沒有找到的時候, 並不 立即拋出 找不到元素的異常。

而是周期性(每隔半秒鐘)重新尋找該元素,直到該元素找到,

或者超出指定最大等待時長,這時才 拋出異常(如果是 find_elements 則是返回空列表)。

Selenium 的 Webdriver 對象 有個方法叫 implicitly_wait

該方法接受一個參數 就是指定的 最大等待時長。

如果我們 加入如下代碼

driver.implicitly_wait(10)

那麼後續所有的 find_element 或者 find_elements 之類的方法調用 都會採用上面的策略。

就是找不到元素 每隔 半秒鐘 再去界面上查看一次, 直到找到該元素, 或者 過了10秒鐘 最大時長。

這樣,我們的百度搜索的例子的最終代碼如下

from selenium import webdriverdriver = webdriver.Chrome()# 設置最大等待時長為 10秒driver.implicitly_wait(10)driver.get(https://www.baidu.com)element = driver.find_element_by_id(kw)element.send_keys(黑羽魔巫宗
)element = driver.find_element_by_id(1)print (element.text)

大家再運行一下,可以發現不會有錯誤了。

訪問原文網站,看 下一篇 操作web界面 2

文章轉自 白月黑羽教Python

推薦閱讀:

有哪些值得推薦的Python學習網站?
用Python玩GTA 5—使用OpenCV讀取遊戲面面
向csv新增內容
mark down, word up

TAG:Python | Selenium | Web應用 |