Selenium-5

 五、frame切换/窗口切换

1、切换到frame

如果我们要 选择 下图方框中 所有的 蔬菜,使用css选择,怎么写表达式?

当然,要先查看到它们的html元素特征

image

大家可能会照旧写出如下代码:

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

wd = webdriver.Chrome()

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)

运行一下,你就会发现,运行结果打印内容为空白,说明没有选择到 class 属性值为 plant 的元素。

为什么呢?

因为仔细看,你可以发现, 这些元素是在一个叫 iframe的 元素中的。

image

这个 iframe 元素非常的特殊, 在html语法中,frame 元素 或者iframe元素的内部 会包含一个 被嵌入的 另一份html文档。

在我们使用selenium打开一个网页是, 我们的操作范围 缺省是当前的 html , 并不包含被嵌入的html文档里面的内容。

如果我们要 操作 被嵌入的 html 文档 中的元素, 就必须 切换操作范围 到 被嵌入的文档中。

怎么切换呢?

使用 WebDriver 对象的 switch_to 属性,像这样

wd.switch_to.frame(frame_reference)

其中, frame_reference 可以是 frame 元素的属性 name 或者 ID 。

比如这里,就可以填写 iframe元素的id 'frame1' 或者 name属性值 'innerFrame'。

像这样

wd.switch_to.frame('frame1')

或者

wd.switch_to.frame('innerFrame')

也可以填写frame 所对应的 WebElement 对象。

我们可以根据frame的元素位置或者属性特性,使用find系列的方法,选择到该元素,得到对应的WebElement对象

比如,这里就可以写

wd.switch_to.frame(wd.find_element(By.TAG_NAME, "iframe"))

然后,就可以进行后续操作frame里面的元素了。

上面的例子的正确代码如下

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

wd = webdriver.Chrome()

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


# 先根据name属性值 'innerFrame',切换到iframe中
wd.switch_to.frame('innerFrame')

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

for element in elements:
    print(element.text)

如果我们已经切换到某个iframe里面进行操作了,那么后续选择和操作界面元素 就都是在这个frame里面进行的。

这时候,如果我们又需要操作 主html(我们把最外部的html称之为主html) 里面的元素了呢?

怎么切换回原来的主html呢?

很简单,写如下代码即可

wd.switch_to.default_content()

例如,在上面 代码 操作完 frame里面的元素后, 需要 点击 主html 里面的按钮,就可以这样写

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

wd = webdriver.Chrome()

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


# 先根据name属性值 'innerFrame',切换到iframe中
wd.switch_to.frame('innerFrame')

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

for element in elements:
    print(element.text)

# 切换回 最外部的 HTML 中
wd.switch_to.default_content()

# 然后再 选择操作 外部的 HTML 中 的元素
wd.find_element_by_id('outerbutton').click()

wd.quit()

2、切换到新的窗口

在网页上操作的时候,我们经常遇到,点击一个链接 或者 按钮,就会打开一个 新窗口 。

请大家点击这里,打开这个链接

在打开的网页中,点击 链接 访问bing网站 , 就会弹出一个新窗口,访问bing网址。

如果我们用Selenium写自动化程序 在新窗口里面 打开一个新网址, 并且去自动化操作新窗口里面的元素,会有什么问题呢?

问题就在于,即使新窗口打开了, 这时候,我们的 WebDriver对象对应的 还是老窗口,自动化操作也还是在老窗口进行,

我们可以运行如下代码验证一下

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

wd = webdriver.Chrome()
wd.implicitly_wait(10)

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

# 点击打开新窗口的链接
link = wd.find_element(By.TAG_NAME, "a")
link.click()

# wd.title属性是当前窗口的标题栏 文本
print(wd.title)

运行完程序后,最后一行 打印当前窗口的标题栏 文本, 输出内容是

白月黑羽测试网页3

