Web自动化测试--selenium

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

🔥 资源分享耗时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自动化测试/测试开发,走向高薪之路

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第五十二回 戴宗二取公孙胜 李逵独劈罗真人-飞桨AI框架安装和使用示例

吴用说只有公孙胜可以破法术&#xff0c;于是宋江请戴宗和李逵去蓟州。两人听说公孙胜的师傅罗真人在九宫县二仙山讲经&#xff0c;于是到了二仙山&#xff0c;并在山下找到了公孙胜的家。 两人请公孙胜去帮助打高唐州&#xff0c;公孙胜说听师傅的。罗真人说出家人不管闲事&a…

【java】后序遍历二叉树

采用递归方式实现 节点类 public class Node {private int value;//父节点private Node fNode;//左节点private Node left;//右节点private Node right;//是否已经打印过private boolean sign false;public Node() {}public boolean isSign() {return sign;}public void setS…

京东老矣,尚能饭否?

图片&#xff5c;《冰与火之歌》截图 ©自象限原创 作者丨程心 编辑丨罗辑 从2004年1月&#xff0c;京东正式涉足电商至今&#xff0c;整整二十年过去了。 2024年3月6日&#xff0c;京东发布了2023年第四季度及全年财报。数据显示&#xff0c;2023Q4京东收入3061亿元人民…

腾讯云服务器和阿里云服务器价格测评_2024年费用大PK

2024年阿里云服务器和腾讯云服务器价格战已经打响&#xff0c;阿里云服务器优惠61元一年起&#xff0c;腾讯云服务器61元一年&#xff0c;2核2G3M、2核4G、4核8G、4核16G、8核16G、16核32G、16核64G等配置价格对比&#xff0c;阿腾云atengyun.com整理阿里云和腾讯云服务器详细配…

分段线性化问题探析

目录 1 使用0-1变量将分段函数转换为线性约束 2 连续函数采用分段线性化示例 3 matlab程序测试 4 matlab测试结果说明 5 分段线性化应用 1 使用0-1变量将分段函数转换为线性约束 2 连续函数采用分段线性化示例 3 matlab程序测试 clc;clear all; gn10;tn1; x_pfsdpvar(1, t…

迷你内裤洗衣机排名前十名:推荐十款2024专业性高的内衣洗衣机

最近一段时间&#xff0c;关于内衣到底是机洗好&#xff0c;还是手洗好这个话题&#xff0c;有很多人都在讨论&#xff0c;坚决的手洗党觉得应该用手来清洗&#xff0c;机洗与其它衣物混合使用&#xff0c;会产生交叉感染&#xff0c;而且随着使用时间的推移&#xff0c;会变得…

一命通关前缀和

前缀和 简介 先来简单看一个场景。现在有一个公交车&#xff0c;第一站上了4个人&#xff0c;第二站上了7个人&#xff0c;第三站上了1个人&#xff0c;第四站上了5个人&#xff0c;问一共上了多少人&#xff1f; 答案很显而易见&#xff0c;只需要遍历这个数组&#xff0c;把…

DevEco-Studio 3.1.1 Release和DevEco Studio NEXT Developer Preview1同时安装在mac m2上

其实mas上支持同一个app的多个版本安装的&#xff0c;需要注意的是SDK的目录需要区分开&#xff0c;不能被覆盖。 HarmonyOS和OpenHarmony SDK配置 3.1.1 Release&#xff0c;HarmonyOS的SDK目录&#xff1a;/Users/zhongyili/Library/Huawei/Sdk_3.1 NEXT Developer Previ…

【2】SLoRa: A Systematic Framework for Synergic Interference Resilience In LPWAN

这一篇基于上一篇文章,仅记录我遗忘的知识点&#xff1b; 以较低的成本提供可靠的符号恢复&#xff1b; 符号恢复【振幅和频率】 为了避免环境噪声并提高可靠性&#xff0c;我们采用信号预处理和窗口滑动算法来检测幅度变化点&#xff1b; 信号处理&#xff1a;归一化和指数化…

如何查看前端的vue项目是vue2还是vue3项目

1. 检查package.json文件 在项目的根目录下&#xff0c;打开package.json文件&#xff0c;查找dependencies或devDependencies部分中的vue条目。版本号将告诉你是Vue 2还是Vue 3。例如&#xff1a; Vue 2.x: "vue": "^2.x.x"Vue 3.x: "vue": &…

Rust入门:C++和Rust动态库(dll)的相互调用

无论是C调用Rust动态库还是Rust调用C动态库&#xff0c;其操作基本都是一样地简单&#xff0c;基本和C调用C的动态库没什么区别&#xff0c;只需要列出所需要导入的函数&#xff0c;并链接到相应的lib文件即可。 这里&#xff0c;在windows中&#xff0c;我们以dll动态库为例说…

虽说主业搞前端,看到如此漂亮的网页UI,也是挪不开眼呀。

漂亮的网页UI能够吸引人的眼球&#xff0c;给人留下深刻的印象。作为前端开发人员&#xff0c;可以通过不断学习和掌握设计技巧和工具&#xff0c;提升自己的UI设计能力&#xff0c;为用户提供更好的视觉体验。 以下是一些提升网页UI设计能力的建议&#xff1a; 学习设计基础知…

外包干了一周,技术明显倒退。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

【鸿蒙 HarmonyOS 4.0】解决:搜索无效问题

一、背景 页面包含搜索框和列表&#xff0c;列表默认展示所有数据并具有分页功能。然而&#xff0c;在输入关键字到搜索框时&#xff0c;列表未正确展示搜索结果。 二、功能实现 2.1、原代码及实现效果 import ChargeType from ../../viewModel/ChargeType import ChargeMo…

devc++8x8取模软件

这几天在搞arduino nano和单个max7219模块&#xff0c;涉及到16进制的取模&#xff0c;在网上转了一圈&#xff0c;没找到合适的取模软件&#xff0c;于是自己做了一个&#xff0c;试过&#xff0c;可以用&#xff0c;按esc退出并生成16进制的取模结果 源代码&#xff1a; #i…

liunx操作系统 环境变量

环境变量 main函数参数 命令行参数环境变量 环境变量的查看环境变量的获取 main函数参数 命令行参数 main函数是有参数的&#xff0c;只是我们一般不适用 这是main函数从bash中读取进程数据使用的一个基本入口。 下面进行简单演示。 o 好oo都是我们输入的命令行参数。其实&a…

20240304-使用VS2022编译blender3.6.2源代码

20240304-使用VS2022编译blender3.6.2源代码 一、软件环境 Win10 x64 22h2 JuneVS2022 v17.9.0CMake v3.24.4SVN v1.14.3GIT v2.29.2标签&#xff1a;win10 22h2 vs2022 blender 63335分栏&#xff1a;C 二、硬件环境 Win10 x64的PC台式机 三、获取源码 方法一 网盘下载…

安装sqlserver2022最新版只能使用.\SQLEXPRESS登录数据库怎么修改成.

.\SQLEXPRESS “服务器名称 localhost\SQLEXPRESS”中的 “SQLEXPRESS”就是数据库的实例名称/数据库名/服务器名&#xff0c; “localhost”即登录本计算机安装的数据库 安装sqlserver2022最新版只能使用.\SQLEXPRESS登录数据库怎么修改成. 2、查看SQL Server数据库的实例名…

Redis实战—验证码登录功能实现

本博客为个人学习笔记&#xff0c;学习网站&#xff1a;黑马程序员Redis入门到实战 实战篇之验证码登录 目录 基于Session实现登录流程 发送短信验证码 短信验证码登录、注册 校验登录状态 session共享问题 Redis代替session的业务流程 设计Key的结构 设置Key的细节 整…

FreeRTOS操作系统学习——任务管理

任务概念 在FreeRTOS中&#xff0c;一个任务相当于一个线程&#xff0c;可以有很多的任务&#xff0c;每个人任务可以设置不同的优先级。相同优先级的任务轮流使用CPU&#xff0c;高优先级的任务可以一直使用CPU&#xff0c;直到主动放弃&#xff0c;低级的任务才有被执行的机…