Selenium—iframe的操作

什么是iframe?

<iframe> 标签是一个内联框架,即用来在当前 HTML 页面中嵌入另一个文档的,且所有主流浏览器都支持iframe标签。

简单说,就是在一个页面内,又嵌入了一个页面,看似是一个页面,但是在selenium中,无法对iframe内元素进行直接定位

示例:

  打印出网易云音乐-云音乐热歌榜中前10首歌曲名

我们先定位出排行榜中前10首歌曲的元素

简单说一下,为什么使用红色框内的 id 信息

  1. 定位元素,一般我们会直接先定位到某一首歌曲信息,此时我们发现该歌曲的 id 属性值为一长串数字,此时我们有必要怀疑,该数值是随机生成的

  2. 验证:复制该元素的 id 属性值,刷新界面,重新查看该元素的 id 属性值,是否与刚刚复制下来的内容一致,如不一致,则验证了第 1 条的假设

  3. 验证第 1 条之后,此时我们需要做的就是往上层找,看看是否存在我们能直接定位到元素的属性值

  4. 父元素的 class 属性值,可以直接准确定位,则该元素可用

  5. 再往上找,蓝色框内的 id 属性值可以看出,均存在乱序内容,我们第一反应就应该为 该属性值 不可用

  6. 再往上找到 id = song-list-pre-cache 的属性值,可以看出是有序的,可直接定位

  7. 此时,第 4 条与第 6 条均可实现精准定位,作者这里是习惯性的使用了 id 属性

 查找到元素后,我们直接撸代码,打印出歌曲信息即可

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10)
# 抓取排行榜信息
driver.get('https://music.163.com/#/discover/toplist?id=3778678')

div = driver.find_elements_by_css_selector('#song-list-pre-cache .m-table-rank tbody tr:nth-child(-n+10) b')

# 使用for循环,获取到每首歌曲的元素,并打印出该元素的 text 属性值


for one in div:
    print(one.get_attribute('title')) 

driver.quit()

输出结果:

# 在漫长的隐式等待(10s)中,输出结果为空,并没有报错,这是为什么呢?

知识点

  1. find_elements :注意 s ,复数;返回的为列表形式,如果为查找到元素,则返回空列表,无报错信息

  2. find_element : 定位某一元素,如果指定的时间内,未找到该元素,则会抛出错误

修改一下我们的代码:

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10)
# 抓取排行榜信息
driver.get('https://music.163.com/#/discover/toplist?id=3778678')

songList = driver.find_element_by_id('song-list-pre-cache')
div = songList.find_elements_by_css_selector('.m-table-rank tbody tr:nth-child(-n+10) b')

# 使用for循环,获取到每首歌曲的元素,并打印出该元素的 text 属性值
for one in div:
    print(one.get_attribute('title')) 
driver.quit()

看一看我们的输出结果:

阿西吧,果然报错了,错在第8行:songList = driver.find_element_by_id('song-list-pre-cache');但是我们明明可以在浏览器中定位到该元素啊?

 

定位iframe

定位没有问题,那么我们就需要考虑是不是 iframe 在搞鬼!

重新查看一下我们的元素信息

从红色的框框内,我们看到了 id="song-list-pre-cache" 的 父元素 和 子元素,我们往前找,蓝色框内,存在了一个 #g_iframe 的父元素

点击蓝色区域,让我们看一下 iframe 

我们可以确定了,排行榜的歌曲信息,是写在一个 iframe 框架内,那我们该如何操作 iframe 中的元素呢?

 

切换iframe

  • 通过 id 切换,且 id 唯一

    • driver.switch_to.frame('g_iframe')
  • 通过 name 切换,且 name 唯一

    • driver.switch_to.frame('contentFrame')

 

  • 若无 id 和 name ,则需要先定位到 iframe ,然后再切换

    1. iframe = driver.find_elements_by_tag_name('iframe')[0]
    2. driver.switch_to.frame(iframe)

切回主文档

  我们切入到 iframe 框架内进行操作后,需要再次回到主文档区域进行操作,就必须要切回主文档

  • driver.switch_to_default_content()

多嵌套iframe

  既然主文档可以嵌套 iframe ,那么 iframe 同样可以嵌套 iframe ,那么存在这种多重嵌套我们要怎么处理呢?

 

<html>
    <iframe id="frame1">
        <iframe id="frame2" / >
    </iframe>
</html>

  如果我们需要操作 iframe2 中的元素,我们需要切换 2 次

  • 先从主文档切换至 iframe1
    • driver.switch_to.frame('iframe1')
  • 再从 iframe1 切换至 iframe2
    • driver.switch_to.frame('iframe2')

  

  我们切到 iframe2 中操作完之后,需要回到 iframe1 中进行操作,selenium 提供了一个更好的方式,避免了从 iframe2 切到主文档 再切到 iframe1 的复杂

  • 从 iframe2 切回至 iframe1

    • driver.switch_to.parent_frame()

 

让我们来完成之前的需求:

 

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10)
# 抓取排行榜信息
driver.get('https://music.163.com/#/discover/toplist?id=3778678')

# 定位到 iframe 的元素
iframe = driver.find_elements_by_tag_name('iframe')[0]

# 切到 iframe 框架内
driver.switch_to.frame(iframe)

songList = driver.find_element_by_id('song-list-pre-cache')
div = songList.find_elements_by_css_selector('.m-table-rank tbody tr:nth-child(-n+10) b')

# 使用for循环,获取到每首歌曲的元素,并打印出该元素的 text 属性值
for one in div:
    print(one.get_attribute('title'))

# 切到 iframe 的上一层,即为主文档
driver.switch_to.parent_frame()

# 打印主文档的一段内容
meta = driver.find_element_by_css_selector('meta[name="description"]')
print('\n'+meta.get_attribute('content'))

driver.quit()

 

输出结果如下:

心如止水
多想在平庸的生活拥抱你
归去来兮
晚安
我曾
四块五
出山
Monsters
那个女孩
像鱼

网易云音乐是一款专注于发现与分享的音乐产品,依托专业音乐人、DJ、好友推荐及社交功能,为用户打造全新的音乐生活。

 

 

  

 

参考文档:

  selenium切换到iframehttps://www.cnblogs.com/xiaoxiaolvdou/p/9316805.html

 

posted @ 2019-05-29 11:26  落晨  阅读(1372)  评论(0编辑  收藏  举报