1113Selenium web自動化測試經驗分享-frame切換時的定位、expected_conditions模組的frame_to_be_available_and_switch_to_it()
這篇分享裡面坑很多,不推薦掌握;我是爬了又掉,接著爬,接著掉坑,到現在總算是有點收穫。
一)frame表單切換時的定位方法
大家都知道,對於不同的iframe/frame表單中的元素是無法直接定位的。需要先結合switchTo().frame()方法切換到指定的frame/iframe中。
關於定位方法,個人建議 2點:driver.switch_to.frame(xxxx) xxxx 可以是id屬性值;或是查詢到這個元素(WebElement)。
可能很多人會說 name屬性也是可以用的,但為了方便記憶後面的frame_to_be_available_and_switch_to_it()的用法,就比較推薦那id和WebElement來定位。
關於郵箱登入時iframe的切換,有些網站(126郵箱、Yeah.net網易免費郵)和163的是類似,動態id;有些網站是沒有設定iframe,可以直接定位到輸入框;還有些是和QQ郵箱(189郵箱、21CN個人郵箱、阿里郵箱)類似,id是固定屬性值;
def test_57o1(self): """expected_conditions模組下的frame_to_be_available_and_switch_to_it()""" # frame的定位 driver.switch_to.frame(xxxx) xxxx 可以是id屬性值;或是查詢到這個元素WebElement,不可以使用locator元組 driver = webdriver.Chrome() driver.maximize_window() driver.get('https://mail.163.com/') # <iframe name="" frameborder="0" id="x-URS-iframe1542168428186.7546" scrolling="no" style="width: 100%; height: 100%; border: none; background: none;" src="https://dl.reg.163.com/webzj/v1.0.1/pub/index_dl2_new.html?cd=https%3A%2F%2Fmimg.127.net%2Findex%2F163%2Fscripts%2F2017%2Fpc%2Fcss%2F&cf=urs.7ac8b88e.css&MGID=1542168428186.7546&wdaId=&pkid=CvViHzl&product=mail163"></iframe> frame1 = self.xin_find_element(driver, By.CSS_SELECTOR, 'iframe[frameborder="0"]') # 查詢到這個元素WebElement,通過 # frame1 = 'id' # 無法嘗試 動態id driver.switch_to.frame(frame1) self.xin_find_element(driver, By.CSS_SELECTOR, 'input[placeholder="郵箱帳號或手機號碼"]').clear() self.xin_find_element(driver, By.CSS_SELECTOR, 'input[placeholder="郵箱帳號或手機號碼"]').send_keys('185') time.sleep(1) driver.quit()
上圖程式碼是處理 163郵箱登入介面iframe:動態id,推薦WebElement來定位。
def test_57o3(self): """expected_conditions模組下的frame_to_be_available_and_switch_to_it()""" # frame的定位 driver.switch_to.frame(xxxx) xxxx 可以是id屬性值;或是查詢到這個元素WebElement,不可以使用locator元組 self.driver = webdriver.Chrome() self.driver.maximize_window() self.driver.implicitly_wait(10) self.driver.get("https://mail.qq.com/") # <iframe id="login_frame" name="login_frame" height="100%" scrolling="no" width="100%" frameborder="0" src="https://xui.ptlogin2.qq.com/cgi-bin/xlogin?target=self&appid=522005705&daid=4&s_url=https://mail.qq.com/cgi-bin/readtemplate?check=false%26t=loginpage_new_jump%26vt=passport%26vm=wpt%26ft=loginpage%26target=&style=25&low_login=1&proxy_url=https://mail.qq.com/proxy.html&need_qr=0&hide_border=1&border_radius=0&self_regurl=http://zc.qq.com/chs/index.html?type=1&app_id=11005?t=regist&pt_feedback_link=http://support.qq.com/discuss/350_1.shtml&css=https://res.mail.qq.com/zh_CN/htmledition/style/ptlogin_input24e6b9.css"></iframe> # frame11 = "login_frame" # 通過 但是無法確定是id 還是name屬性值來做的判斷 # frame11 = (By.XPATH, '//iframe[@frameborder="0"]') # 報錯 Message: unknown error: invalid 'id' frame11 = self.driver.find_element(By.XPATH, '//iframe[@frameborder="0"]') # 查詢到這個元素WebElement 通過 self.driver.switch_to.frame(frame11) self.driver.find_element_by_id("switcher_plogin").click() # 賬號密碼登入 self.driver.find_element_by_id("u").clear() self.driver.find_element_by_id("u").send_keys('987654') time.sleep(1) self.driver.quit()
上圖程式碼是處理 QQ郵箱登入介面的iframe:推薦id定位和WebElement。
二)expected_conditions模組下的frame_to_be_available_and_switch_to_it()
expected_conditions模組下有個類frame_to_be_available_and_switch_to_it(),主要是用來判斷該frame是否可以switch進去。
單獨使用:可傳入定位方式id屬性值,成功的話就返回True並switch進去,否則 返回False;也可傳入locator元組或WebElement,成功定位的話就返回True並switch進去,否則 會報錯,找不到定位。
def test_57o4(self):
"""expected_conditions模組下的frame_to_be_available_and_switch_to_it()"""
# frame_to_be_available_and_switch_to_it() 判斷該frame是否可以switch進去
# 如果直接傳入定位方式id,可以的話就返回True並switch進去,否則返回False
# 也可傳入locator元組或WebElement,可以的話就返回True並switch進去,否則報錯,找不到定位
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(5)
self.driver.get("https://mail.qq.com/")
print('0', time.ctime())
# <iframe id="login_frame" name="login_frame" height="100%" scrolling="no" width="100%" frameborder="0" src="https://xui.ptlogin2.qq.com/cgi-bin/xlogin?target=self&appid=522005705&daid=4&s_url=https://mail.qq.com/cgi-bin/readtemplate?check=false%26t=loginpage_new_jump%26vt=passport%26vm=wpt%26ft=loginpage%26target=&style=25&low_login=1&proxy_url=https://mail.qq.com/proxy.html&need_qr=0&hide_border=1&border_radius=0&self_regurl=http://zc.qq.com/chs/index.html?type=1&app_id=11005?t=regist&pt_feedback_link=http://support.qq.com/discuss/350_1.shtml&css=https://res.mail.qq.com/zh_CN/htmledition/style/ptlogin_input24e6b9.css"></iframe>
# 直接傳入定位方式id
# print(EC.frame_to_be_available_and_switch_to_it('login_frame')(self.driver)) # 正確的 返回True並switch進去
# print(EC.frame_to_be_available_and_switch_to_it('login_frame123')(self.driver)) # 錯誤的 返回False
# 傳入locator元組
# print(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, 'iframe[frameborder="0"][width="100%"]'))(self.driver)) # 正確的 返回True並switch進去
# print(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, 'iframe[frameborder="10"]'))(self.driver)) # 報錯 Message: no such element
# 傳入WebElement
abcd = self.driver.find_element(By.XPATH, '//iframe[@height="100%" and @scrolling="no"]') # 正確的 返回True並switch進去
# abcd = self.driver.find_element(By.XPATH, '//iframe[@height="1000%" and @scrolling="no123"]') # 報錯 Message: no such element
print(EC.frame_to_be_available_and_switch_to_it(abcd)(self.driver))
self.driver.find_element_by_id("switcher_plogin").click()
self.driver.find_element_by_id("u").clear()
self.driver.find_element_by_id("u").send_keys('987654')
self.driver.switch_to.default_content()
print('1', time.ctime())
time.sleep(1)
self.driver.quit()
class frame_to_be_available_and_switch_to_it(object):
""" An expectation for checking whether the given frame is available to
switch to. If the frame is available it switches the given driver to the
specified frame.
"""
def __init__(self, locator):
self.frame_locator = locator
def __call__(self, driver):
try:
if isinstance(self.frame_locator, tuple):
driver.switch_to.frame(_find_element(driver,
self.frame_locator))
else:
driver.switch_to.frame(self.frame_locator)
return True
except NoSuchFrameException:
return False
原始碼沒怎麼看懂 = =
分享下 自己琢磨出來的經驗:
frame_to_be_available_and_switch_to_it()和顯式等待結合後,傳入定位方式id、locator元組,可以的話就返回True並switch進去,否則 超時報錯 selenium.common.exceptions.TimeoutException;傳入WebElement,可以的話就返回True並switch進去,否則找不到定位報錯 selenium.common.exceptions.NoSuchElementException: Message: no such element。
(報錯型別不同)
def test_57o7(self):
"""expected_conditions模組下的frame_to_be_available_and_switch_to_it()"""
# frame_to_be_available_and_switch_to_it() 判斷該frame是否可以switch進去
# 如果直接傳入定位方式id,可以的話就返回True並switch進去,否則返回False
# 也可傳入locator元組或WebElement,可以的話就返回True並switch進去,否則報錯,找不到定位
# 和顯式等待結合後,傳入定位方式id、locator元組,可以的話就返回True並switch進去,否則 超時報錯 selenium.common.exceptions.TimeoutException
# 和顯式等待結合後,傳入WebElement,可以的話就返回True並switch進去,否則報 找不到定位報錯 selenium.common.exceptions.NoSuchElementException: Message: no such element
# 此外 WebElement因為是去定位某個元素,定位不到會報錯,應該放在try裡面,放在try前面 會執行到那一步就直接報錯;
# 定位某個元素的WebElement放在try裡面,但又用不到那個顯式等待的!在執行前就已經報錯 找不到元素。
# 對比 錯誤的locator元組(放在裡面、外面都可以,因為不查詢)是用的當前的顯式等待! 建議都是放在try裡面
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(5)
self.driver.get("https://webmail30.189.cn/w2/") # 189郵箱
print('start', time.ctime())
# <iframe class="login_iframe" id="iframeLogin" allowtransparency="true" frameborder="0" scrolling="no" src="/w2/logon/UnifyLogin.do?t=1542157418806"></iframe>
print(EC.frame_to_be_available_and_switch_to_it('iframeLogin')(self.driver))
self.driver.find_element(By.XPATH, '//input[@name="userName" or @id="userName"]').send_keys('987')
self.driver.switch_to.default_content()
print('0', time.ctime())
time.sleep(1) # 執行速度太快
WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it('iframeLogin'), '失敗')
self.driver.find_element(By.XPATH, '//input[@id="userName"]').clear()
self.driver.switch_to.default_content()
print('00', time.ctime())
time.sleep(1)
print(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, 'iframe[class="login_iframe"]'))(self.driver))
self.driver.find_element(By.XPATH, '//input[@name="userName" or @id="userName"]').send_keys('654')
self.driver.switch_to.default_content()
print('1', time.ctime())
time.sleep(1)
WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, 'iframe[class="login_iframe"]')), '失敗')
self.driver.find_element(By.XPATH, '//input[@id="userName"]').clear()
self.driver.switch_to.default_content()
print('10', time.ctime())
time.sleep(1)
ABCD = self.driver.find_element(By.ID, 'iframeLogin')
print(EC.frame_to_be_available_and_switch_to_it(ABCD)(self.driver))
self.driver.find_element(By.XPATH, '//input[@id="userName"]').send_keys('321')
self.driver.switch_to.default_content()
print('2', time.ctime())
time.sleep(1)
ABCD1 = self.driver.find_element(By.ID, 'iframeLogin')
WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it(ABCD1), '失敗')
self.driver.find_element(By.XPATH, '//input[@id="userName"]').clear()
self.driver.switch_to.default_content()
print('20', time.ctime())
try:
ABCD11 = self.driver.find_element(By.ID, 'iframeLogin111111')
WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it(ABCD11), '失敗')
self.driver.find_element(By.XPATH, '//input[@id="userName"]').clear()
self.driver.find_element(By.XPATH, '//input[@id="userName"]').send_keys('666')
self.driver.switch_to.default_content()
except BaseException as e11:
print(e11) # Message: no such element: Unable to locate element: {"method":"id","selector":"iframeLogin111111"}
print('3', time.ctime()) # 5秒的隱式等待
try:
ABCD22 = (By.CSS_SELECTOR, 'iframe11111111[class="login_iframe"]')
WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it(ABCD22), '失敗')
self.driver.find_element(By.XPATH, '//input[@id="userName"]').clear()
self.driver.find_element(By.XPATH, '//input[@id="userName"]').send_keys('666666')
self.driver.switch_to.default_content()
except BaseException as e111:
print(e111)
print('4', time.ctime())
try:
WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it('22222222'), '沒能成功')
self.driver.find_element(By.XPATH, '//input[@id="userName"]').clear()
self.driver.find_element(By.XPATH, '//input[@id="userName"]').send_keys('6666666666')
self.driver.switch_to.default_content()
except BaseException as e11111:
print(e11111)
print('5', time.ctime())
# WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it('22222222'), '沒能成功')
# 報錯 selenium.common.exceptions.TimeoutException: Message: 沒能成功
# WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, 'iframe11111111[class="login_iframe"]')), '失敗')
# 報錯 selenium.common.exceptions.TimeoutException: Message: 失敗
# WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it(self.driver.find_element(By.ID, 'iframeLogin111111')), '失敗')
# 報錯 selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"id","selector":"iframeLogin111111"}
print('end', time.ctime())
time.sleep(1)
self.driver.quit()
實際看我用例的名稱就知道寫的好幾個,但是因為此次分享在實際工作中不常見,所以就分享了一個。
交流技術 歡迎+QQ 153132336 zy
歡迎關注 微信公眾號:紫雲小站