说明, 我们的 WebDriver对象指向的还是老窗口,否则的话,运行结果就应该新窗口的标题栏 "微软Bing搜索"

如果我们要到新的窗口里面操作,该怎么做呢?

可以使用Webdriver对象的switch_to属性的 window方法,如下所示:

wd.switch_to.window(handle)

其中,参数handle需要传入什么呢?

WebDriver对象有window_handles 属性,这是一个列表对象, 里面包括了当前浏览器里面所有的窗口句柄

所谓句柄,大家可以想象成对应网页窗口的一个ID,

那么我们就可以通过 类似下面的代码,

for handle in wd.window_handles:
    # 先切换到该窗口
    wd.switch_to.window(handle)
    # 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
    if 'Bing' in wd.title:
        # 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
        break

上面代码的用意就是:

我们依次获取 wd.window_handles 里面的所有 句柄 对象, 并且调用 wd.switch_to.window(handle) 方法,切入到每个窗口,

然后检查里面该窗口对象的属性(可以是标题栏,地址栏),判断是不是我们要操作的那个窗口,如果是,就跳出循环。


同样的,如果我们在新窗口 操作结束后, 还要回到原来的窗口,该怎么办?

我们可以仍然使用上面的方法,依次切入窗口,然后根据 标题栏 之类的属性值判断。

还有更省事的方法。

因为我们一开始就在 原来的窗口里面,我们知道 进入新窗口操作完后,还要回来,可以事先 保存该老窗口的 句柄,使用如下方法

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

切换到新窗口操作完后,就可以直接像下面这样,将driver对应的对象返回到原来的窗口

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

六、选择框

请点击打开这个网址

并且按F12,观察HTML的内容

常见的选择框包括: radio框、checkbox框、select框

1、radio框

radio框选择选项,直接用WebElement的click方法,模拟用户点击就可以了。

比如, 我们要在下面的html中:

  • 先打印当前选中的老师名字
  • 再选择 小雷老师
<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>

对应的代码如下

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

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

其中 #s_radio input[name="teacher"]:checked 里面的 :checked 是CSS伪类选择

表示选择 checked 状态的元素,对 radio 和 checkbox 类型的input有效

2、checkbox框

对checkbox进行选择,也是直接用 WebElement 的 click 方法,模拟用户点击选择。

需要注意的是,要选中checkbox的一个选项,必须 先获取当前该复选框的状态 ,如果该选项已经勾选了,就不能再点击。否则反而会取消选择。

比如, 我们要在下面的html中:选中 小雷老师

<div id="s_checkbox">
  <input type="checkbox" name="teacher" value="小江老师">小江老师<br>
  <input type="checkbox" name="teacher" value="小雷老师">小雷老师<br>
  <input type="checkbox" name="teacher" value="小凯老师" checked="checked">小凯老师
</div>

我们的思路可以是这样:

  • 先把 已经选中的选项全部点击一下,确保都是未选状态
  • 再点击 小雷老师

示例代码

# 先把 已经选中的选项全部点击一下
elements = wd.find_elements(By.CSS_SELECTOR, 
  '#s_checkbox input[name="teacher"]:checked')

for element in elements:
    element.click()

# 再点击 小雷老师
wd.find_element(By.CSS_SELECTOR, 
  "#s_checkbox input[value='小雷老师']").click()

3、select框

radio框及checkbox框都是input元素,只是里面的type不同而已。

select框 则是一个新的select标签,大家可以对照浏览器网页内容查看一下

对于Select 选择框, Selenium 专门提供了一个 Select类 进行操作。

Select类 提供了如下的方法

  • select_by_value

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

比如,下面的HTML,

<option value="foo">Bar</option>

就可以根据 foo 这个值选择该选项,

s.select_by_value('foo')
  • select_by_index

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

注意:视频讲解中用的是老版本的seleium,那时是从 1 开始,

现在Selenium 4 是从 0 开始,

