上手Selenium

目录

  • 介绍
  • 准备工作
    • 安装selenium库
    • 安装浏览器驱动
    • 初始化浏览器对象
    • 其他浏览器
  • 操控浏览器的基本方法
    • 访问页面
    • 设置浏览器大小
    • 设置代理
    • 获取页面基础属性
    • 无界面浏览器、截图
    • 刷新页面
    • 前进后退
    • 浏览器窗口切换
    • 弹出对话框
    • 冻结界面
  • 操控元素的基本方法
    • 点击元素
    • 输入、点击、结果等待
    • 清空 & 输入
    • **获取元素的文本内容**
    • 获取输入框里面的文字
    • 获取元素属性
    • 获取整个元素对应的HTML
    • frame切入切出
    • 高级方法1:模拟鼠标
      • 鼠标移动
      • 鼠标左右键
      • 鼠标拖拽
  • 元素的选择方法
    • 基本方法
      • 根据 id属性 选择元素
      • 根据 class属性 选择元素
      • 根据 tag名 选择元素
      • 根据 link定位、partial定位
    • CSS表达式
      • 根据 tag名、id、class 选择元素
      • 根据属性选择
      • 子元素、后代元素、逻辑或
      • 奇数节点和偶数节点
      • 兄弟节点选择
    • Xpath选择器
      • 绝对路径、相对路径
      • 通配符
      • 根据属性选择
      • 选择第几个
      • 范围选择
      • 逻辑或、父节点、兄弟节点✨
  • 元素的选择场景:选择框
    • radio框
    • checkbox框
    • select框
    • Select单选框
    • Select多选框
  • 参考

介绍

Selenium 是一套 Web网站的程序自动化操作解决方案。通过它,我们可以写出自动化程序,像人一样在浏览器里操作web界面。 比如点击界面按钮,在文本框中输入文字等操作。
支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera和Edge等。这里我将以Chrome为例进行Selenium功能的演示~

准备工作

安装selenium库

不同的编程语言选择不同的Selenium客户端库,对应我们Python语言来说,Selenium客户端库的安装非常简单,用 pip 命令即可。
打开命令行程序,运行如下命令:pip install selenium
网络不好的话,可以使用豆瓣源:pip install selenium -i https://pypi.douban.com/simple/

安装浏览器驱动

浏览器驱动是和浏览器对应的。 不同的浏览器需要选择不同的浏览器驱动。
2.1 浏览器的选择
目前主流的浏览器中,谷歌 Chrome 浏览器对Selenium自动化的支持更加成熟一些。
2.2 检查浏览器版本
其实,有两种方式安装浏览器驱动:一种是常见的手动安装,另一种则是利用第三方库自动安装。
这里介绍手动安装,自动安装参见:https://mp.weixin.qq.com/s/_lsDLPpNI1zdSwaPgdTZHQ
首先需要查看浏览器版本(2种方式均可):
方式1:在浏览器的地址栏键入Chrome://version,即可查看浏览器版本号
上手Selenium_第1张图片
方式2:点击“Chrome菜单”→“帮助”→“关于Google Chrome”,查看浏览器版本号
相当于地址栏输入:chrome://settings/help
上手Selenium_第2张图片
2.3 浏览器驱动的安装
下载地址:https://chromedriver.storage.googleapis.com/index.html
注意:驱动和浏览器的版本号越接近越好,但是略有差别,比如98和97 ,通常也没有什么问题。
上手Selenium_第3张图片

初始化浏览器对象

通过调用浏览器驱动,可以打开浏览器,就可以了

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

# 创建 WebDriver 对象,指明使用chrome浏览器驱动
# 注意,等号右边 返回的是 WebDriver 类型的对象,我们可以通过这个对象来操控浏览器,比如 打开网址、选择界面元素等。
wb = webdriver.Chrome(service=Service(r'C:\Users\asuka\Downloads\Compressed\chromedriver.exe'))

# 添加 input,让程序保持运行状态
input()

上手Selenium_第4张图片
在创建WebDriver对象时,需要指定浏览器驱动路径,这样写有2个问题:

  1. 比较麻烦, 每次写自动化代码都 要指定路径。
  2. 如果你的代码给别人运行,他的电脑上存放浏览器驱动的路径不一定和你一样(比如他的电脑是苹果Mac电脑),得改脚本。

有什么好办法呢?我们可以把浏览器驱动 所在目录加入环境变量Path , 写代码时,就可以无需指定浏览器驱动路径了,像这样:wd = webdriver.Chrome()
设置完环境变量后,别忘了重启IDE(比如 PyCharm) 新的环境变量才会生效。
上手Selenium_第5张图片
其他报错、报毒问题,参见:原理与安装 | 白月黑羽

其他浏览器

其他浏览器,如:360、Edge,参见:https://mp.weixin.qq.com/s/0mCAEcdRdyVKzDrueMUlpw

操控浏览器的基本方法

访问页面

使用Get方法访问某网站

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

# 初始化浏览器为chrome浏览器
browser = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))

# 访问百度首页
browser.get(r'https://www.baidu.com/')

# 关闭浏览器
browser.close()

设置浏览器大小

get_window_size()获取窗口大小
set_window_size()方法可以用来设置浏览器大小(就是分辨率)
maximize_window则是设置浏览器为全屏!

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

browser = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))

# 获取当前窗口大小
browser.get(r'https://www.baidu.com')
print(browser.get_window_size())  # {'width': 838, 'height': 892}
time.sleep(2)

# 设置浏览器大小:全屏
browser.maximize_window()
time.sleep(2)

# 设置分辨率 500*500
browser.set_window_size(500, 500)
time.sleep(2)

# 设置分辨率 1000*800
browser.set_window_size(1000, 800)
time.sleep(2)

