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(r‘d:\webdrivers\chromedriver.exe‘)
# WebDriver 實例對象的get方法 可以讓瀏覽器打開指定網址
driver.get(‘https://www.baidu.com‘)
# 根據id選擇元素,返回的就是該元素對應的WebElement對象
element = driver.find_element_by_id(‘kw‘)
# 通過該 WebElement對象,就可以對頁面元素進行操作了
# 比如輸入字符串到 這個 輸入框裏
element.send_keys(‘黑羽魔巫宗\n‘)
其中
driver = webdriver.Chrome(r‘d:\webdrivers\chromedriver.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 屬性選擇元素。
大家請訪問這個網址 http://www.python3.vip/doc/tutorial/python/code/sample1.html
這個網址對應的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(r‘d:\webdrivers\chromedriver.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(r‘d:\webdrivers\chromedriver.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 webdriver
driver = webdriver.Chrome(r‘d:\webdrivers\chromedriver.exe‘)
driver.get(‘https://www.baidu.com‘)
element = driver.find_element_by_id(‘kw‘)
element.send_keys(‘黑羽魔巫宗\n‘)
# 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 webdriver
driver = webdriver.Chrome(r‘d:\webdrivers\chromedriver.exe‘)
driver.get(‘https://www.baidu.com‘)
element = driver.find_element_by_id(‘kw‘)
element.send_keys(‘黑羽魔巫宗\n‘)
# 等待 2 秒
from time import sleep
sleep(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 webdriver
driver = webdriver.Chrome()
# 設置最大等待時長為 10秒
driver.implicitly_wait(10)
driver.get(‘https://www.baidu.com‘)
element = driver.find_element_by_id(‘kw‘)
element.send_keys(‘黑羽魔巫宗\n‘)
element = driver.find_element_by_id(‘1‘)
print (element.text)
大家再運行一下,可以發現不會有錯誤了。
訪問原文網站,看 下一篇 操作web界面 2
文章轉自 白月黑羽教Python
Web自動化 - 選擇操作元素 1