Selenium

0x01 原理与安装

(1)原理

Selenium 是一套 Web 网站的程序自动化操作解决方案

graph LR A(自动化程序<br/>Selenium 客户端库)-->B(浏览器驱动<br/>由浏览器厂商提供) B-->A B-->C(浏览器) C-->B

由此,编写自动化程序需要使用客户端库,当需要模拟用户点击界面的按钮,就会发送点击元素的请求给浏览器驱动,之后浏览器驱动向浏览器转发请求,其中的请求满足 HTTP。该流程中的客户端库由 Selenium 组织提供。

Selenium 自动化流程如下:

  1. 自动化程序调用 Selenium 客户端库函数
  2. 客户端库会发送 Selenium 命令给浏览器的驱动程序
  3. 浏览器驱动程序接收到命令后驱动浏览器去执行命令
  4. 浏览器执行命令
  5. 浏览器驱动程序获取命令执行的结果,返回给自动化程序
  6. 自动化程序对返回结果进行处理

(2)安装

  1. 安装客户端库

    以 Python 语言举例

    执行命令pip install selenium安装

  2. 安装浏览器驱动

    Chrome 浏览器驱动下载链接
    Edge 浏览器驱动下载链接

    注意:浏览器驱动的版本尽量与浏览器版本一致

    以下全部操作以 Chrome 环境为例

(3)简单实例:自动打开 Chrome 并进入百度

import os
from selenium import webdriver
from selenium.webdriver.chrome.service import Service


# 创建 WebDriver 对象,指明使用 Chrome 浏览器驱动
wd = webdriver.Chrome(service=Service(r'../venv/Scripts/chromedriver.exe'))
# 调用 WebDriver 对象的 get 方法,可以让浏览器打开指定网址
wd.get('https://www.baidu.com')
# 运行后暂停
os.system("pause")

(4)常见问题

  1. 关闭 chromedriver 日志

    from selenium import webdriver
    # 添加参数,禁止 chromedriver 日志写屏
    options = webdriver.ChromeOptions()
    options.add_experimental_option('excludeSwitched', ['enable-logging'])
    # 这里指定 options 参数
    wd = webdriver.Chrome(options=options)
    
  2. 浏览器首页显示防病毒重置设置

    1. 在运行窗口(win+R)输入regedit并运行
    2. 找到HKEY_CURRENT_USER\Software\Google\Chrome
    3. 删除其TriggeredReset子项
    4. 关闭注册表编辑器

0x02 选择元素

(1)选择元素的方法

在网页中开启控制台:F12 或 Ctrl+Shift+I

(2)根据 id 选择

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

wd = webdriver.Chrome()
wd.get('https://www.baidu.com/')
# 根据 id 选择元素,返回的就是该元素的 WebElement 对象
element = wd.find_element(By.ID, 'kw')
# 通过该 WebElement 对象,就可以对页面元素进行操作
element.send_keys('微信公众号认证\n')
os.system("pause")
  • 当传入的 id 被判断为不存在时会抛出selenium.common.exceptions.NoSuchElementException异常
  • 当 Selenium 的版本低于 4 时,可以使用find_element_by_id('kw')方法

将输入回车的方法进行搜索换为按按钮进行搜索:

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

wd = webdriver.Chrome()
wd.get('https://www.baidu.com/')
# 根据 id 选择元素,返回的就是该元素的 WebElement 对象
element = wd.find_element(By.ID, 'kw')
# 通过该 WebElement 对象,就可以对页面元素进行操作
element.send_keys('微信公众号认证')
# 通过点击“百度一下”按钮进行搜索
element = wd.find_element(By.ID, 'su')
# 触发单击事件
element.click()

os.system("pause")

(3)根据 class 选择

find_elements_by_class_name('nav-search-input')
  • element不加s表示选择第一个classnav-search-input的标签
  • elements表示选择所有classnav-search-input的标签
import os
from selenium import webdriver
from selenium.webdriver.common.by import By