# 关闭浏览器
browser.close()

设置代理

网上搜的结果不能用,问ChatGPT问出了答案。
代理类型:HTTP代理
方式1:为浏览器驱动设置了环境变量
上手Selenium_第6张图片

from selenium import webdriver

# 设置代理IP的地址和端口号,类型为 HTTP 代理
proxy_address = "127.0.0.1:8080"
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--proxy-server=http://" + proxy_address)

# 浏览器驱动访问网站
driver = webdriver.Chrome(options=chrome_options)
driver.get("https://www.baidu.com")

# 关闭浏览器
driver.quit()

方式2:指明浏览器驱动位置
上手Selenium_第7张图片

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

# 设置代理IP的地址和端口号,类型为 HTTP 代理
proxy_address = "127.0.0.1:8080"
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--proxy-server=http://" + proxy_address)

# 浏览器驱动访问网站
driver = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'), options=chrome_options)
driver.implicitly_wait(10)
driver.get('https://cn.bing.com/')

# 关闭浏览器
driver.quit()

获取页面基础属性

一些基础属性如:网页标题、网址、浏览器名称、页面源码等信息。

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

browser = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
browser.implicitly_wait(5)
browser.get(r'https://www.baidu.com')

# 获取当前窗口标题
print(browser.title)

# 获取当前窗口URL地址
print(browser.current_url)

# 浏览器名称
print(browser.name)

# 网页源码
print(browser.page_source)

# 关闭浏览器
browser.close()

无界面浏览器、截图

from selenium import webdriver

# 无界面的浏览器
option = webdriver.ChromeOptions()
option.add_argument("headless")
browser = webdriver.Chrome(options=option)

# 访问百度首页
browser.get(r'https://www.baidu.com/')

# 截图预览
browser.get_screenshot_as_file('截图.png')

# 关闭浏览器
browser.close()

刷新页面

刷新页面是我们在浏览器操作时很常用的操作,这里refresh()方法可以用来进行浏览器页面刷新。

from selenium import webdriver
import time

browser = webdriver.Chrome()

# 设置浏览器全屏
browser.maximize_window()
browser.get(r'https://www.baidu.com')
time.sleep(2)

try:
    # 刷新页面
    browser.refresh()
    print('刷新页面')
except Exception as e:
    print('刷新失败')

# 关闭浏览器
browser.close()

前进后退

前进后退是我们在使用浏览器时非常常见的操作,这里forward()方法可以用来实现前进,back()可以用来实现后退。

from selenium import webdriver
import time

browser = webdriver.Chrome()

# 设置浏览器全屏
browser.maximize_window()
browser.get(r'https://www.baidu.com')
time.sleep(2)

# 打开必应页面
browser.get(r'https://cn.bing.com/')
time.sleep(2)

# 后退到百度页面
browser.back()
time.sleep(2)

# 前进的必应页面
browser.forward()
time.sleep(2)

# 关闭浏览器
browser.close()

浏览器窗口切换

测试网站:https://cdn2.byhy.net/files/selenium/sample3.html
实现目标:访问必应网站,执行一次搜索,然后返回到测试网站
上手Selenium_第8张图片
上手Selenium_第9张图片
这里主要涉及到窗口切换,可以使用:wd.switch_to.window(handle),这是一个列表对象,里面包括了当前浏览器里面所有的窗口句柄。所谓句柄,大家可以想象成对应网页窗口的一个ID。
此外,我们可以设置一个当前窗口让它记住,方便随时切回来。

# mainWindow变量保存当前窗口的句柄
mainWindow = wd.current_window_handle

#通过前面保存的老窗口的句柄,自己切换到老窗口
wd.switch_to.window(mainWindow)

得到如下代码:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/sample3.html')

# 点击按钮,打开必应
link = wd.find_element(By.TAG_NAME, 'a')
link.click()
time.sleep(3)

# 记住当前窗口
mainWindow = wd.current_window_handle

# 找到必应窗口
for hanle in wd.window_handles:
    wd.switch_to.window(hanle)  # 切窗口
    if 'Bing' in wd.title:  # 发现某窗口的网页标题中有“Bing”
        break  # 找到了
print(wd.title)  # 输出切到的新窗口的title
# 开始搜索
wd.find_element(By.ID, 'sb_form_q').send_keys('白月黑羽\n')
time.sleep(3)

# 回退到之前记住的窗口
wd.switch_to.window(mainWindow)

time.sleep(3)
wd.close()

弹出对话框

有些网站点击的时候,会弹出的对话框。那么如果点出弹框,获取弹框内容,以及关闭弹框呢?
测试网站:https://cdn2.byhy.net/files/selenium/test4.html
Alert弹框
Alert 弹出框,目的就是显示通知信息,只需用户看完信息后,点击 OK(确定) 就可以了。
上手Selenium_第10张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/test4.html')

# --- alert ---
wd.find_element(By.ID, 'b1').click()

# 打印 弹出框 提示信息
print(wd.switch_to.alert.text)
time.sleep(3)

# 点击 OK 按钮
wd.switch_to.alert.accept()

time.sleep(3)
wd.quit()

Confirm弹框
Confirm弹出框,主要是让用户确认是否要进行某个操作

# 如果我们想点击 OK 按钮,可以用 accept 方法
driver.switch_to.alert.accept()

# 如果我们想点击 Cancel 按钮, 可以用 dismiss 方法
driver.switch_to.alert.dismiss()

上手Selenium_第11张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/test4.html')

# --- confirm ---
wd.find_element(By.ID, 'b2').click()

# 打印 弹出框 提示信息
print(wd.switch_to.alert.text)

# 点击 OK 按钮
wd.switch_to.alert.accept()

# --- confirm ---
wd.find_element(By.ID, 'b2').click()

