Web自动化测试--selenium

一、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:https://registry.npmmirror.com/binary.html?path=chromedriver/

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主要用于识别用户并加载存储的信息。

这个方法常常用于将cookie添加到当前访问的上下文中. 添加Cookie仅接受一组已定义的可序列化JSON对象. 这里是一个链接, 用于描述可接受的JSON键值的列表

首先, 您需要位于有效Cookie的域上. 如果您在开始与网站进行交互之前尝试预设cookie, 并且您的首页很大或需要一段时间才能加载完毕, 则可以选择在网站上找到一个较小的页面 (通常404页很小, 例如 http://example.com/some404page)

将 Cookie 添加到当前浏览器上下文中
driver.add_cookie({"name": "key", "value": "value"})

此方法返回与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()

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的基础学习完结,但学无止境,继续加油