Web自动化测试--selenium

news2024/12/30 3:17:23

 🔥 交流讨论:欢迎加入我们一起学习!

🔥 资源分享耗时200+小时精选的「软件测试」资料包

🔥 教程推荐:火遍全网的《软件测试》教程  

📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

一、selenium介绍

Selenium 是支持web浏览器自动化的一系列工具和库的综合项目,能够进行自动化网页浏览器操作,广泛应用于测试和自动化行业。它可以模拟用户在浏览器中执行的操作,如点击按钮、填写表单、导航到不同页面等。Selenium 提供了一组强大的 API 和工具,使开发人员能够以编程方式控制浏览器,从而实现自动化测试、网页抓取和跨浏览器测试等任务。

官网:https://www.selenium.dev/zh-cn/documentation/

特点:

多语言支持:Selenium 提供了多种编程语言的 API,例如 Java、Python、C#、Ruby 等,使开发人员可以使用自己熟悉的语言编写测试脚本。
跨浏览器兼容性:Selenium 支持各种流行的浏览器,包括Chrome、Firefox、Safari 和 Edge等,可以在不同浏览器上执行测试并验证应用程序的一致性。
强大的定位机制:Selenium 提供了丰富的元素定位方法,如通过 ID、CSS、XPath 等定位方式,使得开发人员可以准确定位页面上的元素并与之交互。
自动化与集成:Selenium 可以与常见的集成工具和测试框架(如 TestNG、JUnit、Cucumber 等)无缝集成,使得测试和自动化过程更加灵活高效。
支持分布式测试:Selenium Grid 允许在多台计算机上并行执行测试,以加速测试执行和提高效率。
丰富的社区支持:Selenium 拥有庞大的开发者社区和活跃的维护者团队,提供了丰富的文档、教程和示例,方便开发人员学习和解决问题。

二、环境搭建

1、安装 Selenium 库

pip install selenium

2、获取浏览器的驱动程序

1.1 查看谷歌浏览器版本(以谷歌浏览器作为示例)
Chrome -> 右上角三个点-> 设置 -> 关于Google Chrome

1.2 下载对应版本的chromedriver
谷歌浏览器chromedriver:CNPM Binaries Mirror

3 配置 ChromeDriver 路径

下载解压后得到 chromedriver.exe,将其放入 Python 安装路径下的 Scripts 目录

4 编写 Selenium 脚本验证安装

新建python文件,命名open-web.py,使用 ChromeDriver 创建一个 Chrome 浏览器实例,打开 "https://www.example.com" 网页并最后关闭浏览器

from selenium import webdriver

# 创建 ChromeDriver 实例
driver = webdriver.Chrome()
# 打开网页,填写你需要的网站
driver.get("https://www.example.com")
# 执行其他操作
# ...
# 关闭浏览器0...........
driver.quit()

三、基本组成

1. 使用驱动实例开启会话

from selenium import webdriver
driver = webdriver.Chrome()

2. 在浏览器上执行操作

导航到网页

driver.get("https://www.selenium.dev/selenium/web/web-form.html")

3. 请求浏览器信息

请求一系列关于浏览器的信息, 包括窗口句柄、浏览器尺寸/位置、cookie、警报等

title = driver.title

4. 建立等待策略

等待一段时间使元素处于可交互状态

driver.implicitly_wait(0.5)
time.sleep(0.5)

5. 发送命令查找元素

text_box = driver.find_element(by=By.NAME, value="my-text")
submit_button = driver.find_element(by=By.CSS_SELECTOR, value="button")

6. 操作元素

text_box.send_keys("Selenium")
submit_button.click()

7. 获取元素信息

value = message.text

8. 结束会话

driver.quit()

四、元素

1.查询

根据提供的定位值定位元素.

#评估DOM元素,查找匹配的第一个元素
driver.find_element(By.CLASS_NAME, "tomatoes")

#评估DOM子集,缩小范围,通过父元素定位子元素
fruits = driver.find_element(By.ID, "fruits")
fruit = fruits.find_element(By.CLASS_NAME,"tomatoes")

#使用 CSS 或 XPath 在单个命令中找到此元素
fruit = driver.find_element(By.CSS_SELECTOR,"#fruits .tomatoes")

#获取所有匹配元素
plants = driver.find_elements(By.TAG_NAME, "li")

#循环访问集合并确定所需的集合
elements = driver.find_elements(By.TAG_NAME, 'p')
for e in elements:
    print(e.text)
 

2. 定位器

在DOM中标识一个或多个特定元素的方法
新版本:

名称含义定位元素
类名定位class属性与搜索值匹配的元素(不允许使用复合类名)By.ID
CSS 选择器定位 CSS 选择器匹配的元素By.XPATH
编号定位 id 属性与搜索值匹配的元素By.LINK_TEXT
名字定位 name 属性与搜索值匹配的元素By.PARTIAL_LINK_TEXT
链接文本定位link text可视文本与搜索值完全匹配的锚元素By.NAME
部分链接文本定位link text可视文本部分与搜索值部分匹配的锚点元素。 如果匹配多个元素,则只选择第一个元素。By.TAG_NAME
标签名称定位标签名称与搜索值匹配的元素By.CLASS_NAME
xpath定位与 XPath 表达式匹配的元素By.CSS_SELECTOR

例:
单个元素:driver.find_element(By.CSS_SELECTOR, "#fname")
多个元素:driver.find_elements(By.CSS_SELECTOR, "#fname")

旧版本:

定位元素含义
find_element_by_id通过元素 id 进行定位
find_element_by_name通过元素名称进行定位
find_element_by_xpath通过 xpath 表达式进行定位
find_element_by_link_text通过完整超链接文本进行定位
find_element_by_partial_link_text通过部分超链接文本进行定位
find_element_by_tag_name通过标记名称进行定位
find_element_by_class_name通过类名进行定位
find_element_by_css_selector通过 css 选择器进行定位

例:
单个元素:driver.find_element_by_id('username')
多个元素:driver.find_elements_by_id('username')

3. 信息

3.1 是否显示

是否正确显示在网页上. 返回一个 Boolean 值, 如果连接的元素显示在当前的浏览器上下文中,则为True,否则返回false
is_email_visible = driver.find_element(By.NAME, "email_input").is_displayed()

3.2 是否启用

检查所连接的元素在网页上是启用还是禁用状态。 返回一个布尔值,如果在当前浏览上下文中是启用状态,则返回 true,否则返回 false。
value = driver.find_element(By.NAME, 'button_input').is_enabled()

3.3 是否被选定

此方法确认相关的元素是否已选定,常用于复选框、单选框、输入框和选择元素中。
该方法返回一个布尔值,如果在当前浏览上下文中 选择了 引用的元素,则返回 True,否则返回 False。
value = driver.find_element(By.NAME, "checkbox_input").is_selected()

3.4 获取元素标签名

此方法用于获取在当前浏览上下文中具有焦点的被引用元素的TagName。
attr = driver.find_element(By.NAME, "email_input").tag_name

3.5 位置和大小

用于获取参照元素的尺寸和坐标。
提取的数据主体包含以下详细信息:

元素左上角的X轴位置
元素左上角的y轴位置
元素的高度
元素的宽度

res = driver.find_element(By.NAME, "range_input").rect

3.6 获取元素CSS值

获取当前浏览上下文中元素的特定计算样式属性的值。
cssValue = driver.find_element(By.ID, "namedColor").value_of_css_property('background-color')

3.7 文本内容

获取特定元素渲染后的文本内容。
text = driver.find_element(By.ID, "justanotherlink").text

3.8 获取特性或属性

获取与 DOM 属性关联的运行时的值。 它返回与该元素的 DOM 特性或属性关联的数据。

email_txt = driver.find_element(By.NAME, "email_input")
value_info = email_txt.get_attribute("value")

#获取链接
例:article.find_elements_by_xpath("/a")[j].get_attribute('href') 

五、交互

1. 元素交互

1.1 点击

元素点击命令执行在元素中央。如果元素中央由于某些原因被遮挡 , Selenium将返回一个元素点击中断错误。
driver.find_element(By.NAME, "input").click()

1.2 发送键位

元素发送键位命令将录入提供的键位到编辑的元素。通常, 这意味着元素是具有文本类型的表单的输入元素或具有内容可编辑属性的元素. 如果不可编辑, 则返回无效元素状态错误。
driver.find_element(By.NAME, "email_input").send_keys("abc")

1.3 清除

元素清除命令重置元素的内容. 这要求元素可编辑, 且可重置。 通常, 这意味着元素是具有文 类型的表单的输入元素或具有内容可编辑属性的元素. 如果不满足这些条件, 将返回无效元素状态错误.
driver.find_element(By.NAME, "email_input").clear()

2. 浏览器交互(获取浏览器信息)

2.1 获取标题

driver.title

2.2 获取当前url

driver.current_url

3. 浏览器导航

3.1 打开网站

driver.get("https://selenium.dev")

3.2 后退

driver.back()

3.3 前进

driver.forward()

3.4 刷新

driver.refresh()

4. 弹窗

4.1 Alerts 警告框