# 点击 取消 按钮
wd.switch_to.alert.dismiss()

time.sleep(3)
wd.quit()

Prompt弹框
出现 Prompt 弹出框 是需要用户输入一些信息,提交上去。
比如:当管理员在网站上选择给某个账号延期时,就可能会弹出 Prompt 弹出框, 要求输入延期多长时间。
上手Selenium_第12张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/test4.html')

# --- prompt ---
wd.find_element(By.ID, 'b3').click()

# 获取 alert 对象
alert = wd.switch_to.alert

# 打印 弹出框 提示信息
print(alert.text)

# 输入信息,并且点击 OK 按钮 提交
alert.send_keys('web自动化 - selenium')
alert.accept()

# 点击 Cancel 按钮 取消
wd.find_element(By.ID, 'b3').click()
alert = wd.switch_to.alert
alert.dismiss()

time.sleep(3)
wd.quit()

冻结界面

当鼠标放到某个位置,会出现一些内容,如果想获取这些内容对应的位置,发现 F12不好用了,甚至有些时候通过“审查元素”都找不到(或者只能找到1个,不方便找其他的,如下图中的“影响推广”),这个时候就需要冻结界面了。
上手Selenium_第13张图片
我们可以在控制台中输入debugger实现冻结效果。
上手Selenium_第14张图片
那么,如果延迟数秒再冻结,就可以解决悬停显示问题了:

# 在 5000毫秒后,执行 debugger 命令
# debug状态有个特性,界面被冻住,不管我们怎么点击界面都不会触发事件。
setTimeout(function(){debugger}, 5000)

上手Selenium_第15张图片

操控元素的基本方法

选择到元素之后,我们的代码会返回元素对应的 WebElement对象,通过这个对象,我们就可以操控元素了。
操控元素通常包括:

  • 点击元素
  • 在元素中输入字符串,通常是对输入框这样的元素
  • 获取元素包含的信息,比如文本内容,元素的属性

点击元素

点击元素非常简单,就是调用元素WebElement对象的click方法。前面我们已经学过。
这里我们要补充讲解一点。当我们调用 WebElement 对象的click方法去点击元素的时候, 浏览器接收到自动化命令,点击的是该元素的中心点位置。

element = wd.find_element(By.ID,'go')
element.click()

输入、点击、结果等待

演示如何输入一个内容,点击按钮,等待加载结果

假设要获取搜索结果中的第一个结果内容,这里要添加一个休眠时间,因为搜索出结果是需要时间的!
上手Selenium_第16张图片
我想的是挺好的,但是代码一跑就出错了,抛了异常:NoSuchElementException,意思就是在当前的网页上 找不到该元素, 就是找不到 id 为 1 的元素。

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

wd = webdriver.Chrome()
wd.get('https://www.byhy.net/_files/stock1.html')

element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯\n')

element = wd.find_element(By.ID, '1')
print(element.text)

wd.quit()

上手Selenium_第17张图片
出现这个问题的原因在于网站还没有来得及返回搜索结果,代码就索要结果了。因此代码需要等待网站搜索出结果才行,那要等多久呢?直接设置个sleep休眠显然不好,不如让代码反复try:

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

wd = webdriver.Chrome()
wd.get('https://www.byhy.net/_files/stock1.html')

element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯\n')
while True:
    try:
        element = wd.find_element(By.ID, '1')
        print(element.text)
        break
    except:
        # 添加一个休眠,防止网站响应慢导致程序进入死循环
        time.sleep(1)

wd.quit()

# 结果
国美通讯
代码:600898

其实,Selenium提供了一个更合理的解决方案,是这样的:
当发现元素没有找到的时候, 并不立即返回找不到元素的错误。而是周期性(每隔半秒钟)重新寻找该元素,直到该元素找到,或者超出指定最大等待时长,这时才抛出异常(如果是 find_elements 之类的方法, 则是返回空列表)。
Selenium 的 Webdriver 对象有个方法叫implicitly_wait,可以称之为“隐式等待”,或者“全局等待”。该方法接受一个参数,用来指定最大等待时长。如果我们加入如下代码:wd.implicitly_wait(10),那么后续所有的find_element或者find_elements之类的方法调用都会采用上面的策略。如果找不到元素, 每隔半秒钟再去界面上查看一次, 直到找到该元素, 或者过了10秒最大时长。

特别警告⚠:implicitly_wait是为了解决找不到的问题,但是找到的也有可能是错误的。
当你网购时选择收件地址,选择省、市、县……,你怎么切换都有结果,但是你需要等“市”加载完之后,才能选择“县”,这个时候implicitly_wait就不好使了,还是需要sleep一下。

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

wd = webdriver.Chrome()
wd.implicitly_wait(10)  # 最久等待10秒
wd.get('https://www.byhy.net/_files/stock1.html')

element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯\n')

# 返回页面 ID 为 1 的元素
element = wd.find_element(By.ID, '1')
print(element.text)

wd.quit()

# 结果
国美通讯
代码:600898

清空 & 输入

使用WebElement对象的clear方法清空输入框内容
使用WebElement对象的send_keys方法输入内容
测试靶场:https://cdn2.byhy.net/files/selenium/test3.html
上手Selenium_第18张图片
上手Selenium_第19张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

browser = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))

# 设置浏览器全屏
browser.maximize_window()
browser.get(r'https://cdn2.byhy.net/files/selenium/test3.html')

element = browser.find_element(By.ID, 'input1')
element.clear()  # 清除输入框已有的字符串
element.send_keys('白月黑羽\n')  # 输入新字符串

input()

获取元素的文本内容

上面已经知道,通过WebElement对象的 text 属性,可以获取元素展示在界面上的文本内容。

element = wd.find_element(By.ID, '1')
print(element.text)

获取输入框里面的文字

