selenium+python实现1688登录 —— iframe中元素获取
1. 背景
- 在1688网站登录时,无法通过 browser.find_element_by_xpath 直接获取到用户名和密码的输入框。
- 从网页源代码分析,发现这个网页是一个iframe嵌套的模式,所以按照传统的方式无法定位到表单元素。
2. 环境
- python 3.6.1
- 系统:win7
- IDE:pycharm
- 安装过chrome浏览器
- 配置好chromedriver
- selenium 3.7.0
3. 分析过程
3.1. 进入1688登录页面,分析网页结构。
- 也就是说,登录框是以子页面(iframe)的方式嵌入在主页面中的。
- 所以按照以下的方式是无法获得“密码登录”这个超链接的。
# 寻找使用用户名和密码登陆的链接,并点击
links = browser.find_elements_by_tag_name("a")
for link in links:
# print(f"linkText1 = {link.text}, link = {link}")
if link.text == '密码登录':
link.click()
break
- 需要在此之前将focus由default content转到这个frame:
# 切换到登录框frame
# 这种是网页中有frame嵌套,而且没有标记,不知道frame的name,通过源代码,知道是第一个iframe
browser.switch_to.frame(browser.find_elements_by_tag_name("iframe")[0])
- 切换到frame的方式(browser.switch_to.frame)有三种,引用源代码中的注释:
"""
Switches focus to the specified frame, by index, name, or webelement.
:Args:
- frame_reference: The name of the window to switch to, an integer representing the index,
or a webelement that is an (i)frame to switch to.
:Usage:
driver.switch_to.frame('frame_name') # iframe标签的name属性
driver.switch_to.frame(1)
driver.switch_to.frame(driver.find_elements_by_tag_name("iframe")[0])
"""
3.2. 点击密码登录,分析网页结构。
- 此时网页结构并未发生变化:
# 输入用户名和密码
userNameInput = browser.find_element_by_xpath("//input[@name='TPL_username']")
userNameInput.clear()
userNameInput.send_keys(userName)
userPassword = browser.find_element_by_xpath("//input[@name='TPL_password']")
userPassword.clear()
userPassword.send_keys("ancode2017")
time.sleep(5)
# 敲enter键
userPassword.send_keys(Keys.RETURN)
time.sleep(30)
- 此时大概率情况下,会直接通过。小概率会进行滑块验证码 + 手机短信验证。
3.3. 进入短信验证码页面,分析网页结构。
此时网页结构又发生了变化:
分析源码可以看到手机验证输入框处于 Main ——> iframe ——> iframe两层嵌套之内。
- 所以,需要再次改变focus
# 首先切换到新的 frame,这个是原来登录frame下又嵌套了一层frame
# 当前browser的focus已经是中间层的frame,所以这里只要再switch一层即可
browser.switch_to.frame(browser.find_elements_by_tag_name("iframe")[0])
# 寻找发送手机验证码按钮
messageSendButton = browser.find_element_by_xpath("//button[@id='J_GetCode']")
print(f"messageSendButton = {messageSendButton}")
messageSendButton.click()
# 手动获得手机验证码,并输入到程序中
messageConfirm = input("Enter your message confirm:")
print(f"messageConfirm = {messageConfirm}")
# 输入手机验证码
messageConfirmInput = browser.find_element_by_xpath("//input[@id='J_Checkcode']")
messageConfirmInput.clear()
messageConfirmInput.send_keys(messageConfirm)
# 提交
submit = browser.find_element_by_xpath("//button[@type='submit']")
submit.click()
# 进入页面
time.sleep(60)
4. 总结
- 如果一个页面只有一个head, 一个body,那么可以直接使用browser.find_element_by_xxxx( )查找页面中的任何一个元素。
- 假如页面中存在< iframe ………….. /iframe>的使用,使得一个html页面中包含多个子html页面。
- 在这种情况下,使用browser.find_element_by_xxxx( )查找页面某个元素,如果元素是属于主html的,那么可以查找到。
- 如果该元素是属于某个子的< iframe ………….. /iframe>下,使用browser.find_element_by_xxxx( )获取页面元素会失败。要想成功,首先要弄清楚该元素所属的frame的,并将focus切换到该frame
- 方法是:先使用browser.switch_to.frame( ) , 然后再使用 browser.find_element_by_xxxx( )查找元素。
- 操作完以后,如果想返回主页面,那么使用:browser.switch_to.default_content( ) 。
- 操作完以后,如果想返回上一级frame,那么使用:browser.switch_to.parent_frame( ) 。