它显示一条自定义消息, 以及一个用于关闭该警告的按钮, 在大多数浏览器中标记为"确定"(OK). 在大多数浏览器中, 也可以通过按"关闭"(close)按钮将其关闭, 但这始终与“确定”按钮具有相同的作用

# 导入所需的模块和类
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 实例化浏览器驱动
driver = webdriver.Chrome()
# 点击链接以激活弹窗
driver.find_element(By.LINK_TEXT, "See an example alert").click()
# 等待弹窗显示并将其存储在变量中
wait = WebDriverWait(driver, 10)
alert = wait.until(EC.alert_is_present())
# 将弹窗文本存储在变量中
text = alert.text
# 点击确定按钮
alert.accept()
#点击取消按钮
alert.dismiss()

4.2 Confirm 确认框

确认框类似于警告框, 不同之处在于用户还可以选择取消消息

# 点击链接以激活确认框
driver.find_element(By.LINK_TEXT, "See a sample confirm").click()
# 等待确认框的出现,expected_conditions重命名为EC
wait = WebDriverWait(driver, 10)
wait.until(EC.alert_is_present())
# 将确认框存储在变量中以便复用
alert = driver.switch_to.alert
# 将确认框文本存储在变量中
text = alert.text
# 点击取消按钮
alert.dismiss()

4.3 Prompt 提示框

提示框与确认框相似, 不同之处在于它们还包括文本输入. 与处理表单元素类似, 您可以使用WebDriver的sendKeys来填写响应. 这将完全替换占位符文本. 按下取消按钮将不会提交任何文本

# 等待提示框的出现
wait = WebDriverWait(driver, 10)
wait.until(EC.alert_is_present())
# 将提示框存储在变量中以便复用
alert = Alert(driver)
# 输入消息
alert.send_keys("Selenium")
# 点击确定按钮
alert.accept()

5. 窗口和标签页

5.1 获取窗口句柄

WebDriver 没有区分窗口和标签页。如果你的站点打开了一个新标签页或窗口,Selenium 将允许您使用窗口句柄来处理它。 每个窗口都有一个唯一的标识符,该标识符在单个会话中保持持久性。你可以使用以下方法获得当前窗口的窗口句柄
driver.current_window_handle

5.2 切换窗口或标签页

单击在 <a href=“https://seleniumhq.github.io"target="_blank”>新窗口 中打开链接, 则屏幕会聚焦在新窗口或新标签页上,但 WebDriver 不知道操作系统认为哪个窗口是活动的。 要使用新窗口,您需要切换到它。 如果只有两个选项卡或窗口被打开,并且你知道从哪个窗口开始, 则你可以遍历 WebDriver, 通过排除法可以看到两个窗口或选项卡,然后切换到你需要的窗口或选项卡。

# 存储原始窗口的 ID
original_window = driver.current_window_handle
# 检查一下,我们还没有打开其他的窗口
assert len(driver.window_handles) == 1
# 单击在新窗口中打开的链接
driver.find_element(By.LINK_TEXT, "new window").click()
# 等待新窗口或标签页
wait.until(EC.number_of_windows_to_be(2))
# 循环执行,直到找到一个新的窗口句柄
for window_handle in driver.window_handles:
    if window_handle != original_window:
        driver.switch_to.window(window_handle)
        break
# 等待新标签页完成加载内容
  wait.until(EC.title_is("xxxx"))

5.3 创建新窗口或新标签页并且切换

创建一个新窗口 (或) 标签页,屏幕焦点将聚焦在新窗口或标签在上。您不需要切换到新窗口 (或) 标签页。如果除了新窗口之外, 您打开了两个以上的窗口 (或) 标签页,您可以通过遍历 WebDriver 看到两个窗口或选项卡,并切换到非原始窗口。

# 打开新标签页并切换到新标签页
driver.switch_to.new_window('tab')
# 打开一个新窗口并切换到新窗口
driver.switch_to.new_window('window')

5.4 关闭窗口或标签页

#关闭标签页或窗口
driver.close()
#切回到之前的标签页或窗口
driver.switch_to.window(original_window)

5.5 在会话结束时退出浏览器

完成了浏览器会话,应该调用 quit 退出,而不是 close 关闭
driver.quit()
退出将会:

  • 关闭所有与 WebDriver 会话相关的窗口和选项卡
  • 结束浏览器进程
  • 结束后台驱动进程
  • 通知 Selenium Grid 浏览器不再使用,以便可以由另一个会话使用它(如果您正在使用 Selenium Grid)

5.6 获取窗口大小