对于input输入框的元素,要获取里面的输入文本,用text属性是不行的,这时可以使用element.get_attribute(‘value’)
测试靶场:https://www.byhy.net/_files/stock1.html
上手Selenium_第20张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

browser = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))

browser.get(r'https://www.byhy.net/_files/stock1.html')

element = browser.find_element(By.ID, 'kw')

element.send_keys('白月黑羽')
print(element.get_attribute('value'))

browser.close()

# 结果
白月黑羽

但是,有时候,元素的文本内容没有展示在界面上,或者没有完全完全展示在界面上。这时,用WebElement对象的text属性,获取文本内容,就会有问题。出现这种情况,可以尝试使用 element.get_attribute(‘innerText’) ,或者 element.get_attribute(‘textContent’)。
使用 innerText 和 textContent 的区别是,前者只显示元素可见文本内容,后者显示所有内容(包括display属性为none的部分)。具体可以参考这里

获取元素属性

通过WebElement对象的 get_attribute 方法来获取元素的属性值,比如要获取元素属性class的值,就可以使用 element.get_attribute(‘class’)
练习靶场:https://www.byhy.net/_files/stock1.html
练习目标:获取“包钢股份”的属性值
上手Selenium_第21张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

browser = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))

# 设置浏览器全屏
browser.maximize_window()
browser.get(r'https://www.byhy.net/_files/stock1.html')

element = browser.find_element(By.ID, '1')
print(element.text + '\n')
print(element.get_attribute('class'))

input()

# 结果
包钢股份
代码:600010

result-item

获取整个元素对应的HTML

要获取整个元素对应的HTML文本内容,可以使用element.get_attribute('outerHTML')
如果,只是想获取某个元素内部的HTML文本内容,可以使用element.get_attribute('innerHTML')
测试靶场:https://www.byhy.net/_files/stock1.html
上手Selenium_第22张图片
上手Selenium_第23张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

browser = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))

browser.get(r'https://www.byhy.net/_files/stock1.html')

element = browser.find_element(By.ID, '1')

# 获取整个元素对应的HTML文本内容
print(element.get_attribute('outerHTML'))
# 获取某个元素内部的HTML文本内容
print(element.get_attribute('innerHTML'))

browser.close()

frame切入切出

获取frame元素或者iframe元素的内部数据时,需要先切入进去才能获取。

测试网站:https://cdn2.byhy.net/files/selenium/sample2.html
上手Selenium_第24张图片
假设我们要获取所有的植物,但是会发现下面的代码运行结果为空。仔细观察源代码会发现,要找的植物位于iframe中。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample2.html')

# 根据 class name 选择元素,返回的是 一个列表
elements = wd.find_elements(By.CLASS_NAME, 'plant')

for element in elements:
    print(element.text)

在html语法中,frame元素或者iframe元素的内部会包含一个被嵌入的另一份html文档。在我们使用selenium打开一个网页时,我们的操作范围缺省是当前的html,并不包含被嵌入的html文档里面的内容。如果我们要操作被嵌入的html文档中的元素,就必须切换操作范围到被嵌入的文档中。
使用 WebDriver 对象的 switch_to 属性进行切换,像这样:wd.switch_to.frame(frame_reference)
其中, frame_reference 可以是 frame 元素的属性 name 或者 ID。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample2.html')

# 切换到iframe中
wd.switch_to.frame('frame1')

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

# 结果
土豆
洋葱
白菜

还可以通过 frame 所对应的 WebElement 对象切换进去:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample2.html')

# 切换到iframe中
element = wd.find_element(By.CSS_SELECTOR, 'iframe[src="sample1.html"]')
wd.switch_to.frame(element)

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


# 结果
土豆
洋葱
白菜

最后,演示切入和切出,并获取点击“外部按钮”点出来的内容
上手Selenium_第25张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/sample2.html')

# 切换到iframe中,获取植物
# element = wd.find_element(By.CSS_SELECTOR, 'iframe[src="sample1.html"]')
# wd.switch_to.frame(element)
wd.switch_to.frame('frame1')

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

# 切出,回到最外部的HTML中
wd.switch_to.default_content()

# 点击外部的一个按钮
wd.find_element(By.ID, 'outerbutton').click()

# 获取点击出来的内容
elements = wd.find_elements(By.CSS_SELECTOR, '#add li')
for element in elements:
    print(element.get_attribute('outerHTML'))

time.sleep(2)
wd.quit()

# 结果
土豆
洋葱
白菜
<li>你点击了外部按钮</li>

高级方法1:模拟鼠标

这里需要导入ActionChains 类:

from selenium.webdriver.common.action_chains import ActionChains

鼠标移动

目标:让鼠标移动到百度首页的“更多”那里。
上手Selenium_第26张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://www.baidu.com/')

from selenium.webdriver.common.action_chains import ActionChains
ac = ActionChains(wd)

# 获取移动的位置 对应的元素
element = wd.find_element(By.CSS_SELECTOR, '[name="tj_briicon"]')
# 移动到指定位置
ac.move_to_element(element).perform()

time.sleep(3)

wd.quit()

鼠标左右键

左键就是click(),很多地方都有演示。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)  # 最久等待10秒
wd.get('https://www.byhy.net/_files/stock1.html')
time.sleep(2)

# 输入
element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯')
time.sleep(2)

# 点击
element = wd.find_element(By.ID, 'go')
element.click()

time.sleep(2)
wd.quit()

鼠标右键:

  • ActionChains(wd):调用ActionChains()类,并将浏览器驱动browser作为参数传入
  • context_click(right_click):模拟鼠标双击,需要传入指定元素定位作为参数
  • perform():执行ActionChains()中储存的所有操作,可以看做是执行之前一系列的操作
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://www.baidu.com/')

