本文共 4110 字,大约阅读时间需要 13 分钟。
在开发自动化测试或动态网页爬取任务时,Selenium库提供了强大的页面操作和元素定位功能。然而,当项目涉及包含多个Frame(内嵌页面)的动态网页时,操作过程中经常会遇到元素定位失败的问题。这种情况下,我们需要理解并掌握Frame切换的相关知识,以确保能够正确识别和操作目标元素。
本文将详细介绍如何在Selenium库中处理Frame切换,具体包括Frame定位方法和实际案例——QQ邮箱信息爬取的实现。
当我们使用Selenium库对动态网页内容进行爬取时,通常会遇到以下错误情形:
吴腾富发在博客中提到frame窗口切换的问题,但并未详细讲解。今天就用Selenium库详细讲解frame的使用。
如果反复检查网页源码发现目标元素在页面中存在,并且使用Firebug等工具也能找到该元素,但Selenium定位却失败,该怎么办?答案是:我们需要先确认微调窗口是否切换了。
要理解这一点,需要了解Selenium如何处理页面布局。WebDriver只能在同一页面的元素进行识别和定位,对于内嵌的Frame表单内的元素,直接定位将失败。
在Selenium库中,Frame切换可通过 switch_to.frame()
方法实现,支持以下几种定位方式:
大多数情况下,Frame会有一些独特的属性,比如id或name。可以使用以下方式切换:
driver.switch_to.frame("login_frame") # 根据Frame的id切换
此外,也可以传入Frame的name属性进行切换。
如果Frame没有id或name属性,Selenium可以根据Frame在页面中的顺序索引进行切换。索引从0开始计算:
driver.switch_to.frame(0)
如果你已经定位到了某个元素,并需要将该元素所属的Frame切换进来,可以直接使用该元素对象进行切换:
element = driver.find_element_by_tag_name('iframe')driver.switch_to.frame(element)
在爬取过程中,我们经常需要切换回主页面进行操作。可以使用 switch_to.default_content()
方法完成这一操作:
driver.switch_to.default_content()
此方法会自动定位并切换回主页面的内容,从而使我们能够操作主页面中的元素。
在某些场景中,网页会打开新的窗口(如点击链接或下载文件等),这时可以通过以下方式切换到新窗口:
for handle in driver.window_handles: driver.switch_to.window(handle)
注意:Window_Handle通常是一个唯一的标识符,用于区分不同的窗口。
在如今的动态网页中,表单结构越来越复杂,常包含多个Frame和页面跳转。以下是使用Selenium库爬取QQ邮箱信息的实现步骤。
driver.get('https://mail.qq.com/')time.sleep(3)
driver.switch_to.frame('login_frame')time.sleep(3)
login_element = driver.find_element_by_name('u')login_element.send_keys('QQ账号') # 请输入QQ号password_element = driver.find_element_by_name('p')password_element.send_keys('QQ密码') # 请输入QQ密码login_button = driver.find_element_by_id('login_button')login_button.click()time.sleep(3)
driver.switch_to.default_content()time.sleep(3)
inbox_element = driver.find_element_by_id('folder_1')inbox_element.click()time.sleep(3)
driver.switch_to.frame('mainFrame')time.sleep(3)
# 使用BeautifulSoup或其他工具解析页面内容source = driver.page_source# 通过解析获取收件箱内容from lxml import etreehtml = etree.HTML(source)for row in html.xpath('//tr[@id="div_showbefore"]/tbody/tr/td'): addressee = row.xpath('nobr/span/text()')[0].strip() email = row.xpath('@e')[0] title = row.xpath('div/u/text()')[0] date = row.xpath('div/text()')[0] # 将数据保存至数据库 result.append([addressee, email, title, date])
from selenium import webdriverimport timeimport pymysql# 数据库连接信息,注意替换为你的数据库信息dbinfo = { 'host': 'localhost', 'user': 'root', 'password': '你的密码', 'db': 'qq_email', 'charset': 'utf8'}def save_to_mysql(sql, val): try: conn = pymysql.connect(**dbinfo) cursor = conn.cursor() cursor.execute(sql, val) conn.commit() except Exception as e: print(f'错误:{e}') conn.rollback() finally: cursor.close() conn.close()if __name__ == '__main__': # 初始化浏览器 driver = webdriver.Chrome('路径到chromedriver.exe') driver.get('https://mail.qq.com/') time.sleep(3) # 登录 driver.switch_to.frame('login_frame') login_email = driver.find_element_by_name('u') login_email.send_keys('QQ账号') password = driver.find_element_by_name('p') password.send_keys('QQ密码') login_button = driver.find_element_by_id('login_button') login_button.click() time.sleep(3) driver.switch_to.default_content() time.sleep(3) # 收件箱 inbox_button = driver.find_element_by_id('folder_1') inbox_button.click() time.sleep(3) main_frame = driver.find_element_by_id('mainFrame') driver.switch_to.frame(main_frame) time.sleep(3) # 爬取数据 source = driver.page_source save_to_mysql( "INSERT INTO qq_youxiang (addressee, email, title, date) VALUES (%s, %s, %s, %s)", result ) # 关闭浏览器 driver.quit()
switch_to.window(handle)
方法。chrome_option
)。通过以上方法,可以轻松处理包含Frame的动态网页爬取任务,同时充分利用Selenium库的强大功能。希望本文能为您的开发工作提供帮助!
转载地址:http://aiphz.baihongyu.com/