# 分别获取每个尺寸
width = driver.get_window_size().get("width")
height = driver.get_window_size().get("height")
# 或者存储尺寸并在以后查询它们
size = driver.get_window_size()
width1 = size.get("width")
height1 = size.get("height")

5.7 设置窗口大小

driver.set_window_size(1024, 768)

5.8 窗口位置

# 分别获取每个尺寸
x = driver.get_window_position().get('x')
y = driver.get_window_position().get('y')

# 或者存储尺寸并在以后查询它们
position = driver.get_window_position()
x1 = position.get('x')
y1 = position.get('y')

5.9 设置窗口位置

# 将窗口移动到主显示器的左上角
driver.set_window_position(0, 0)

5.10 最大化窗口

driver.maximize_window()

5.11 最小化窗口

driver.minimize_window()

5.12 全屏窗口

填充整个屏幕,类似于在大多数浏览器中按下 F11
driver.fullscreen_window()

5.12 屏幕截图

用于捕获当前浏览上下文的屏幕截图. WebDriver端点屏幕截图 返回以Base64格式编码的屏幕截图
driver.save_screenshot('./image.png')

5.13 元素屏幕截图

ele = driver.find_element(By.CSS_SELECTOR, 'h1')
ele.screenshot('./image.png')

5.14 执行脚本

在当前frame或者窗口的上下文中,执行JavaScript代码片段

# 存储标题元素
header = driver.find_element(By.CSS_SELECTOR, "h1")
# 执行 JavaScript 代码以捕获标题元素的 innerText
inner_text = driver.execute_script('return arguments[0].innerText', header)
# 执行JavaScript代码,将页面滚动到底部
js = "window.scrollTo(0, document.body.scrollHeight);"
driver.execute_script(js)

5.15 打印页面

from selenium.webdriver.common.print_page_options import PrintOptions
# 实例化打印选项对象
print_options = PrintOptions()
print_options.page_ranges = ['1-2']
# 打开打印页的网址
driver.get("printPage.html")
# 执行打印操作,并获取打印后的页面内容的 Base64 编码
base64code = driver.print_page(print_options)

6 Cookies

Cookie是从网站发送并存储在您的计算机中的一小段数据. Cookies主要用于识别用户并加载存储的信息。

6.1 添加 Cookie

