Frame及窗口切换

目的:了解Html中框架的概念,掌握使用WebDriver 对象的 switch_to 属性进行框架转换,方便在selenium中定位到框架中的元素进行操作。同时,明确窗口句柄的定义,掌握应用带有窗口句柄参数的switch_to 属性,够实现窗口间的跳转。

要求:在pycharm 环境下完成实验目的中所述各项任务。

条件:win7/10、pycharm、selenium4.4.0

内容及步骤 : 

一个浏览器文档窗口中一般只能显示一个网页文件,但是,使用框架标签就可以将一个浏览器文档窗口分割成多个子窗口,每个子窗口中都可以显示一个独立的网页文件。

框架元素非常的特殊,是由英文Frame翻译过来的,代表浏览器文档窗口中的一个子窗口。在html语法中,frame 元素或者 iframe元素的内部会包含一个被嵌入的另一份html文档。

每个框架都含有可以链接到其他多个网页的超链接条目,访问者单击这些超链接条目后,可以将超链接指向的网页文件显示在另一个指定的框架中。如果要求在单个应用窗口中显示一个以上的网页,就可以使用Frame(或iFrame)框架。iframe用来定义一个内联框架,在html文档里嵌入另一个html文档。iframe包含的内容和页面是一个整体,但是frame包含的内容是一个独立的区域。

在使用selenium打开一个网页时,我们的操作范围默认是当前的 html ,并不包含被嵌入的html文档里面的内容。如果我们要操作被嵌入的 html 文档 中的元素, 就必须把操作范围切换到被嵌入的文档中。

 我们这里使用 WebDriver对象的switch_to属性转换,形如:

driver.switch_to.frame(frame_reference)

其中frame_reference可以是frame元素的name或者 ID属性及 frame 所对应的 WebElement 对象。

方法: 

  • 根据frame元素的id进行切换:

       例如frame元素的 id 为‘frame1’,切换语句为:

driver.switch_to.frame('frame1')
  • 根据frame元素的name属性值进行切换:

       例如frame元素的name属性值为‘innerFrame’ ,切换语句为:

driver.switch_to.frame('innerFrame')
  • 根据frame元素所对应的 WebElement 对象进行切换:

       例如frame元素所对应的 WebElement 对象标签名是iframe,切换语句为:

driver.switch_to.frame(driver.find_element(By.TAG_NAME, 'iframe')
  • 将WebDriver 对象切换回默认区域:
driver.switch_to.default_content()

 练习基于白月黑羽的自动化学习网站:frame切换/窗口切换 | 白月黑羽

 练习1:登录 https://cdn2.byhy.net/files/selenium/sample2.html

①切换进入iframe框架,在其中选择所有动物类型并输出动物名称,

②切换回外层默认部分,点击“外部按钮”,

③输出网页中新出现的“你点击了外部按钮”文本信息。关闭浏览器。

提交代码:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By

# 导入驱动 括号里可填驱动的具体路径
driver = webdriver.Chrome()
# 练习一
# 打开网页
driver.get("https://cdn2.byhy.net/files/selenium/sample2.html")
#  进入内嵌Frame
driver.switch_to.frame('innerFrame')
elements = driver.find_elements(By.CLASS_NAME, 'animal')
# 循环输出元素
for element in elements:
    print(element.text)
#  再次返回到默认区域
driver.switch_to.default_content()

driver.find_element(By.ID, 'outerbutton').click()

show = driver.find_element(By.ID, 'add')
show1 = show.find_element(By.TAG_NAME, 'li')
print(show1.text)
# 关闭页面
driver.quit()

 窗口切换:

引入:在针对网站的实际操作中,经常会点击一个链接或者按钮,在新窗口里面打开一个新网址,并操控新窗口里面的元素。用Selenium写的自动化程序,也要模拟实际操作,不能只在当前页面中执行,需要从 WebDriver对象对应的老窗口,切换到要进行自动化操作的新窗口中,转换语法为:driver.switch_to.window(handle),其中参数handle传入的是指定窗口的句柄。

 具体方法:

WebDriver对象有window_handles 属性,这是一个列表对象,里面包括了当前浏览器里面所有的窗口句柄(相当于对应网页窗口的一个ID)。我们可以使用一个循环,依次获取 driver.window_handles 里面的所有句柄对象,并且调用 driver.switch_to.window(handle) 方法,切入到每个窗口中。然后根据 标题栏 之类的属性值判断是否为想要切换到的窗口。

从跳转后的新窗口,返回原窗口的简便方法是:开始处在原窗口时,保存原窗口句柄,在要切换回来时,仍然使用Webdriver对象的switch_to属性的 window方法,把原窗口句柄作为参数进行传递即可。

 例如:

# mainWindow变量保存当前窗口的句柄 
mainWindow = driver.current_window_handle
    
for handle in driver.window_handles: 
    # 先切换到一个窗口 
    driver.switch_to.window(handle) 
    # 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口 
    if '百度一下,你就知道' in driver.title: 
        # 如果是,那么这时候WebDriver对象就是对应的窗口,正好,跳出循环, 
        Break

…………  # 省略要在选定窗口中执行的操作

# 通过前面保存的原窗口句柄,切换回原窗口 
driver.switch_to.window(mainWindow)

练习2:在练习1主要操作过程和关闭浏览器操作之间,添加以下操控步骤:

①登录 https://cdn2.byhy.net/files/selenium/sample3.html,

②输出当前窗口的标题栏文本,点击打开新窗口的链接,

③切换到新窗口并输出新窗口的标题栏文本,

返回原窗口,点击“功能按钮”,输出网页中新出现的“你点击了外部按钮”。

 提交代码:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
# 练习一
driver.get("https://cdn2.byhy.net/files/selenium/sample2.html")

# frame1 =driver.switch_to.frame(driver.find_element(By.CSS_SELECTOR ,'.frame1'))
driver.switch_to.frame('innerFrame')
elements = driver.find_elements(By.CLASS_NAME, 'animal')

for element in elements:
    print(element.text)

driver.switch_to.default_content()

driver.find_element(By.ID, 'outerbutton').click()

show = driver.find_element(By.ID, 'add')
show1 = show.find_element(By.TAG_NAME, 'li')
print(show1.text)
# driver.quit()
time.sleep(2)
# 练习二
driver.get('https://cdn2.byhy.net/files/selenium/sample3.html')
mainWindow = driver.current_window_handle
print(driver.title)

link = driver.find_element(By.TAG_NAME, 'a').click()
# driver.switch_to.window()
time.sleep(2)
for handle in driver.window_handles:
    # 先切换到该窗口
    driver.switch_to.window(handle)
    # 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
    if 'Bing' in driver.title:
        # 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
        break
print(driver.title)

driver.switch_to.window(mainWindow)
driver.find_element(By.ID, 'outerbutton').click()
show2 = driver.find_element(By.ID, 'add')
show3 = show2.find_element(By.TAG_NAME, 'li')
print(show3.text)
driver.quit()

练习3:以管理员身份登录 http://127.0.0.1:8047/mgr/sign.html,用户名 :byhy 密码: 88888888。点击页脚处 链接 白月黑羽教学使用,点击访问官网;然后在新打开的 白月黑羽教学网页,获取页眉导航菜单中所有教程类目(可以调用webdriver对象的maximize_window()方法最大化窗口,以便显示所有菜单 );随后再回到 白月SMS系统网页,点击退出登录。预期结果为:成功登录后,完成上述操作,验证导航菜单名,依次为:Python基础、Python进阶、Qt图形界面、Django、自动化测试、性能测试、HTML/CSS、JS语言、JS Web。验证回到登录界面(可以根据webdriver对象的current_url属性判断是否进入登录页面)。

提交代码:

from selenium import webdriver
from time import sleep
from selenium.webdriver.common.by import By

# 创建 WebDriver 实例对象,指明使用chrome浏览器驱动
wd = webdriver.Chrome()
# WebDriver 实例对象的get方法 可以让浏览器打开指定网址
wd.get('http://127.0.0.1:8047/mgr/sign.html')
# 设置最大等待时长为 10秒
wd.implicitly_wait(10)
#最大化窗口
wd.maximize_window()
#登录白月黑羽系统
elementuser = wd.find_element(By.ID,'username')
elementuser.send_keys('byhy')
elementpass = wd.find_element(By.ID, 'password')
elementpass.send_keys('88888888')
elementbutton=wd.find_element(By.TAG_NAME, 'button')
elementbutton.click()
#点击外链之前先保存本页面句柄
mainwindow=wd.current_window_handle
#点击外链
wd.find_element(By.CSS_SELECTOR ,'.pull-right>[href="http://www.python3.vip"]').click()
#寻找所选外链
for handle in wd.window_handles:
    wd.switch_to.window(handle)
    if '白月黑羽教Python' in wd.title:
        break
wd.maximize_window()
barelements=wd.find_elements(By.CSS_SELECTOR, 'li.nav-item span')
for barelement in barelements:
    print(barelement.text)
wd.switch_to.window(mainwindow)
wd.find_element(By.CSS_SELECTOR, 'span.hidden-xs').click()
wd.find_element(By.CSS_SELECTOR, '.pull-right a.btn').click()
sleep(2)
if wd.current_url=="http://127.0.0.1/mgr/sign.html":
    print("成功退出登录")

附加练习4:打开网易云音乐https://music.163.com/网站,点击“排行榜”,在左侧菜单栏中点击“新歌榜”,在歌曲列表中找出排名上升最多和下降最多的歌曲名称及歌手,输出格式为:

排名上升最多:歌曲名:XXX   歌手:YYY(若有上升位次相同的换行列出)

排名下降最多:歌曲名:XXX   歌手:YYY(若有下降位次相同的换行列出)

提交代码: 

#xml是XML和HTML的解析器,其主要功能是解析和提取XML和HTML中的数据
from lxml import etree
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get('https://music.163.com/')
# 隐式等待 等待页面加载成功
driver.implicitly_wait(3)
# 点击排行榜
rank_btn = driver.find_element(By.CSS_SELECTOR,"body ul >li+li>a")
rank_btn.click()
#iframe标签定位
driver.switch_to.frame('g_iframe')
#点击新歌榜
new_song_btn = driver.find_element(By.CSS_SELECTOR,".f-cb > li+li").click()
page_text = driver.execute_script("return document.documentElement.outerHTML")
#获取页面
html = etree.HTML(page_text)
up_rank_list =[]
down_rank_list =[]
up_song_name_list=[]
up_artist_list =[]
down_song_name_list=[]
down_artist_list=[]
#获取每个列表
song_rows = html.xpath('//tbody/tr')
#获取每个列表里的元素并添加到数组
for row in song_rows:
    up_rank = row.xpath('.//span[@class="ico u-icn u-icn-73 s-fc9"]/text()')
    down_rank = row.xpath('.//span[@class="ico u-icn u-icn-74 s-fc10"]/text()')
    song_name = row.xpath(".//b/@title")
    span = row.xpath(".//td[@class=' s-fc3']/span[@class='u-dur ']/text()")
    artist = row.xpath(".//div[@class='text']/span/@title")
    if up_rank != []:
        str1 = ''.join(up_rank)
        up_rank_list.append(int(str1))   # 最大上升数组
        song_name_str = ''.join(song_name)
        up_song_name_list.append(song_name_str)
        artist_str =''.join(artist)
        up_artist_list.append(artist_str)
    if down_rank !=[]:
        str2 = ''.join(down_rank)
        down_rank_list.append(int(str2)) # 最大下降数组
        song_name_str = ''.join(song_name)
        down_song_name_list.append(song_name_str)
        artist_str =''.join(artist)
        down_artist_list.append(artist_str)
t1 = max(up_rank_list)
num = len(up_rank_list)
n=0
for i in up_rank_list:
    if i ==t1:
        n=n+1
if n!=1:
    for j in range(num):
        if up_rank_list[j] == t1:
            print("排名上升最多:"+up_song_name_list[j]+" \t 歌手:"+up_artist_list[j])
else:
    a1 = up_rank_list.index(t1)
    print("排名上升最多:"+up_song_name_list[a1]+" \t 歌手:"+up_artist_list[a1])

t2 = max(down_rank_list)
num2 = len(down_rank_list)
# print(num)
n1=0
for i1 in down_rank_list:
    if i1 ==t1:
        n1=n1+1
if n1!=1:
    for j1 in range(num2):
        if down_rank_list[j1] == t2:
            print("排名下降最多:"+down_song_name_list[j1]+" \t 歌手:"+down_artist_list[j1])
else:
    a2 = down_rank_list.index(t2)
    print("排名下降最多:"+down_song_name_list[a2]+" \t 歌手:"+down_artist_list[a2])
# 退出页面
driver.quit()


当然方法不是唯一的,在此针对练习4再添加两个不同的解决方法:

方法一: 

driver = webdriver.Chrome()
driver.get('https://music.163.com/')
driver.find_element(By.CSS_SELECTOR, "#g_nav2 li:nth-child(2) a").click()
driver.switch_to.frame(driver.find_element(By.ID, 'g_iframe'))
driver.find_element(By.CSS_SELECTOR, '#toplist li:nth-child(2) a').click()
item = driver.find_element(By.CSS_SELECTOR, '#song-list-pre-cache table tbody')
up_table =[]
lown_table =[]
num=0
sleep(1)
for i in item.find_elements(By.TAG_NAME, 'tr'):
    ranking = i.find_element(By.CSS_SELECTOR, '.rk span')
    name = i.find_element(By.CSS_SELECTOR, 'td:nth-child(2) .ttc a b')
    singer = i.find_element(By.CSS_SELECTOR, 'td:nth-child(4) div')
    class_list = ranking.get_attribute('class').split(" ")
    temp=[(ranking.text),name.get_attribute('title'),singer.get_attribute('title')]
    if 'u-icn-73' in class_list:
        up_table.append(temp)
    elif 'u-icn-74' in class_list:
        lown_table.append(temp)
up_table.sort(key=lambda x:int(x[0]), reverse=True)
lown_table.sort(key=lambda x:int(x[0]), reverse=True)
for table in [up_table, lown_table]:
    for i in table:
        if i[0] == table[0][0]:
            print(f"排名{['上升','下降'][num]}最多: 歌曲名:{i[1]} 歌手:{i[2]}")
        else:
            break
        num +=1

方法二: 

driver = webdriver.Chrome()
driver.get('https://music.163.com/')
driver.find_element(By.CSS_SELECTOR,'[href="/discover/toplist"]').click()
driver.switch_to.frame('contentFrame')
driver.find_element(By.CSS_SELECTOR, '[href="/discover/toplist?id=3779629"]').click()
maxnum=[]
minnum=[]
count1 =[]
count2=[]
count =0
list_all = driver.find_elements(By.CSS_SELECTOR, '.rk>span')
for n in list_all:
    count = count+1
    txt = n.get_attribute("className").split(" ")[-1]
    if txt == "s-fc9":
        maxnum.append(int(n.text))
        count1.append(count)
    elif txt == "s-fc10":
        minnum.append(int(n.text))
        count2.append(count)

print(max(maxnum))
print(max(minnum))

upnum = []
for i in range(len(maxnum)):
    if maxnum[i]== max(maxnum):
        upnum.append(count1[i])
# downnum用来记录下降最快的位于所有列表的哪个位置
downnum = []
for j in range(len(minnum)):
    if minnum[j] == max(minnum):
        downnum.append(count2[j])
songname = driver.find_elements(By.CSS_SELECTOR, '.ttc>.txt>a>b')
singer = driver.find_elements(By.CSS_SELECTOR, '.text>span')
for m in upnum:
    print("排名上升最多∶歌曲名: "+songname[m-1].get_attribute("title")+"歌手:"+singer[m-1].get_attribute("title"))
for n in downnum:
    print("排名下降最多∶歌曲名:"+songname[n-1].get_attribute("title")+"歌手: "+singer[n-1].get_attribute("title"))

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值