select_by_index(0) ,选择的是 第1个选项,

select_by_index(1) ,选择的是 第2个选项, 依此类推

  • select_by_visible_text

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

比如,下面的HTML,

<option value="foo">Bar</option>

就可以根据 Bar 这个内容,选择该选项

s.select_by_visible_text('Bar')
  • deselect_by_value

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

  • deselect_by_index

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

  • deselect_by_visible_text

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

  • deselect_all

去除 选中所有元素

Select单选框

对于 select单选框,操作比较简单:

不管原来选的是什么,直接用Select方法选择即可。

例如,选择示例里面的小雷老师,示例代码如下

# 导入Select类
from selenium.webdriver.support.ui import Select

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

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

Select多选框

对于select多选框,要选中某几个选项,要注意去掉原来已经选中的选项。

例如,我们选择示例多选框中的 小雷老师 和 小凯老师

可以用select类 的deselect_all方法,清除所有 已经选中 的选项。

然后再通过 select_by_visible_text方法 选择 小雷老师 和 小凯老师。

示例代码如下:

# 导入Select类
from selenium.webdriver.support.ui import Select

# 创建Select对象
select = Select(wd.find_element(By.ID, "ss_multi"))

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

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

七、实战技巧

1、ActionChains 类

之前我们对web元素做的操作主要是:选择元素,然后 点击元素 或者 输入 字符串。

还有没有其他的操作了呢?

有。

比如:比如 鼠标右键点击、双击、移动鼠标到某个元素、鼠标拖拽等。

这些操作,可以通过 Selenium 提供的 ActionChains 类来实现。

ActionChains 类 里面提供了 一些特殊的动作的模拟,我们可以通过 ActionChains 类的代码查看到,如下所示

image

我们以移动鼠标到某个元素为例。

百度首页的右上角,有个 更多产品 选项,如下图所示

image

如果我们把鼠标放在上边,就会弹出 下面的 糯米、音乐、图片 等图标。

使用 ActionChains 来 模拟鼠标移动 操作的代码如下:

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

driver = webdriver.Chrome()
driver.implicitly_wait(5)

driver.get('https://www.baidu.com/')

from selenium.webdriver.common.action_chains import ActionChains

ac = ActionChains(driver)

# 鼠标移动到 元素上
ac.move_to_element(
    driver.find_element(By.CSS_SELECTOR, '[name="tj_briicon"]')
).perform()

2、直接执行javascript

我们可以直接让浏览器运行一段javascript代码,并且得到返回值,如下

# 直接执行 javascript,里面可以直接用return返回我们需要的数据
nextPageButtonDisabled = driver.execute_script(
    '''
    ele = document.querySelector('.soupager > button:last-of-type');
    return ele.getAttribute('disabled')
    ''')

# 返回的数据转化为Python中的数据对象进行后续处理
if nextPageButtonDisabled == 'disabled': # 是最后一页
    return True
else: # 不是最后一页
    return False


 

有时,自动化的网页内容很长,或者很宽,超过一屏显示,

如果我们要点击的元素不在窗口可见区内,新版本的selenium协议, 浏览器发现要操作(比如点击操作)的元素,不在可见区内,往往会操作失败,

出现类似下面的提示

element click intercepted: Element <span>这里是元素html</span> 
is not clickable at point (119, 10). 
Other element would receive the click: <div>...</div>

这时,可以调用 execute_script 直接执行js代码,让该元素出现在窗口可见区正中

driver.execute_script("arguments[0].scrollIntoView({block:'center',inline:'center'})", job) 

其中 arguments[0] 就指代了后面的第一个参数 job 对应的js对象,

js对象的 scrollIntoView 方法,就是让元素滚动到可见部分

block:'center' 指定垂直方向居中

inline:'center' 指定水平方向居中

3、冻结界面

有些网站上面的元素, 我们鼠标放在上面,会动态弹出一些内容。