这个方法常常用于将cookie添加到当前访问的上下文中. 添加Cookie仅接受一组已定义的可序列化JSON对象. 这里是一个链接, 用于描述可接受的JSON键值的列表
首先, 您需要位于有效Cookie的域上. 如果您在开始与网站进行交互之前尝试预设cookie, 并且您的首页很大或需要一段时间才能加载完毕, 则可以选择在网站上找到一个较小的页面 (通常404页很小, 例如 http://example.com/some404page)
将 Cookie 添加到当前浏览器上下文中
driver.add_cookie({"name": "key", "value": "value"})

6.2 获取命名的 Cookie

此方法返回与cookie名称匹配的序列化cookie数据中所有关联的cookie.

# 将 Cookie 添加到当前浏览器上下文中
driver.add_cookie({"name": "key", "value": "value"})
# 使用命名的 cookie 'key' 获取 cookie 详细信息
print(driver.get_cookie("key"))

6.3 获取全部 Cookies

driver.get_cookies()

6.4 删除 Cookie

driver.delete_cookie("key")

6.5 删除所有 Cookies

driver.delete_all_cookies()

6.6 Same-Site Cookie属性

此属性允许用户引导浏览器控制cookie, 是否与第三方站点发起的请求一起发送. 引入其是为了防止CSRF(跨站请求伪造)攻击.
Same-Site cookie属性接受以下两种参数作为指令

  • Strict:当sameSite属性设置为 Strict, cookie不会与来自第三方网站的请求一起发送.
  • Lax:将cookie sameSite属性设置为 Lax, cookie将与第三方网站发起的GET请求一起发送.
driver.add_cookie({"name": "key", "value": "value", 'sameSite': 'Strict'})
driver.add_cookie({"name": "key1", "value": "value", 'sameSite': 'Lax'})

7. IFrames和Frame

遇到嵌套的 iframe(内联框架),需要定位和切换到 iframe

7.1 使用 WebElement切换

iframe_element = driver.find_element_by_xpath("//iframe[@id='iframe_id']")
driver.switch_to.frame(iframe_element)

7.2 使用 name 或 id切换

# 通过 id 切换框架
driver.switch_to.frame('buttonframe')

7.3 使用索引切换

# 基于索引切换到第 2 个 iframe
iframe = driver.find_elements(By.TAG_NAME,'iframe')[1]
# 切换到选择的 iframe
driver.switch_to.frame(iframe)

7.4 切回主文档

完成 iframe 内的操作后,可以使用该方法将焦点切回到主文档。这将恢复驱动器的默认上下文,使后续的操作在主文档中进行
driver.switch_to.default_content()

六、等待

我们在做WEB自动化时,一般要等待页面元素加载完成后,才能执行操作,否则会报错找不到元素的错误
三种等待方式:

  • 隐式等待
  • 显示等待
  • 强制等待

1. 隐式等待

Selenium有一种内置的方式来自动等待称为隐式等待的元素。 可以使用浏览器选项中的超时功能或使用驱动程序方法(如下所示)设置隐式等待值。
这是一个全局设置,适用于整个会话的每个元素位置调用。 默认值为 ,这意味着如果未找到该元素,它将 立即返回错误。如果设置了隐式等待,驱动程序将等待 返回错误之前所提供值的持续时间。请注意,只要元素定位,驱动程序将返回元素引用,代码将继续执行, 因此,较大的隐式等待值不一定会增加会话的持续时间。缺点:有时需要的元素早已加载完成,个别元素加载慢,仍要等待页面全部加载完成才能执行下一步。
警告:不要混合隐式和显式等待。 这样做可能会导致不可预测的等待时间。 例如,将隐式等待设置为 10 秒 并显式等待 15 秒 可能会导致 20 秒后发生超时
driver.implicitly_wait(2)

2. 显式等待

显式等待是一种条件触发式的等待方式,指定某一条件直到这个条件成立时才会继续执行,可以设置超时时间,如果超过这个时间元素依然没被加载,就会抛出异常。
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//div//input"))
或者例下:

revealed = driver.find_element(By.ID, "revealed")
wait = WebDriverWait(driver, timeout=2)
driver.find_element(By.ID, "reveal").click()
wait.until(lambda d : revealed.is_displayed())
revealed.send_keys("Displayed")

3. 强制等待

利用time模块的sleep方法来实现,使程序等待一段时间
time.sleep(time)

4. 其他

Selenium提供了一些内置的用于显式等待的方法,位于expected_conditions类中,方法名称如表所示:

内置方法功能
title_is判断当前页面的title 是否等于预期内容
title_contains判断当前页面的 title 是否包含预期字符串
presence_of_element_located判断某个元素是否被加到了 dom 树里,并不代表该元素一定可见
visibility_of_element_located判断某个元素是否可见
visibility_of判断某个元素是否可见
presence_of_all_elements_located判断是否至少有 1个元素存在于 dom 树中
text_to_be_present_in_element判断某个元素中的 text 是否包含了预期的字符串
text_to_be_present_in_element_value判断某个元素中的 value 属性是否包含了预期的字符串
frame tobe availableand switch toit判断该 frame 是否可以切换进去,如果可以的话,返回 True并且切换进去,否则返回 False
invisibility_of_element_located判断某个元素中是否不存在于 dom 树或不可见
element_tobeclickable判断某个元素中是否可见并且是 enable 的
stalenessof等待某个元素从 dom树中移除
element_tobeselected判断某个元素是否被选中了,一般用于下拉列表
element_located to be_selected判断某个元素是否被选中了,一般用于下拉列表
element_selection_statetobe判断某个元素的选中状态是否符合预期
element_located_selection_state_to_be判断某个元素的选中状态是否符合预期
alert_is_present判断页面上是否存在 alert 框

七、Web自动化测试示例

这是本人空闲时间写的一个招标信息获取自动化测试,里面基本涵盖了上述selenium内容,附加了注释,日期、excel表格读取和写入,贴近日常工作。

import time
import pandas as pd
import glob
import openpyxl
import traceback
from openpyxl.styles import Border, Side, Alignment
from datetime import datetime,timedelta
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


# 指定桌面路径
keyword_path = Path.home() / '招标/关键词'
save_path = Path.home() / '招标/结果'
# 获取当日日期``````````
today = time.strftime("%Y-%m-%d", time.localtime())
# 获取昨天的日期时间
yesterday = datetime.now() - timedelta(days=1)
yesterday_start = yesterday.replace(hour=0, minute=0, second=0, microsecond=0)
# 获取今天的日期时间
thetoday = datetime.now()
today_start = thetoday.replace(hour=0, minute=0, second=0, microsecond=0)
# 格式化日期时间
yesterday_formatted = yesterday_start.strftime("%Y-%m-%d %H:%M:%S")
today_formatted = today_start.strftime("%Y-%m-%d %H:%M:%S")
# 创建空的case列表
case = []
# 创建空的结果列表
result_list = []

def read_excel():
    global case
    # 查找以"关键词"开头的Excel文件
    file_pattern = str(keyword_path / '关键词*.xlsx')
    file_list = glob.glob(file_pattern)
    # 读取第一个匹配到的Excel文件
    if file_list:
        file_path = file_list[0]
        df = pd.read_excel(file_path)
        case = df['关键字'].values.tolist()
    else:
        print("未找到匹配的Excel文件")

#网站1数据获取
def search_results():
    global result_list
    global case
    # 打开第一个网站
    driver.get("http://118.64.254.72/freecms/site/juncai//cggg/index.html")

    # 等待页面加载完全
    time.sleep(2)

    #进入采购大厅
    purchase_notice1 = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.XPATH, "//ul[@class='nav-tab']//li/span[contains(text(),'采购大厅')]"))
    )
    purchase_notice1.click()
    # 等待搜索结果加载完全
    time.sleep(1)
    driver.find_element_by_xpath("//div[@class='layui-input-inline']//input[@id='stateDate']").send_keys(yesterday_formatted)
    driver.find_element_by_xpath("//div[@class='layui-input-inline']//input[@id='endDate']").send_keys(today_formatted)
    driver.find_element_by_xpath(
        "//div[@class='layui-col-md3']//div[@class='layui-form-select']//i[@class ='layui-edge']").click()
    time.sleep(1)
    driver.find_element_by_xpath(
        "//div[@class='layui-input-inline layui-form']//dl/dd[contains(text(),'全部')]").click()
    driver.find_element_by_xpath(
        "//div[@class='layui-col-md3']//div[@class='layui-form-select']//i[@class ='layui-edge']").click()

    for i, keyword in enumerate(case):
        # 在第一个网站中搜索关键词
        keyword_str = str(keyword)
        search_input1 = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "input[name='identity']")))
        search_input1.clear()
        search_input1.send_keys(keyword)

        search_button = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, "//button[contains(@class,'layui-btn-normal')]"))
        )
        search_button.click()
        # 等待搜索结果加载完全
        time.sleep(1)

        # 循环处理每一页的搜索结果
        while True:
            # 获取当前页的搜索结果
            articles = driver.find_elements(By.XPATH, "//div[@class='searchBoxBottom']//ul/li/a/..")
            if articles:
                for j, article in enumerate(articles):
                    # 获取搜索结果的信息
                    Announcement_title =article.find_elements_by_xpath("//div[@class='searchBoxBottom']//ul/li/a/span/p[@class='ellipsis']")[j].text
                    Announcement_type = article.find_elements_by_xpath("//div[@class='searchBoxBottom']//ul/li/a/span[contains(@style,'margin-left: 42px')]")[j].text
                    Announcement_time = article.find_elements_by_xpath("//div[@class='searchBoxBottom']//ul/li/a/span[contains(@style,'margin-right: 15px')]")[j].text
                    Announcement_link = article.find_elements_by_xpath("//div[@class='searchBoxBottom']//ul/li/a")[j].get_attribute('href')
                    result_list.append([keyword_str, Announcement_type, Announcement_title, Announcement_time, Announcement_link])
            time.sleep(1)
            # 判断是否存在下一页按钮
            next_page_buttons = driver.find_elements(By.XPATH, "//div[@class='pagination' and not(contains(@style,'display: none'))]//li[contains(text(),'>') and not(@class='disabled')]")
            if len(next_page_buttons) > 0:
                # 点击下一页按钮
                next_page_button = next_page_buttons[0]
                next_page_button.click()
                # 等待搜索结果加载完全
                time.sleep(1)
            else:
                break
        time.sleep(1)
    return result_list

