这篇分享里面坑很多,不推荐掌握;我是爬了又掉,接着爬,接着掉坑,到现在总算是有点收获。
大家都知道,对于不同的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/')
#
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/")
#
# 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(),主要是用来判断该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())
#
# 直接传入定位方式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())
#
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
个人博客 https://blog.csdn.net/zyooooxie