比如,百度首页的右上角,有个 更多产品 选项,如下图所示

如果我们把鼠标放在上边,就会弹出 下面的 糯米、音乐、图片 等图标。

如果我们要用 selenium 自动化 点击 糯米图标,就需要 F12 查看这个元素的特征。

但是 当我们的鼠标 从 糯米图标 移开, 这个 栏目就整个消失了, 就没法 查看 其对应的 HTML。

怎么办?

可以如下图所示:

在 开发者工具栏 console 里面执行如下js代码

setTimeout(function(){debugger}, 5000)

这句代码什么意思呢?

表示在 5000毫秒后,执行 debugger 命令

执行该命令会 浏览器会进入debug状态。 debug状态有个特性, 界面被冻住, 不管我们怎么点击界面都不会触发事件。

所以,我们可以在输入上面代码并回车 执行后, 立即 鼠标放在界面 右上角 更多产品处。

这时候,就会弹出 下面的 糯米、音乐、图片 等图标。

然后,我们仔细等待 5秒 到了以后, 界面就会因为执行了 debugger 命令而被冻住。

然后,我们就可以点击 开发者工具栏的 查看箭头, 再去 点击 糯米图标 ,查看其属性了。

4、弹出对话框

有的时候,我们经常会在操作界面的时候,出现一些弹出的对话框。

请点击打开这个网址

分别点击界面的3个按钮,你可以发现:

弹出的对话框有三种类型,分别是 Alert(警告信息)、confirm(确认信息)和prompt(提示输入)

Alert

Alert 弹出框,目的就是显示通知信息,只需用户看完信息后,点击 OK(确定) 就可以了。

那么,自动化的时候,代码怎么模拟用户点击 OK 按钮呢?

selenium提供如下方法进行操作

driver.switch_to.alert.accept()

注意

注意:如果我们不去点击它,页面的其它元素是不能操作的。

如果程序要获取弹出对话框中的信息内容, 可以通过 如下代码

driver.switch_to.alert.text

示例代码如下

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

driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('https://cdn2.byhy.net/files/selenium/test4.html')


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

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

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

Confirm

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

比如:当管理员在网站上选择删除某个账号时,就可能会弹出 Confirm弹出框, 要求确认是否确定要删除。

Confirm弹出框 有两个选择供用户选择,分别是 OK 和 Cancel, 分别代表 确定 和 取消 操作。

那么,自动化的时候,代码怎么模拟用户点击 OK 或者 Cancel 按钮呢?

selenium提供如下方法进行操作

如果我们想点击 OK 按钮, 还是用刚才的 accept方法,如下

driver.switch_to.alert.accept()

如果我们想点击 Cancel 按钮, 可以用 dismiss方法,如下

driver.switch_to.alert.dismiss()

示例代码如下

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

driver = webdriver.Chrome()
driver.implicitly_wait(5)

driver.get('https://cdn2.byhy.net/files/selenium/test4.html')

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

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

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

driver.find_element(By.ID, 'b2').click()

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

Prompt

出现 Prompt 弹出框 是需要用户输入一些信息,提交上去。

比如:当管理员在网站上选择给某个账号延期时,就可能会弹出 Prompt 弹出框, 要求输入延期多长时间。

可以调用如下方法

driver.switch_to.alert.send_keys()

示例代码如下

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

driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('https://cdn2.byhy.net/files/selenium/test4.html')


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

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

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

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

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

注意

有些弹窗并非浏览器的alert 窗口,而是html元素,这种对话框,只需要通过之前介绍的选择器选中并进行相应的操作就可以了。

5、其他技巧

下面是一些其他的 Selenium 自动化技巧

窗口大小

有时间我们需要获取窗口的属性和相应的信息,并对窗口进行控制

  • 获取窗口大小
driver.get_window_size()
  • 改变窗口大小
driver.set_window_size(x, y)

获取当前窗口标题