#创建excel保存数据
def creat_excel(result_list):
    # 创建Excel工作簿
    wb = openpyxl.Workbook()
    sheet = wb.active
    last_row = 0
    # 设置表头
    sheet['A1'] = '关键词'
    sheet['B1'] = '公告类型'
    sheet['C1'] = '标题'
    sheet['D1'] = '时间'
    sheet['E1'] = 'URL'

    # 遍历result_list中的数据,并逐个写入Excel单元格
    for i, result in enumerate(result_list):
        keyword_str, Announcement_type, Announcement_title, Announcement_time, Announcement_link = result
        # 从第二行开始写入,因为第一行是表头
        last_row = i + 2
        sheet.cell(row=last_row, column=1, value=keyword_str)
        sheet.cell(row=last_row, column=2, value=Announcement_type)
        sheet.cell(row=last_row, column=3, value=Announcement_title)
        sheet.cell(row=last_row, column=4, value=Announcement_time)
        sheet.cell(row=last_row, column=5, value=Announcement_link)

    # 创建边框样式
    border = Border(
        left=Side(border_style="thin", color="000000"),
        right=Side(border_style="thin", color="000000"),
        top=Side(border_style="thin", color="000000"),
        bottom=Side(border_style="thin", color="000000")
    )

    # 设置边框样式、对齐方式和行高
    for row in sheet.iter_rows(min_row=1, max_row=last_row, min_col=1, max_col=5):
        for cell in row:
            cell.border = border
            cell.alignment = Alignment(wrap_text=True, vertical="center")
            sheet.row_dimensions[cell.row].height = 40
            # 设置列宽
            sheet.column_dimensions['A'].width = 19
            sheet.column_dimensions['B'].width = 10
            sheet.column_dimensions['C'].width = 21
            sheet.column_dimensions['D'].width = 12
            sheet.column_dimensions['E'].width = 40

    # 保存Excel文件
    file_name = f'结果_{today}.xlsx'
    file_path = save_path / file_name
    wb.save(file_path)
    wb.close()
    print("数据已写入Excel文件:", file_path)