# 定位到要右击的元素,这里选的新闻链接
right_click = wd.find_element(By.LINK_TEXT, '新闻')

# 执行鼠标右键操作
ActionChains(wd).context_click(right_click).perform()
time.sleep(2)

# 关闭浏览器
wd.close()

鼠标拖拽

使用方法:drag_and_drop(source,target)
演示靶场:https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable
上手Selenium_第27张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChains
import time

browser = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
browser.implicitly_wait(10)
browser.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
time.sleep(2)

# 切入 iframe
browser.switch_to.frame('iframeResult')

# 开始位置
source = browser.find_element(By.CSS_SELECTOR, '#draggable')

# 结束位置
target = browser.find_element(By.CSS_SELECTOR, "#droppable")

# 执行元素的拖放操作
ActionChains(browser).drag_and_drop(source, target).perform()
time.sleep(5)

# 关闭浏览器
browser.close()

元素的选择方法

在selenium自动化中,最最常用的操作就是点击和输入,要实现这个操作,经常会碰到的一个问题就是怎么找到点击和输入的位置?有以下几种方法帮助我们找到这些位置。

基本方法

记不全没关系,下面有好用的CSS表达式

根据 id属性 选择元素

我们可以把 id 想象成元素的编号, 是用来在html中标记该元素的。根据规范, 如果元素有id属性 ,这个id 必须是当前html中唯一的。所以如果元素有id, 根据id选择元素是最简单高效的方式。
练习靶场:https://www.byhy.net/_files/stock1.html
实现目标:查询股票代码

  1. 获取id属性

上手Selenium_第28张图片

  1. 运行代码。这里一旦进入断点,页面中就会执行输入“通讯”,并且执行回车键,于是就查询出了结果。

上手Selenium_第29张图片
如果我不使用回车键,而是想点击“查询”按钮呢?
上手Selenium_第30张图片
上手Selenium_第31张图片
代码如下:

  • 第11行代码:发起一个请求通过浏览器驱动转发给浏览器,告诉它,需要选择一个idkw的元素。浏览器 找到idkw的元素后,将结果通过 浏览器驱动 返回给 自动化程序, 所以 find_element 方法会返回一个 WebElement 类型的对象。这个WebElement 对象可以看成是对应 页面元素的遥控器。我们通过这个WebElement对象,就可以 操控对应的界面元素。
from selenium import webdriver
from selenium.webdriver.common.by import By

# 创建 WebDriver 对象
wd = webdriver.Chrome()

# 调用WebDriver 对象的get方法 可以让浏览器打开指定网址
wd.get('https://www.byhy.net/_files/stock1.html')

# 根据id选择元素,返回的就是该元素对应的WebElement对象
element = wd.find_element(By.ID, 'kw')

# 通过该 WebElement对象,就可以对页面元素进行操作了
# 比如输入字符串到 这个 输入框里
element.send_keys('通讯')

element = wd.find_element(By.ID,'go')
element.click()

# 正常结束程序
wd.quit()

根据 class属性 选择元素

web自动化的难点和重点之一,就是如何 选择 我们想要操作的web页面元素。
除了根据元素的id ,我们还可以根据元素的 class 属性选择元素。
练习靶场:https://cdn2.byhy.net/files/selenium/sample1.html
练习根据class属性选择元素
可以看到,所有的植物元素都有个class属性值为 plant,所有的动物元素都有个class属性值为 animal。
上手Selenium_第32张图片
假设我要获取所有的动物:
于是得到脚本:

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

# 创建 WebDriver 实例对象,指明使用chrome浏览器驱动
wd = webdriver.Chrome()

# WebDriver 实例对象的get方法 可以让浏览器打开指定网址
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

# 根据 class name 选择元素,返回的是 一个列表
# 里面 都是class 属性值为 animal的元素对应的 WebElement对象
elements = wd.find_elements(By.CLASS_NAME, 'animal')

# 取出列表中的每个 WebElement对象,打印出其text属性的值
# text属性就是该 WebElement对象对应的元素在网页中的文本内容
for element in elements:
    print(element.text)

# 结果
狮子
老虎
山羊

注意事项:
如果把wd.find_elements(By.CLASS_NAME, 'animal')改为wd.find_element(By.CLASS_NAME, 'animal'),那么返回的就是第一个class 属性为 animal 的元素, 也就是“狮子”
上手Selenium_第33张图片

根据 tag名 选择元素

练习靶场:https://cdn2.byhy.net/files/selenium/sample1.html
我们可以通过指定参数为By.TAG_NAME,选择所有的tag名为 div 的元素,如下所示:

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

wd = webdriver.Chrome()

wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

# 根据 tag name 选择元素,返回的是 一个列表
# 里面 都是 tag 名为 div 的元素对应的 WebElement对象
elements = wd.find_elements(By.TAG_NAME, 'div')

# 取出列表中的每个 WebElement对象,打印出其text属性的值
# text属性就是该 WebElement对象对应的元素在网页中的文本内容
for element in elements:
    print(element.text)
    

上手Selenium_第34张图片
升级一下,混合 id 属性和 tag 属性,来获取结果。
目标:获取红框中的数据
上手Selenium_第35张图片

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

element = wd.find_element(By.ID, 'container')
# 限制 选择元素的范围是 id 为 container 元素的内部。
spans = element.find_elements(By.TAG_NAME, 'span')
for span in spans:
    print(span.text)

# 结果
内层11
内层12
内层21

在后面学习了CSS表达式后,可以通过获取后代元素的方式简化代码:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

elements = wd.find_elements(By.CSS_SELECTOR, '#container  span')

for element in elements:
    print(element.text)

根据 link定位、partial定位

这种方法顾名思义就是用来定位文本链接的:
上手Selenium_第36张图片

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://www.baidu.com/')