浏览网页的时候,我们的窗口标题是不断变化的,可以使用WebDriver的title属性来获取当前窗口的标题栏字符串。

driver.title

获取当前窗口URL地址

driver.current_url

例如,访问网易,并获取当前窗口的标题和URL

from selenium import  webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(5)

# 打开网站
driver.get('https://www.163.com')

# 获取网站标题栏文本
print(driver.title) 

# 获取网站地址栏文本
print(driver.current_url) 

截屏

有的时候,我们需要把浏览器屏幕内容保存为图片文件。

比如,做自动化测试时,一个测试用例检查点发现错误,我们可以截屏为文件,以便测试结束时进行人工核查。

可以使用 WebDriver 的 get_screenshot_as_file方法来截屏并保存为图片。

from selenium import  webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(5)

# 打开网站
driver.get('https://www.baidu.com/')

# 截屏保存为图片文件
driver.get_screenshot_as_file('1.png')

手机模式

我们可以通过 desired_capabilities 参数,指定以手机模式打开chrome浏览器

参考代码,如下

from selenium import webdriver

mobile_emulation = { "deviceName": "Nexus 5" }

chrome_options = webdriver.ChromeOptions()

chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)

driver = webdriver.Chrome( desired_capabilities = chrome_options.to_capabilities())

driver.get('http://www.baidu.com')

input()
driver.quit()

上传文件

有时候,网站操作需要上传文件。

比如,著名的在线图片压缩网站: TinyPNG – Compress WebP, PNG and JPEG images intelligently

通常,网站页面上传文件的功能,是通过 type 属性 为 file 的 HTML input 元素实现的。

如下所示:

<input type="file" multiple="multiple">

使用selenium自动化上传文件,我们只需要定位到该input元素,然后通过 send_keys 方法传入要上传的文件路径即可。

如下所示:

# 先定位到上传文件的 input 元素
ele = wd.find_element(By.CSS_SELECTOR, 'input[type=file]')

# 再调用 WebElement 对象的 send_keys 方法
ele.send_keys(r'h:\g02.png')

如果需要上传多个文件,可以多次调用send_keys,如下

ele = wd.find_element(By.CSS_SELECTOR,  'input[type=file]')
ele.send_keys(r'h:\g01.png')
ele.send_keys(r'h:\g02.png')

但是,有的网页上传,是没有 file 类型 的 input 元素的。

如果是Windows上的自动化,可以采用 Windows 平台专用的方法:

执行

pip install pypiwin32

确保 pywin32 已经安装,然后参考如下示例代码

# 找到点击上传的元素,点击
driver.find_element(By.CSS_SELECTOR, '.dropzone').click()

sleep(2) # 等待上传选择文件对话框打开

# 直接发送键盘消息给 当前应用程序,
# 前提是浏览器必须是当前应用
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")

# 输入文件路径,最后的'\n',表示回车确定,也可能时 '\r' 或者 '\r\n'
shell.Sendkeys(r"h:\a2.png" + '\n')
sleep(1)

自动化Edge浏览器

点击这里,边看视频讲解,边学习下面的内容

自动化基于Chromium内核的 微软最新Edge浏览器,首先需要查看Edge的版本。

点击菜单 帮助和反馈 > 关于Microsoft Edge ,在弹出界面中,查看到版本,比如

版本 95.0.1020.30 (官方内部版本) (64 位)

然后 点击这里,打开Edge浏览器驱动下载网页 ,并选择下载对应版本的驱动。

在自动化代码中,指定使用Edge Webdriver类,并且指定 Edge 驱动路径,如下所示

from selenium import webdriver

driver = webdriver.Edge(r'd:\tools\webdrivers\msedgedriver.exe')

driver.get('http://www.51job.com')

八、Xpath选择器

1、Xpath语法简介

XPath (XML Path Language) 是由国际标准化组织W3C指定的,用来在 XML 和 HTML 文档中选择节点的语言。