if __name__ == '__main__':
    try:
        read_excel()
        # 创建Chrome浏览器实例
        driver = webdriver.Chrome()
        driver.maximize_window()
        #调用函数
        search_results()
        # 关闭网站
        driver.quit()
        creat_excel(result_list=result_list)
    except Exception as e:
        print(traceback.format_exc())

八、总结

本文主要介绍了selenium的部署使用、组成元素、交互操作等基本内容,后续还有一些进阶内容,例如Actions接口,验证码识别、脚本执行等等,我也会结合python编写实用的程序供大家参考。至此,selenium的基础学习完结,但学无止境,继续加油

最后我邀请你进入我们的【软件测试学习交流群:785128166】, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路

作为一个软件测试的过来人,我想尽自己最大的努力,帮助每一个伙伴都能顺利找到工作。所以我整理了下面这份资源,现在免费分享给大家,有需要的小伙伴可以关注【公众号:程序员二黑】自提!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1498268.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++数据结构与算法——二叉搜索树的修改与构造

C第二阶段——数据结构和算法&#xff0c;之前学过一点点数据结构&#xff0c;当时是基于Python来学习的&#xff0c;现在基于C查漏补缺&#xff0c;尤其是树的部分。这一部分计划一个月&#xff0c;主要利用代码随想录来学习&#xff0c;刷题使用力扣网站&#xff0c;不定时更…

JVM3_数据库连接池虚引用ConnectionFinalizerPhantomReference引起的FullGC问题排查

背景 XOP服务运行期间&#xff0c;查看Grafana面板&#xff0c;发现堆内存周期性堆积&#xff0c;Full GC时间略长&#xff0c;需要调查下原因 目录 垃圾收集器概述 常见的垃圾收集器分区收集策略为什么CMS没成为默认收集器 查看JVM运行时环境分析快照 PhantomReference虚引用…

DAWG库下载出现的问题

今天配置一些环境出现了报错需要下载DAWG-0.8.0-cp38-cp38-win_amd64&#xff0c; PyPi官网https://pypi.org/project/DAWG/#files 只找到了mac版本&#xff0c;没发现windows版本 于是找到了非官方网址&#xff1a; https://www.lfd.uci.edu/~gohlke/pythonlibs/#dawg 下载DA…

JAVA开发第一个Springboot WebApi项目

一、创建项目 1、用IDEA新建一个SpringBoot项目 注意JDK与Java版本的匹配,如果想选择jdk低版本,先要更改服务器URL:start.aliyun.com 2、添加依赖 (1)、Lombok (2)、Spring Web (3)、Mybatis Framework (4)、MySqlDriver 项目中的配置 pom.xml 如下 <?…

java写DBF文件

之前漏了个功能支持&#xff0c;那就是WhoNet上报的DBF文件导出&#xff0c;因为DBF基本没什么人在用了&#xff0c;实现DbfUtil供业务写DBF文件做WhoNet上报导出用。 DBF读写工具类 package JRT.Core.Util;import com.linuxense.javadbf.DBFDataType; import com.linuxense.…

java017 - Java抽象类

1、概述 一般情况&#xff0c;动物是抽象的&#xff0c;所以不能被new,比如你在Animal类中定义一个成员方法eat,你不能定义具体内容&#xff0c;比如吃鱼或者吃白菜&#xff0c;因为动物是抽象的。 一个没有方法体的方法&#xff0c;应该定义为抽象方法&#xff0c;而类中如果…

Linux:kubernetes(k8s)探针ReadinessProbe的使用(9)

