浏览过程中,图片中的内容可能太小,无法看清,可以>右键>在新标签中打开
Outline
项目原因,需要用selenium实现模拟登陆、模拟上传文件,自然就需要模拟点击【上传】按钮;
模拟点击之前需要通过selenium提供的“方法”去定位到要点击的元素;
模拟登陆过程中,全程都可以定位到需要点击的元素,但登陆后需要定位点击【上传】按钮时问题来了;
元素明明在那放着,就是定位不到,这个问题困扰了一下午还没解决,最终走到了iframe这个一步,才得以解决。
什么是iframe
解决问题之前很有必要先了解下什么是iframe:
HTML内联框架元素 <iframe> 表示嵌套的浏览上下文,有效地将另一个HTML页面嵌入到当前页面中。在HTML 4.01中,文档可能包含头部和正文,或头部和框架集,但不能包含正文和框架集。
但是,<iframe>可以在正常的文档主体中使用。每个浏览上下文都有自己的会话历史记录和活动文档。包含嵌入内容的浏览上下文称为父浏览上下文。顶级浏览上下文(没有父级)通常是浏览器窗口。
iframe是HTML三种结构中的框结构,框结构中还有另外两个元素:
frameset
和frame
,但它们都已废弃,不再推荐使用。
HTML中iframe展示
如下图所示,右侧代码中圈出来的iframe标签,渲染之后在前端显示的就是左侧圈出来的区域;
也就是此iframe嵌套在该HTML框架中。
如何说明iframe是一个独立部分、是被嵌套到HTML框架内部的?见下图:
将iframe标签中的 src=/default/research/redirect 复制出来在地址栏进行链接替换,会发现此时的页面只有iframe独立部分,之前页面中的banner不见了。
参考:
selenium定位元素
selenium模拟登陆操作
部分代码:
def auto_login(self): # 获取浏览器窗口对象 driver = webdriver.Chrome() # 打开浏览器进入指定地址 driver.get('https://ycjq.95358.com/research') # selenium进行元素定位、填写内容 driver.find_element_by_name("CyLoginForm[username]").send_keys("你的账号") driver.find_element_by_name("CyLoginForm[pwd]").send_keys("你的密码") # 这里图像识别获取验证码 def valideCode(): # driver.find_element_by_name("valideCode").send_keys("") # selenium进行元素定位、模拟点击(登陆) time.sleep(10) driver.find_element_by_id("btnSubmit").click()
页面分析:
根据标签的“name”、“id”等,进行元素定位,然后模拟操作。
执行上述代码,你会发现会自动打开浏览器,进入指定地址,然后会自动进行账号密码的输入,并且自动点击“登陆”;
然后会进行登陆后的页面跳转。
整个流程很正确也很合理,但页面跳转之后再进行元素定位、模拟点击时就有坑了。
切换iframe
上一步“模拟登陆”时,HTML页面并不涉及 iframe 标签,但登陆过后就含有 iframe标签了。
所以再通过selenium进行模拟点击时就要切换iframe了。
在用selenium定位页面元素的时候会遇到定位不到的问题,明明元素就在那儿,用firebug也可以看到,就是定位不到,问题很有可能就出在iframe上。
问题复现
错误代码复现:
def auto_login(self): # 获取浏览器窗口对象 driver = webdriver.Chrome() # 打开浏览器进入指定地址 driver.get('https://ycjq.95358.com/research') # selenium进行元素定位、填写内容 driver.find_element_by_name("CyLoginForm[username]").send_keys("你的账号") driver.find_element_by_name("CyLoginForm[pwd]").send_keys("你的密码") # selenium进行元素定位、模拟点击(登陆) time.sleep(10) driver.find_element_by_id("btnSubmit").click() time.sleep(10) # 定位到“上传”按钮 driver.find_element_by_id('notebook_list_info').click()
可以确定下图的元素定位位置无误,理应可以通过selenium模拟点击的,但模拟点击之后一直提示找不到标签:
问题解决
问题出现之后,进行相关问题搜索,五花八门,各种解决方案,用了一下午,各种尝试,最终确定问题出在iframe。
只有切换到iframe里面,selenium才能定位到 iframe里面的元素。
切换iframe
selenium提供了switch_to.frame()方法来切换frame
switch_to.frame(reference)
注意:
可能你会这样写:switch_to_frame(),但会发现,这段代码被加上“删除线”了;
原因是这个方法已经out了,之后可能被废弃,建议switch_to.frame()
switch_to.frame(reference)中的reference是传入的参数,用来定位frame,可以传入id、name、index以及selenium的WebElement对象。
如下图中的 id、name。
如果没有id、name属性的化,可以通过xpath匹配WebElement对象进行定位。
正确定位代码:
def auto_login(self): # 获取浏览器窗口对象 driver = webdriver.Chrome() # 打开浏览器进入指定地址 driver.get('https://ycjq.95358.com/research') # selenium进行元素定位、填写内容 driver.find_element_by_name("CyLoginForm[username]").send_keys("你的账号") driver.find_element_by_name("CyLoginForm[pwd]").send_keys("你的密码") # 这里图像识别获取验证码 def valideCode(): # driver.find_element_by_name("valideCode").send_keys("") # selenium进行元素定位、模拟点击(登陆) time.sleep(10) driver.find_element_by_id("btnSubmit").click() time.sleep(10) # 切换iframe driver.switch_to.frame('research') driver.find_element_by_id('notebook_list_info').click()
执行代码之后即可正确模拟点击”上传“按钮。
参考:https://blog.csdn.net/huilan_same/article/details/52200586