目前主流浏览器 (chrome、firefox,edge,safari) 都支持XPath语法,xpath有 1 和 2 两个版本,目前浏览器支持的是 xpath 1的语法。

既然已经有了CSS,为什么还要学习 Xpath呢? 因为

  • 有些场景 用 css 选择web 元素 很麻烦,而xpath 却比较方便。

  • 另外 Xpath 还有其他领域会使用到,比如 爬虫框架 Scrapy, 手机App框架 Appium。

请点击打开这个网址

按F12打开调试窗口,点击 Elements标签。

要验证 Xpath 语法是否能成功选择元素,也可以像 验证 CSS 语法那样,按组合键 Ctrl + F ,就会出现 搜索框

xpath 语法中,整个HTML文档根节点用'/'表示,如果我们想选择的是根节点下面的html节点,则可以在搜索框输入

/html

如果输入下面的表达式

/html/body/div

这个表达式表示选择html下面的body下面的div元素。

注意 / 有点像 CSS中的 > , 表示直接子节点关系。

绝对路径选择

从根节点开始的,到某个节点,每层都依次写下来,每层之间用 / 分隔的表达式,就是某元素的 绝对路径

上面的xpath表达式 /html/body/div ,就是一个绝对路径的xpath表达式, 等价于 css表达式 html>body>div

自动化程序要使用Xpath来选择web元素,应该调用 WebDriver对象的方法 find_element_by_xpath 或者 find_elements_by_xpath,像这样:

elements = driver.find_elements(By.XPATH, "/html/body/div")

相对路径选择

有的时候,我们需要选择网页中某个元素, 不管它在什么位置 。

比如,选择示例页面的所有标签名为 div 的元素,如果使用css表达式,直接写一个 div 就行了。

那xpath怎么实现同样的功能呢? xpath需要前面加 // , 表示从当前节点往下寻找所有的后代元素,不管它在什么位置。

所以xpath表达式,应该这样写: //div

'//' 符号也可以继续加在后面,比如,要选择 所有的 div 元素里面的 所有的 p 元素 ,不管div 在什么位置,也不管p元素在div下面的什么位置,则可以这样写 //div//p

对应的自动化程序如下

elements = driver.find_elements(By.XPATH, "//div//p")

如果使用CSS选择器,对应代码如下

elements = driver.find_elements(By.CSS_SELECTOR,"div p")

如果,要选择 所有的 div 元素里面的 直接子节点 p , xpath,就应该这样写了 //div/p

如果使用CSS选择器,则为 div > p

通配符

如果要选择所有div节点的所有直接子节点,可以使用表达式 //div/*

* 是一个通配符,对应任意节点名的元素,等价于CSS选择器 div > *

代码如下:

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

2、根据属性选择

Xpath 可以根据属性来选择元素。

根据属性来选择元素 是通过 这种格式来的 [@属性名='属性值']

注意:

  • 属性名注意前面有个@

  • 属性值一定要用引号, 可以是单引号,也可以是双引号

根据id属性选择

选择 id 为 west 的元素,可以这样 //*[@id='west']

根据class属性选择

选择所有 select 元素中 class为 single_choice 的元素,可以这样 //select[@class='single_choice']

如果一个元素class 有多个,比如

<p id="beijing" class='capital huge-city'>
    北京    
</p>

如果要选 它, 对应的 xpath 就应该是 //p[@class="capital huge-city"]

不能只写一个属性,像这样 //p[@class="capital"] 则不行

根据其他属性

同样的道理,我们也可以利用其它的属性选择

比如选择 具有multiple属性的所有页面元素 ,可以这样 //*[@multiple]

属性值包含字符串

要选择 style属性值 包含 color 字符串的 页面元素 ,可以这样 //*[contains(@style,'color')]

要选择 style属性值 以 color 字符串 开头 的 页面元素 ,可以这样 //*[starts-with(@style,'color')]