# 使用CSS表达式
# wd.find_element(By.CSS_SELECTOR, '[href="http://news.baidu.com"]').click()

# 使用基本方法
wd.find_element(By.LINK_TEXT, '新闻').click()

time.sleep(6)
wd.close()

有时候一个超链接的文本很长,我们如果全部输入,既麻烦,又显得代码很不美观,这时候我们就可以只截取一部分字符串,用这种方法模糊匹配了。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://www.baidu.com/')

# 模糊匹配“新闻”中的部分字符
wd.find_element(By.PARTIAL_LINK_TEXT, '闻').click()

time.sleep(6)
wd.close()

CSS表达式

如果我们要选择的元素没有id、class属性,或者有些我们不想选择的元素也有相同的id、class属性值,怎么办呢?这时候我们通常可以通过CSS selector语法选择元素。这是一种很强大好用的选择方法。
练习靶场:https://cdn2.byhy.net/files/selenium/sample1.html

根据 tag名、id、class 选择元素

CSS Selector同样可以根据tag名、id属性和class属性来选择元素。
1.1 根据tag名选择元素的CSS Selector语法非常简单,直接写上tag名即可,比如要选择所有的tag名为div的元素,就可以是这样,下面第8行和第9行代码功能是一样的。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

# elements = wd.find_elements(By.TAG_NAME, 'div')
elements = wd.find_elements(By.CSS_SELECTOR, 'div')

for element in elements:
    print(element.text)

wd.close()

1.2 根据id属性选择元素的语法是在id号前面加上一个井号: #id值
尝试在下面的输入框中输入内容
上手Selenium_第37张图片
上手Selenium_第38张图片
下面第8行和第9行代码功能是一样的。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

# element = wd.find_element(By.ID, 'searchtext')
element = wd.find_element(By.CSS_SELECTOR, '#searchtext')

element.send_keys('你好啊')

wd.close()

1.3 根据class属性选择元素的语法是在 class 值 前面加上一个点: .class值
下面第8行和第9行代码功能是一样的。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

# elements = wd.find_elements(By.CLASS_NAME, 'animal')
elements = wd.find_elements(By.CSS_SELECTOR, '.animal')

for element in elements:
    print(element.text)

# 结果
狮子
老虎
山羊

根据属性选择

css选择器专门提供了常用属性 id、class 选择的语法,那么其他的属性呢?
css 选择器支持通过任何属性来选择元素,语法是用一个方括号 [] 。
举例:我想获取这个链接地址
上手Selenium_第39张图片
测试代码如下:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

elements = wd.find_elements(By.CSS_SELECTOR, '[href="http://www.miitbeian.gov.cn"]')

for element in elements:
    print(element.get_attribute('outerHTML'))
wd.quit()

# 结果
<a href="http://www.miitbeian.gov.cn">苏ICP备88885574</a>

CSS还可以选择属性值包含某个字符串的元素比如,要选择a节点,里面的href属性包含了miitbeian字符串,就可以这样写:a[href*="miitbeian"]

# 还可以选择属性值以某个字符串开头的元素。
# 比如,要选择a节点,里面的href属性以http开头,就可以这样写
a[href^="http"]

# 还可以选择属性值以某个字符串结尾的元素。比如,
# 要选择a节点,里面的href属性以gov.cn结尾,就可以这样写
a[href$="gov.cn"]

子元素、后代元素、逻辑或

练习靶场:https://cdn2.byhy.net/files/selenium/sample1.html
网页代码如下所示:

  • id 为 container 的div元素直接包含了 id 为 layer1 和 layer2 的两个div元素
  • id 为 container 的div元素间接包含了id 为 inner11 、inner12 、inner22 的元素和三个span类型的元素
  • layer1 和 layer2是container的直接子元素
  • inner11 、inner12 、inner22、layer1、layer2是container的后代元素
<div id='container'>
    <div id='layer1'>
        <div id='inner11'>
            <span>内层11span>
        div>
        <div id='inner12'>
            <span>内层12span>
        div>
    div>
    <div id='layer2'>
        <div id='inner21'>
            <span>内层21span>
        div>
    div>
div>

上面的说法看懂看不懂无所谓,代码演示一下就懂了:
使用右箭头获取直接子元素

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

elements = wd.find_elements(By.CSS_SELECTOR, '#container  div')

for element in elements:
    print(element.get_attribute('outerHTML'))
    print('-----------------')

wd.quit()

上手Selenium_第40张图片
使用空格获取后代元素
上手Selenium_第41张图片
现在尝试获取所有的植物:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')

elements = wd.find_elements(By.CSS_SELECTOR, '.plant  span')

for element in elements:
    print(element.get_attribute('outerHTML'))
    print(element.text)
    print('-----------------')

wd.quit()

上手Selenium_第42张图片
验证CSS Selector
通过在浏览器中输入CSS Selector语法,可以很方便的判断语法是否正确,是否符合效果。
避免了在开发工具中反复调试代码。F12 ➡ Ctrl+F
上手Selenium_第43张图片
进一步精准定位:#bottom > .footer1 span.copyright
上手Selenium_第44张图片
**逻辑或:**使用逗号进行分割,运行优先级低
案例1:获取所有的动物和植物
测试网站:https://cdn2.byhy.net/files/selenium/sample1.html
使用“逻辑或”直接获取:.plant,.animal
上手Selenium_第45张图片
案例2:获取唐诗中的所有作品和作者
测试网站:https://cdn2.byhy.net/files/selenium/sample1a.html
由于“逻辑或”的优先级低,因此使用:#t1 span , #t1 p
上手Selenium_第46张图片
父元素的第n个子节点
我们可以指定选择的元素是父元素的第几个子节点,使用nth-child
案例1:
测试网站:https://cdn2.byhy.net/files/selenium/sample1b.html
使用:span:nth-child(2),获取第2个子元素是span的数据
上手Selenium_第47张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/sample1b.html')