wd = webdriver.Chrome()
wd.get('http://www.moj.gov.cn/')
# 根据 class 选择元素,返回的就是该元素的 WebElement 对象
elements = wd.find_elements(By.CLASS_NAME, 'mainlevel')
for element in elements:
    print(element.text)

os.system("pause")

当没有符合条件的元素出现时:

  • find_element会抛出异常
  • find_elements会返回空列表

类似的可以通过tag名称、css选择器进行选择:

  • find_element(By.TAG_NAME, 'input')
  • find_element(By.CSS_SELECTOR, 'button[type=submit]')

(4)选择延迟

程序运行速度超过浏览器加载速度时需要延迟程序

import time
time.sleep(1)	# 单位为 秒

Selenium 内置了一个方法implicitly_wait(),用于设置最大等待时长:

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

wd = webdriver.Chrome()
wd.get('http://www.moj.gov.cn/')

wd.implicitly_wait(10)

elements = wd.find_elements(By.CLASS_NAME, 'mainlevel')
for element in elements:
    print(element.text)
pass

0x03 操控元素

(1)点击

调用方法click(),实际点击的位置是元素的中心点

(2)输入

调用方法send_keys(),在方法中添加需要输入的字符串信息

调用方法clear(),用于清除输入框已有的字符串

调用元素对象方法element.get_attribute('value'),用于获取输入框已有的内容

(3)获取

  1. 文本

    调用元素对象属性element.text

    获取输入框已有内容

    特殊情况:当元素的文本内容没有或未完全展示在界面上,此时使用下述方法:

    • element.get_attribute("innerText")
    • element.get_attribute("textContent")
  2. 属性

    调用元素对象方法element.get_attribute('href')

    整个元素对应的 HTML:element.get_attribute('outerHTML')

    某个元素内部的 HTML:element.get_attribute('innerHTML')

0x04 CSS 表达式

省略 CSS 基础

方法find_elements(By.CSS_SELECTOR, 'xxx')中,xxx为 CSS 选择器参数

举例:采取 CSS 选择器选中 class 为 mainlevel 的标签

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

wd = webdriver.Chrome()
wd.get('http://www.moj.gov.cn/')

wd.implicitly_wait(10)

# 设置 CSS 选择器选择类 mainlevel
elements = wd.find_elements(By.CSS_SELECTOR, '.mainlevel')
for element in elements:
    print(element.text)

pass

0x05 frame 切换/窗口切换

(1)切换到 frame

对于一些网页中使用了<iframe></iframe>标签,Selenium 在默认情况下无法进入该标签中被嵌入的另一份 HTML 文档,此时需要切换操作范围至被嵌入的文档中。

切换方法为 WebDriver 对象中的switch_to属性:

wd.switch_to.frame(frame_reference)

其中,frame_reference可以是frame元素的属性nameID

  • wd.switch_to.frame('frame1')
  • wd.switch_to.frame('innerFrame')

frame元素没有设置属性nameID时,可以通过 CSS 选择器或选取tag的方法:

  • wd.switch_to.frame(wd.find_element(By.CSS_SELECTOR, '[src="xxx.html"]'))
  • wd.switch_to.frame(wd.find_element(By.TAG_NAME, 'iframe'))

当需要切换回主 HTML 时,使用wd.switch_to.default_content()

(2)浏览器窗口切换(多页面操作)

对于一些网页的<a></a>标签设置了属性target="_blank",即在新窗口打开对应链接,此时 Selenium 不会主动进行窗口切换,可以使用 WebDriver 对象中的switch_to属性:

wd.switch_to.window(handle)

其中,handle窗口的句柄,句柄可以看作网页窗口的 ID。

考虑到当前浏览器中可能打开了多个窗口,可以通过以下方法找到并切换窗口:

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

wd = webdriver.Chrome()
wd.implicitly_wait(10)
wd.get('http://www.moj.gov.cn/pub/sfbgw/')
# 打开新窗口链接
element = wd.find_element(By.CLASS_NAME, 'sLinkItem_first')
element.click()
# 输出新窗口标题
print("1.", wd.title)