要选择 style属性值 以 某个 字符串 结尾 的 页面元素 ,大家可以推测是 //*[ends-with(@style,'color')], 但是,很遗憾,这是xpath 2.0 的语法 ,目前浏览器都不支持

3、按次序选择

前面学过css表达式可以根据元素在父节点中的次序选择, 非常实用。

xpath也可以根据次序选择元素。 语法比css更简洁,直接在方括号中使用数字表示次序

比如

某类型 第几个 子元素

比如

要选择 p类型第2个的子元素,就是

//p[2]

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

注意体会区别

再比如,要选取父元素为div 中的 p类型 第2个 子元素

//div/p[2]

第几个子元素

也可以选择第2个子元素,不管是什么类型,采用通配符

比如 选择父元素为div的第2个子元素,不管是什么类型

//div/*[2]

某类型 倒数第几个 子元素

当然也可以选取倒数第几个子元素

比如:

  • 选取p类型倒数第1个子元素
//p[last()]
  • 选取p类型倒数第2个子元素
//p[last()-1]
  • 选择父元素为div中p类型倒数第3个子元素
//div/p[last()-2]

范围选择

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

比如,

  • 选取option类型第1到2个子元素
//option[position()<=2]

或者

//option[position()<3]
  • 选择class属性为multi_choice的前3个子元素
//*[@class='multi_choice']/*[position()<=3]
  • 选择class属性为multi_choice的后3个子元素
//*[@class='multi_choice']/*[position()>=last()-2]

为什么不是 last()-3 呢? 因为

last() 本身代表最后一个元素

last()-1 本身代表倒数第2个元素

last()-2 本身代表倒数第3个元素

4、组选择、父节点、兄弟节点

组选择

css有组选择,可以同时使用多个表达式,多个表达式选择的结果都是要选择的元素

css 组选择,表达式之间用 逗号 隔开

xpath也有组选择, 是用 竖线 隔开多个表达式

比如,要选所有的option元素 和所有的 h4 元素,可以使用

//option | //h4

等同于CSS选择器

option , h4

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

 //*[@class='single_choice'] | //*[@class='multi_choice']

等同于CSS选择器

.single_choice , .multi_choice

选择父节点

xpath可以选择父节点, 这是css做不到的。

某个元素的父节点用 /.. 表示

比如,要选择 id 为 china 的节点的父节点,可以这样写 //*[@id='china']/.. 。

当某个元素没有特征可以直接选择,但是它有子节点有特征, 就可以采用这种方法,先选择子节点,再指定父节点。

还可以继续找上层父节点,比如 //*[@id='china']/../../..

兄弟节点选择

前面学过 css选择器,要选择某个节点的后续兄弟节点,用 波浪线

xpath也可以选择 后续 兄弟节点,用这样的语法 following-sibling::

比如,要选择 class 为 single_choice 的元素的所有后续兄弟节点 //*[@class='single_choice']/following-sibling::*

等同于CSS选择器 .single_choice ~ *

如果,要选择后续节点中的div节点, 就应该这样写 //*[@class='single_choice']/following-sibling::div

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选择器参考手册

5、selenium 注意点

我们来看一个例子

我们的代码:

  • 先选择示例网页中,id是china的元素

  • 然后通过这个元素的WebElement对象,使用find_elements_by_xpath,选择里面的p元素,

# 先寻找id是china的元素
china = wd.find_element(By.ID, 'china')

# 再选择该元素内部的p元素
elements = china.find_elements(By.XPATH, '//p')

# 打印结果
for element in elements:
    print('----------------')
    print(element.get_attribute('outerHTML'))

运行发现,打印的 不仅仅是 china内部的p元素, 而是所有的p元素。

要在某个元素内部使用xpath选择元素, 需要 在xpath表达式最前面加个点 。

像这样

elements = china.find_elements(By.XPATH, './/p')
  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值