elements = wd.find_elements(By.CSS_SELECTOR, 'span:nth-child(2)')
for element in elements:
    print(element.get_attribute('outerHTML'))
wd.quit()

# 结果
<span>李白</span>
<span>苏轼</span>

案例2:由于没有指明第2个子节点的标签名,因此所有的第2个子节点都会被选上。:nth-child(2)
上手Selenium_第48张图片
这个东西可以正着数,也可以倒着数,如:父元素的倒数第n个子节点
使用:nth-last-child
测试网站:https://cdn2.byhy.net/files/selenium/sample1b.html
目标:获取父元素倒数第1个子节点是p类型的:p:nth-last-child(1)
上手Selenium_第49张图片
父元素的第几个某类型的子节点
我们可以指定选择的元素是父元素的第几个某类型的子节点,使用nth-of-type
举例如下,p:nth-of-type(2)匹配的子节点类型是p,这个p是第二个。
可以通俗的理解为,要从闺女(span)、侄子(span)、儿子(p)中寻找二儿子。
上手Selenium_第50张图片
这个东西可以正着数,也可以倒着数,如:父元素的倒数第几个某类型的子节点
p:nth-last-of-type(2):获取子节点是p的,倒数第二个p
上手Selenium_第51张图片

奇数节点和偶数节点

如果要选择的是父元素的 偶数节点,使用 nth-child(even)
如果要选择的是父元素的 奇数节点,使用 nth-child(odd)
上手Selenium_第52张图片

兄弟节点选择

相邻兄弟节点选择,使用+进行选择
p + span:p后面的同级别节点,第一个是span的就选上
上手Selenium_第53张图片
后续所有兄弟节点选择,使用~进行选择
h3 ~ span:h3后面的同级别节点,只要是span,就全选上
上手Selenium_第54张图片
更多CSS选择器的介绍,可以参考 CSS 选择器参考手册

Xpath选择器

上面已经学习了CSS,为什么还要学习 Xpath呢? 因为:

  • 有些场景用 css 选择 web 元素 很麻烦,而xpath却比较方便。
  • 另外 Xpath 还有其他领域会使用到,比如爬虫框架 Scrapy, 手机App框架 Appium。

测试网站:https://cdn2.byhy.net/files/selenium/test1.html

绝对路径、相对路径

**绝对路径:**从根节点开始,到某个节点,每层都依次写下来,每层之间用 / 分隔的表达式。
可以通过浏览器直接复制出绝对路径,十分方便,假设我这里要获取所有的城市。
上手Selenium_第55张图片
上手Selenium_第56张图片
上手Selenium_第57张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(5)
wd.get(r'https://cdn2.byhy.net/files/selenium/test1.html')

elements = wd.find_elements(By.XPATH,'/html/body/div/div/div//p')

for element in elements:
    print(element.text)

wd.close()

# 结果
北京
上海
纽约
休斯顿
芝加哥

**相对路径:**用//开始,选择内部直接子节点使用/,选择内部所有子节点使用//
我还是习惯使用绝对路径,然后微调获取所有的外国城市://div/span/p
上手Selenium_第58张图片

通配符

如果要选择所有div节点的所有直接子节点,可以使用表达式//div/*
*是一个通配符,对应任意节点名的元素,等价于CSS选择器div > *
代码如下:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(5)
wd.get(r'https://cdn2.byhy.net/files/selenium/test1.html')

elements = wd.find_elements(By.XPATH, '//div/*')
for element in elements:
    print(element.get_attribute('outerHTML'))

wd.close()

根据属性选择

Xpath 可以根据属性来选择元素。
根据属性来选择元素是通过这种格式来的 [@属性名=‘属性值’]
注意:

  • 属性名注意前面有个@
  • 属性值一定要用引号, 可以是单引号,也可以是双引号

方式1:根据id属性选择
选择 id 为 west 的元素,可以这样//*[@id='west']/p
上手Selenium_第59张图片
方式2:根据class属性选择
选择所有 select 元素中 class 为 single_choice 的元素,可以这样//select[@class='single_choice']
方式3:其他属性
比如选择具有 multiple 属性的所有页面元素 ,可以这样//*[@multiple](因为没有值,所以只写属性)
上手Selenium_第60张图片
方式4:包含某字符
要选择 style 属性值包含 color 字符串的页面元素,可以这样//*[contains(@style,'color')]
要选择 style 属性值以 color 字符串 开头 的页面元素 ,可以这样//*[starts-with(@style,'color')]
要选择 style 属性值以某个字符串结尾的页面元素,大家推测是 //*[ends-with(@style,'color')], 但是很遗憾,这是xpath 2.0 的语法 ,目前浏览器支持的是 xpath 1的语法。

选择第几个

  1. 要选择p类型第2个的子元素,就是://p[2]

注意,选择的是 p 类型第2个的子元素;并非选择第2个子元素类型是p。

  1. 选择父元素为div的第2个子元素,不管是什么类型://div/*[2]
  2. 选取p类型倒数第1个子元素://p[last()]
  3. 选取p类型倒数第2个子元素://p[last()-1]

范围选择

xpath还可以选择子元素的次序范围。

  1. 选取option类型第1到2个子元素://option[position()<=2]或者//option[position()<3]
  2. 选择class属性为multi_choice的前3个子元素://*[@class='multi_choice']/*[position()<=3]
  3. 选择class属性为multi_choice的后3个子元素:
//*[@class='multi_choice']/*[position()>=last()-2]

为什么不是 last()-3 呢? 因为:
last() 本身代表最后一个元素
last()-1 本身代表倒数第2个元素
last()-2 本身代表倒数第3个元素