for handle in wd.window_handles:
    # 先顺序进行窗口切换
    wd.switch_to.window(handle)
    # 通过标题判断是否为需要的窗口
    if '中国政府网' in wd.title:
        # 如果正确则跳出循环
        break

# 在新窗口中进行操作
wd.implicitly_wait(10)
print("2.", wd.title)
element = wd.find_element(By.ID, 'mainlevel_02')
element.click()


os.system("pause")

当需要返回之前的网页时,有以下两种方法:

  • 继续采取上述循环的方法找到相应的网页

  • 记录该窗口的句柄并直接跳转

    # 保存主窗口的句柄
    mainWindow = wd.current_window_handle
    # ...
    # 通过记录的句柄切换回主窗口
    wd.switch_to.window(mainWindow)
    

0x06 选择框

(1)radio 单选框

找到目标位置,直接模拟用户点击即可。

(2)checkbox 复选框

找到目标位置,必须首先确认当前复选框的状态,之后直接模拟用户点击即可。

确认当前复选框的状态有以下两种方法:

  • print(wd.find_elements(By.CSS_SELECTOR, 'input[type="checkbox"]').is_selected())
    • True / False
  • print(wd.find_elements(By.CSS_SELECTOR, 'input[type="checkbox"]').get_attribute("checked"))
    • true / None

全选方法:

elements = wd.find_elements(By.CSS_SELECTOR, 'input[type="checkbox"]')
for element in elements:
    judge = element.is_selected()
    print(judge)
    if judge is False:
        element.click()

(3)select 下拉框

对于 select 选择框,Selenium 提供了专门的 Select 类进行操作

# 导入 Select 类
from selenium.webdriver.support.ui import Select
# 创建 Select 对象
select = Select(element)
  1. select.select_by_value(value)

    根据选项的 value 属性值选择元素

  2. select.select_by_index(index)

    根据选项的次序值选择元素

  3. select_by_visible_text(text)

    根据选项的可见文本选择元素

  4. deselect_by_value(value)

    根据选项的 value 属性值去除元素

  5. deselect_by_index(index)

    根据选项的次序值去除元素

  6. deselect_by_visible_text(text)

    根据选项的可见文本去除元素

  7. deselect_all()

    去除所有元素

select 下拉选框通过是否设置multiple属性控制是否可以多选

单选:直接模拟用户点击操作即可

多选:先查看已选项,后进行选择操作

0x07 实战技巧

(1)更多操作

对于进行双击、右击、移动、悬停、拖拽等操作,Selenium 提供了ActionChains类来实现,以鼠标移动举例:

import os
from selenium import webdriver
from selenium.webdriver.common.by import By
# 导入 ActionChains 类
from selenium.webdriver.common.action_chains import ActionChains

wd = webdriver.Chrome()
wd.implicitly_wait(10)
wd.get('https://www.baidu.com/')
ac = ActionChains(wd)
# 鼠标移动到元素上
ac.move_to_element(
    wd.find_element(By.CSS_SELECTOR, '[name="tj_briicon"]')
).perform()		# perform() 是执行上述鼠标移动操作的“启动器”


os.system("pause")

(2)冻结界面

用于解决无法查看鼠标悬停后触发的页面

setTimeout(function(){debugger}, 5000)

(3)弹出框操作

  1. Alert,警告信息

    只需点击确认即可

    wd.switch_to.alert.accept()
    

    当需要获取对话框中的信息时,使用wd.switch_to.alert.text即可

  2. Confirm,确认信息

    需要选择确认或取消

    确认:wd.switch_to.alert.accept()

    取消:wd.switch_to.alert.dismiss()

  3. Prompt,提示输入

    需要输入提交信息,可使用

    # 输入信息
    wd.switch_to.alert.send_keys(text)
    # 确认提交
    wd.switch_to.alert.accept()
    # 取消提交
    wd.switch_to.alert.dismiss()
    
  4. 非类 Alert 弹出框

    根据 HTML 元素选择

0x08 Xpath 选择器

省略 Xpath 基础

posted @ 2023-03-15 14:28  SRIGT  阅读(76)  评论(0编辑  收藏  举报