文章目录
前言
前面做了一个自动打卡的小程序,基本可以实现上班签到,下班签退的任务,并白嫖了CSDN的服务器作为数据收发的基础。在继续优化功能的同时,解决了selenium使用过程中的小坑点。
- 定位以及切换frame(iframe)
- webdriver爬虫#document问题
一、Python+Selenium
具体的环境配置可以参考之前的文章。
二、webdriver中#document问题
如果直接通过获取到的xpath定位的话
driver = webdriver.Firefox()
driver.get(url)
driver.find_element_by_xpath()
print(driver .page_source)
会发现#document下的内容为空。换言之,根本没有定位到相应的元素,而且#document下的内容也没有爬取到。观察发现,#docoment的上一级是iframe标签,相当于内嵌了一段HTML到原本的代码中,根据之前新打开标签页的经验:当driver重新打开一个标签页,需要通过如下代码切换到子标签页中。
current_windows = browser.window_handles
# browser.switch_to_window(current_windows[1])
self.__driver.switch_to.window(current_windows[0])
self.__driver.maximize_window()
因此对于iframe来说,也是同样的,需要切换到iframe中才能定位到相应的元素完成爬取。很多人在用selenium定位页面元素的时候,通过浏览器获取的Xpath元素就是定位不到,这种情况很有可能是frame在搞鬼。
2.1 切换frame的方法
-
selenium提供了switch_to.frame()方法来切换frame
switch_to.frame(reference) switch_to_frame(reference)
提到switch_to_frame(),这个方法已经out了,之后很有可能会不支持,建议的写法是switch_to.frame(),反正到时候多尝试几次,总有一个是可以的。reference是传入的参数,用来定位frame,可以传入id、name、index以及selenium的WebElement对象。例如:
from selenium import webdriver driver = webdriver.Firefox() driver.switch_to.frame(0) # 1.用frame的index来定位,第一个是0 driver.switch_to.frame("frame1") # 2.用id来定位 driver.switch_to.frame("myframe") # 3.用name来定位 driver.switch_to.frame(driver.find_element_by_tag_name("iframe")) # 4.用WebElement对象来定位
-
从frame中切回主文档(switch_to.default_content())
切到frame中之后,我们便不能继续操作主文档的元素,这时如果想操作主文档内容,则需切回主文档。driver.switch_to.default_content()
-
嵌套frame的操作(switch_to.parent_frame()),有时候我们会遇到嵌套的frame,如下:
<html> <iframe id="frame1"> <iframe id="frame2" / > </iframe> </html>
从主文档切到frame2,一层层切进去:
driver.switch_to.frame("frame1") driver.switch_to.frame("frame2")
-
所以只要善用以下三个方法,遇到frame分分钟搞定:
driver.switch_to.frame(reference) driver.switch_to.parent_frame() driver.switch_to.default_content()
2.2 切换#docment的方法
有了刚刚的切换iframe的基础,就可以获取到iframe中的内容了,此时如果通过xpath的方法去定位document中的内容,结果却任然是失败的。网上找到了如下方法,实测有用:在get(url)之后使用
driver.switch_to_default_content()
frame = driver.find_elements_by_tag_name('iframe')[0]
driver.switch_to_frame(frame)
先跳转到iframe中,然后再driver.find_element_by_xpath即可,至于这种跳转方法为什么可以,俺也搞不清楚。
2.3 切换#docment的子#document方法
这次遇到的是#document中套着#document套着#document,无论多少级,切换的方法和iframe的嵌套类似,一层一层切换下去
# 切换到子#document
frame1 = browser3.find_elements_by_tag_name('iframe')[0]
browser3.switch_to_frame(frame1)
# 切换到孙子#document
frame2 = browser3.find_elements_by_tag_name('iframe')[0]
browser3.switch_to_frame(frame2)
#print(browser1.page_source)
# 切换到mainFrame这个iframe中的#document==0
browser3.switch_to_default_content()
frame = browser3.find_elements_by_tag_name('iframe')[0]
browser3.switch_to_frame(frame)
# 切换到子#document
frame1 = browser3.find_elements_by_tag_name('iframe')[0]
browser3.switch_to_frame(frame1)
# 切换到孙子#document
frame2 = browser3.find_elements_by_tag_name('iframe')[0]
browser3.switch_to_frame(frame2)
# 点击确定,确定按钮在上一级iframe
browser3.switch_to.parent_frame()
# 点击确定按钮,再回到第一级
browser3.switch_to.default_content()