[Web] 使用 Selenium web driver 作 web automation
在 使用 Selenium IDE 來做簡單的 web automation 這篇文章中,
曾經提過一個用 Selenium IDE 來做出自動匯出痞客邦網誌的自動化程式~
不過那個麻煩的點是還要自己開啟 Firefox + Selenium IDE,
選擇那個 test case 執行才行,有點不便…
要能更好的自動化,就需要用上 Selenium web driver 了~
它可以讓我們直接用程式 (如 python) 的方式,指揮 Selenium 來操控瀏覽器~
1. 安裝 Selenium web driver for Firefox
Python bindings for selenium 是一個讓 python 可以操控 Selenium 的套件,
裡面會含有給 Firefox 用的 web driver
直接用 pip install selenium 就能安裝了:
testuser@localhost ~ $ pip install selenium Downloading/unpacking selenium Downloading selenium-2.45.0.tar.gz (2.6MB): 2.6MB downloaded Running setup.py (path:/private/var/folders/qg/l7_9f_4x707br0gghptzfs0cjr0hkh/T/pip_build_jeff_lai/selenium/setup.py) egg_info for package selenium Installing collected packages: selenium Running setup.py install for selenium Successfully installed selenium Cleaning up...
要確認安裝成功,只要看看 python 能不能 import selenium 這個 module 就行了:
testuser@localhost ~ $ python
>>> import selenium
>>>
2. 將 Selenium IDE 的 test case 匯出成 python 程式
在 Selenium IDE 選擇 File > Export Test Case As > Python 2 / unittest / WebDriver,
就可以將 test case 匯出成 python 的程式:
匯出後的 python 程式是一個 unittest 程式,在 setUp() 裡建立了 Firefox() 物件,
而主要的邏輯是在 test_xxx() 那個函式裡,例如我匯出的是像下面這樣:
def setUp(self): self.driver = webdriver.Firefox() self.driver.implicitly_wait(30) self.base_url = "https://www.pixnet.net/" self.verificationErrors = [] self.accept_next_alert = True def test_export_pixnet_webdriver(self): driver = self.driver driver.get("http://panel.pixnet.cc/logout") driver.get(self.base_url + "/?done=http%3A%2F%2Fephrain.pixnet.net%2Fblog") driver.find_element_by_id("input-username").clear() driver.find_element_by_id("input-username").send_keys("myusername") driver.find_element_by_id("input-password").clear() driver.find_element_by_id("input-password").send_keys("mypassword") driver.find_element_by_id("login-send").click() driver.get("http://panel.pixnet.cc/blog/export") driver.find_element_by_id("next-button").click() # ERROR: Caught exception [Error: locator strategy either id or name must be specified explicitly.] self.assertEqual(u"備份檔產生完成,請按右下角「下載備份檔」下載您的備份檔", self.close_alert_and_get_its_text()) driver.find_element_by_id("export-status-submit").click()
匯出的程式裡有一段詭異的「ERROR: Caught exception [Error: locator strategy either id or name must be specified explicitly.]」
跟 Selenium IDE 裡的步驟對照一下,應該是 assertAlert 這個動作~
試著利用程式原有的 is_alert_present() 函式來檢查是否 alert 視窗已經出現,
可是它在 Firefox 上總是傳回 True…
如果是改成 self.driver.switch_to_alert().text 會丟出 NoAlertPresentException,
問題是第二次呼叫時就會莫名其妙的卡住,動彈不得…
在網路上查了一下,似乎也有不少人遇到 alert 會卡住的問題,
試了各種不同的方法,最後發現在 Chrome 上沒有這個問題!!
那就改用 Chrome 版的 web driver 吧~
3. 安裝給 Chrome 用的 Selenium web driver
可以到 ChromeDriver 官網看看說明,
我抓的是目前最新的 Chrome driver v2.14 for Mac,
下載後是一個 chromedriver_mac32.zip 檔案,
解開後把 chromedriver 放到 $PATH 找的到的目錄下 (例如 /usr/local/bin)~
unzip chromedriver_mac32.zip -d /usr/local/bin/
4. 改用 Chrome 版的 web driver
要 Selenium 改用 Chrome 來開啟網頁,只要把 setUp() 裡面初始化 self.driver 那行改掉就行了,
原本是 webdriver.Firefox() 改成 webdriver.Chrome():
def setUp(self): # self.driver = webdriver.Firefox() self.driver = webdriver.Chrome() self.driver.implicitly_wait(30) self.base_url = "https://www.pixnet.net/" self.verificationErrors = [] self.accept_next_alert = True
將這 python 程式再執行一次,在 Firefox 上會卡住的 self.driver.switch_to_alert().text,
在 Chrome 上就執行的很正常,因此我加了下面這段,
來判斷 alert 視窗是不是已經出現了:
while True: try: self.driver.switch_to_alert().text break except: print "Waiting for alert window..." time.sleep(1)
下面提供完整的 python 程式供有興趣的人參考囉~
# -*- coding: utf-8 -*- from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import Select from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoAlertPresentException import unittest, time, re class ExportPixnetWebdriver(unittest.TestCase): def setUp(self): # self.driver = webdriver.Firefox() self.driver = webdriver.Chrome() self.driver.implicitly_wait(30) self.base_url = "https://www.pixnet.net/" self.verificationErrors = [] self.accept_next_alert = True def test_export_pixnet_webdriver(self): driver = self.driver driver.get("http://panel.pixnet.cc/logout") driver.get(self.base_url + "/?done=http%3A%2F%2Fephrain.pixnet.net%2Fblog") driver.find_element_by_id("input-username").clear() driver.find_element_by_id("input-username").send_keys("myuser") driver.find_element_by_id("input-password").clear() driver.find_element_by_id("input-password").send_keys("mypassword") driver.find_element_by_id("login-send").click() driver.get("http://panel.pixnet.cc/blog/export") driver.find_element_by_id("next-button").click() while True: try: self.driver.switch_to_alert().text break except: print "Waiting for alert window..." time.sleep(1) self.assertEqual(u"備份檔產生完成,請按右下角「下載備份檔」下載您的備份檔", self.close_alert_and_get_its_text()) driver.find_element_by_id("export-status-submit").click() print "Download file within 10 seconds..." time.sleep(10) def is_element_present(self, how, what): try: self.driver.find_element(by=how, value=what) except NoSuchElementException, e: return False return True def is_alert_present(self): try: self.driver.switch_to_alert() except NoAlertPresentException, e: return False return True def close_alert_and_get_its_text(self): try: alert = self.driver.switch_to_alert() alert_text = alert.text if self.accept_next_alert: alert.accept() else: alert.dismiss() return alert_text finally: self.accept_next_alert = True def tearDown(self): self.driver.quit() self.assertEqual([], self.verificationErrors) if __name__ == "__main__": unittest.main()
One thought on “[Web] 使用 Selenium web driver 作 web automation”
您好,
因您文章受用良深,請教您一問題如附檔視訊,
https://drive.google.com/file/d/1IpDs-O3F9jNniXJT3qfa9dmlRKbDmO2p/view?usp=sharing
環境為FF54&SideeX is an extended version of Selenium IDE,
CLICK指令可點到輸入欄位之ID,可是相同欄位相同ID,TYPE指令卻是未見任何動作,也就是未自動打字,WHY?
麻煩您了
lrd@hust.edu.tw