逻辑或、父节点、兄弟节点✨

逻辑或
css有组选择(这里我称为“逻辑或”),可以同时使用多个表达式,多个表达式选择的结果都是要选择的元素。
比如,要选所有的option元素 和所有的 h4 元素,可以使用:

Xpath选择的语法
//option | //h4

等同于CSS选择器
option , h4

再比如,要选所有的 class属性为 single_choice 和 class属性为 multi_choice 的元素,可以使用:

Xpath选择的语法
//*[@class='single_choice'] | //*[@class='multi_choice']

等同于CSS选择器
.single_choice , .multi_choice

选择父节点⭐
Xpath可以选择父节点, 这是css做不到的。某个元素的父节点用 /.. 表示。
如果某个元素没有特征,但是它的子节点有特征, 就可以采用这种方法。
比如,要选择 id 为 china 的节点的父节点,可以这样写//*[@id='china']/..
后续兄弟节点
前面学过css选择器,要选择某个节点的后续兄弟节点,用波浪线。
Xpath也可以选择后续兄弟节点,用这样的语法following-sibling::
比如,要选择 class 为 single_choice 的元素的所有后续兄弟节点

Xpath选择的语法
//*[@class='single_choice']/following-sibling::*

等同于CSS选择器
.single_choice ~ *

前面兄弟节点
xpath还可以选择前面的兄弟节点,用这样的语法preceding-sibling::

要选择 class 为 single_choice 的元素的 所有 前面的兄弟节点,这样写
//*[@class='single_choice']/preceding-sibling::*

要选择 class 为 single_choice 的元素的前面最靠近的兄弟节点 , 这样写
//*[@class='single_choice']/preceding-sibling::*[1]

前面第2靠近的兄弟节点 , 这样写
//*[@class='single_choice']/preceding-sibling::*[2]

而 CSS选择器 目前还没有方法选择 前面的 兄弟节点!
更多Xpath语法,参见:XPath 教程

元素的选择场景:选择框

常见的选择框包括: radio框、checkbox框、select框
测试网址:https://cdn2.byhy.net/files/selenium/test2.html
请注意,演示的网站存在问题,点选其他框后,check不会发生变化,因此不再获取点选之后的结果了。
上手Selenium_第61张图片

radio框

目标:先打印当前选中的老师名字,再选择小雷老师
网页代码:

<div id="s_radio">
  <input type="radio" name="teacher" value="小江老师">小江老师<br>
  <input type="radio" name="teacher" value="小雷老师">小雷老师<br>
  <input type="radio" name="teacher" value="小凯老师" checked="checked">小凯老师
div>

开发代码如下:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/test2.html')

# 获取当前选中的元素
element = wd.find_element(By.CSS_SELECTOR, '#s_radio input[checked="checked"]')
print('当前选中的是:' + element.get_attribute('value'))
time.sleep(3)

# 点选 小雷 老师
wd.find_element(By.CSS_SELECTOR, '#s_radio input[value="小雷老师"]').click()
time.sleep(3)

wd.quit()

checkbox框

这种框可以多选。如果某个选项已经勾选了,再点击会取消选择。
上手Selenium_第62张图片
目标:只勾选小雷老师
思路:先把已经选中的选项全部点击一下,然后再单独点击目标按钮

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/test2.html')

# 获取当前选中的元素,由于可能有多个按钮被选中,因此使用 find_elements
elements = wd.find_elements(By.CSS_SELECTOR, '#s_checkbox input[checked="checked"]')
for element in elements:
    print('当前选中的是:' + element.get_attribute('value'))
    element.click()
time.sleep(3)

# 点选 小雷 老师
wd.find_element(By.CSS_SELECTOR, '#s_checkbox input[value="小雷老师"]').click()
time.sleep(3)

wd.quit()

select框

radio框及checkbox框都是input元素,只是里面的type不同而已。select框则是一个新的select标签,Selenium专门提供了一个Select类进行操作。Select类提供了如下的方法:

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

# 根据选项的次序(从1开始),选择元素
select_by_index

# 根据选项的可见文本,选择元素
select_by_visible_text
# 根据选项的value属性值,去除选中元素
deselect_by_value

# 根据选项的次序,去除选中元素
deselect_by_index

# 根据选项的可见文本,去除选中元素
deselect_by_visible_text

# 去除选中所有元素
deselect_all

Select单选框

Select单选框操作比较简单:不管原来选的是什么,直接用Select方法重新选择即可。
例如,选择示例里面的小雷老师,示例代码如下:
上手Selenium_第63张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import Select
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/test2.html')

element = wd.find_element(By.ID, 'ss_single')
select = Select(element)  # 创建Select对象

# 通过 Select 对象选中小雷老师
select.select_by_visible_text("小江老师")
time.sleep(3)

wd.quit()

Select多选框

用select类的deselect_all方法,全部取消勾选
select_by_visible_text方法选择 小雷老师 和 小凯老师
上手Selenium_第64张图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import Select
import time

wd = webdriver.Chrome(service=Service(r'D:\tools\selenium\chromedriver.exe'))
wd.get('https://cdn2.byhy.net/files/selenium/test2.html')

# 创建Select对象
element = wd.find_element(By.CSS_SELECTOR, '#ss_multi')
select = Select(element)

# 清除所有 已经选中 的选项
select.deselect_all()

# 选择小雷老师 和 小凯老师
select.select_by_visible_text("小雷老师")
select.select_by_visible_text("小凯老师")

time.sleep(3)
wd.quit()

参考

2万字带你了解Selenium全攻略
2万字带你了解Selenium全攻略_selenium 2万字 教程_可以叫我才哥的博客-CSDN博客
原理与安装 | 白月黑羽

你可能感兴趣的:(python,selenium)