本章yaml文件是根据之前文章迭代修改过来的 先将之前的pod删除&#xff0c;然后使用下面这个yaml进行生成pod apiVersion: v1 # api文档版本 kind: Pod # 资源对象类型 metadata: # pod相关的元数据&#xff0c;用于描述pod的数据name: nginx-po # pod名称labels: # pod的标…

vulhub中ThinkPHP5 SQL注入漏洞 敏感信息泄露

漏洞原理 传入的某参数在绑定编译指令的时候又没有安全处理&#xff0c;预编译的时候导致SQL异常报错。然而thinkphp5默认开启debug模式&#xff0c;在漏洞环境下构造错误的SQL语法会泄漏数据库账户和密码 启动后&#xff0c;访问http://your-ip/index.php?ids[]1&ids[]2…

硬核程序员接单指南,速看!

程序员单没接着&#xff0c;时间还浪费了&#xff1f;惹得一身晦气。遇上了1k开发一个“淘宝”网站的“深井”&#xff1f;不是来下单的&#xff0c;倒像是来许愿的……估摸着是把程序员当阿拉丁神灯。 莫非那些兼职月入3k&#xff0b;的人&#xff0c;都是托儿&#xff1f;带着…

【Leetcode每日一题】 前缀和 - 和为 K 的子数组(难度⭐)(29)

1. 题目解析 题目链接&#xff1a;560. 和为 K 的子数组 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 核心在于计算题目所给数组是否存在连续子数组和为指定值&#xff0c;存在返回连续子数组个数即可&#xff0c;不存在返回0即…

外包干了8天,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入杭州某软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

击鼓传花游戏

有N个小朋友围成一圈玩击鼓传花游戏&#xff0c;将小朋友编号为1-N&#xff0c;从1号开始传花&#xff0c;每次传3个&#xff0c;拿到花的小朋友表演节目后退出。任给N&#xff0c;问最后一个表演的小朋友编号是多少&#xff1f;例如&#xff1a;输入5&#xff0c;从1号开始传花…

网站维护3年15000元,贵不贵?市场价多少

一般来说&#xff0c;给公司做好网站上线之后&#xff0c;网站就进入了运维期间&#xff0c;某功力公司给客户收费3年15000元网站运维费用&#xff0c;到底高不高呢&#xff1f; 首先&#xff0c;来看看网站运维都有哪些项目 网站运维涉及多个项目和任务&#xff0c;包括但不限…

M1电脑 Xcode15升级遇到的问题

遇到四个问题 一、模拟器下载经常报错。 二、Xcode15报错: SDK does not contain libarclite 三、报错coreAudioTypes not found 四、xcode模拟器运行一次下次必定死机 一、模拟器下载经常报错。 可以https://developer.apple.com/download/all/?qios 下载最新的模拟器&…

鸿蒙开发岗成春招最大黑马,“金三银四”应届生如何突围?

一年一度春招时间到&#xff0c;技术岗位已成为众多人才竞相追求的“职业高地”&#xff0c;也是未来职业发展的重要方向之一。鸿蒙人才在春招市场上成为“香饽饽”&#xff0c;与往年不同的是&#xff0c;许多应届生放弃考公执念向程序员进攻&#xff0c;这一现象背后蕴含着深…

程序逻辑控制

1.java的三大结构 可以说java的这三大结构包括其中的语句跟c语言上的基本上都是一样的。现在就当重新复习一遍吧&#xff01; 1.顺序结构 2.分支结构 if语句 跟c语言的语法一模一样。就直接看文案了。 switch语句 java中的switch语句跟c语言中的switch几乎相同&#xff0c;…

试用Claude3

1 简介 好消息是&#xff0c;2024 年 3 月 4 日发布了 Claude3&#xff0c;据传比 GPT-4 更好&#xff0c;snooet 版本可以免费试用&#xff0c;坏消息是我们这儿不能用。 在官网注册时&#xff0c;需要选择国家并使用手机接收短信验证码。而在选项中没有中国这个选项。即使成…

腾讯云学生服务器多少钱?怎么申请?

2024年腾讯云学生服务器优惠活动「云校园」&#xff0c;学生服务器优惠价格&#xff1a;轻量应用服务器2核2G学生价30元3个月、58元6个月、112元一年&#xff0c;轻量应用服务器4核8G配置191.1元3个月、352.8元6个月、646.8元一年&#xff0c;CVM云服务器2核4G配置842.4元一年&…

一周学会Django5 Python Web开发-Django5新增视图CreateView

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计29条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

12.WEB渗透测试-Linux系统管理、安全加固(下)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;11.WEB渗透测试-Linux系统管理、安全加固&#xff08;上&#xff09;-CSDN博客 Linux任务…