目录

一、选择元素的基本方法

  • I 通过WebDriver对象选择元素
  • 1.根据元素的id属性选择元素
  • 2.根据元素的class属性选择元素
  • 3.根据tag(标签)名选择元素
  • II 通过WebElement对象选择元素
  • 二、操控元素的基本方法
  • I 点击元素
  • II 输出框
  • III 获取元素信息
  • 1.获取文本信息
  • 2.获取元素属性
  • 3.获取整个元素对应的HTML
  • 4.获取输出框里面的文字
  • 三、frame切换/窗口切换
  • I frame
  • II 窗口
  • 四、选择框的处理
  • I radio框
  • II checkbox框
  • III select框
  • 1.基本方法
  • 2.select单选框
  • 3.select多选框
  • 五、css表达式
  • I 原理
  • II 根据tag名,id,class,其他属性选择元素
  • III 选择子元素和后代元素
  • IV 按次序选择
  • V 组选择,兄弟节点
  • 1.组选择
  • 2.兄弟节点
  • 六、Xpath选择器
  • I 基本知识
  • II 根据属性选择
  • III 按次序选择
  • IV 组选择,兄弟节点,父节点
  • 1.组选择
  • 2.兄弟节点
  • 3.父节点
  • 七、总结

一、选择元素的基本方法

I 通过WebDriver对象选择元素

1.根据元素的id属性选择元素

  • input元素内容中,有属性id,id属性是用来html中标记该元素的,而且id是html中唯一的。如果元素有id,根据id选择元素是最高效的。 上图是百度搜索框,元素id的值为kw,下面代码,可以通过自动化在浏览器访问百度,并搜索子明
from selenium import webdriver 

# 创建 WebDriver 对象
driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

# 调用WebDriver对象的get方法可以让浏览器打开指定网址
driver.get('https://www.baidu.com')

# 根据id选择元素,返回的就是该元素对应的WebElement对象
element = driver.find_element_by_id('kw')
"""
上面代码发起一个请求通过浏览器驱动转发给浏览器,告诉它,需要选择一个id为 kw 的元素。浏览器找到id为kw的元素后,
将结果通过浏览器驱动返回给自动化程序,所以find_element_by_id 方法会返回一个WebElement 类型的对象。我们就是
通过这个WebElement对象,操控对应的界面元素。
"""

# 比如输入字符串到 这个 输入框里
element.send_keys('子明\n')  # 如果没有\n的话,就要使用如下语句
#element = driver.find_element_by_id("su").click()

【注】 如果你想在请求的时候用options参数来配置20年发行用chrome内核为主的Edge,比如添加代理,设置编码,直接option = webdriver.EdgeOptions(),然后使用option.add_argument()方法是行不通的,本人也遇到这种问题,后来看到大佬博客解其惑,博客链接奉上:

2.根据元素的class属性选择元素

  • input元素内容中,也有class属性,class 属性就用来标志着元素类型 还是百度搜索框,元素class的值为’s_ipt’,下面代码,可以通过自动化在浏览器访问百度,并搜索子明
from selenium import webdriver

# 创建 WebDriver 对象
driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

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

# 根据class选择元素
element = driver.find_element_by_class_name('s_ipt')

element.send_keys('子明\n')

3.根据tag(标签)名选择元素

  • 对于那些只有标签的元素挺好用的,后面京东图书那个例子能体现出来 为了演示,还是选择百度的搜索框
from selenium import webdriver
# 创建 WebDriver 对象
driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

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

# 根据tag名选择元素
"""
这里要注意,input标签这么多,此时如果用driver.find_element_by_tag_name(),那么只能返回整个html页面的第一个input标签元素,
而driver.find_elements_by_tag_name()才能以列表的形式返回所有的元素。这2个方法还有个区别就是,
前者没找到元素会抛出NoSuchElementException 异常,而后者只会返回空列表
"""
element = driver.find_elements_by_tag_name('input')
element[7].send_keys('子明\n')

【注】:肯定会有人会问element[7]怎么来的,首先在浏览器页面检查元素,通过ctrl+F 搜索input标签(这个搜索框不仅可以搜索元素,还可以写css表达式,Xpath表达式),然后发现百度搜索框的input是第8个元素,那么在返回的列表中的索引是7,所以就有了element[7]

python selenium 输出_sed

在这个搜索框也可以验证是否有某个元素,CSS Selector 的语法是否正确,xpath表达式是否正确等,大大减少了bug

II 通过WebElement对象选择元素

  • WebDriver 对象选择元素的范围是 整个 web页面,而WebElement对象选择元素的范围是该元素的内部,这是两者的区别,比如获取京东图书所有分类:
from selenium import webdriver

# 创建 WebDriver 对象
driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

driver.get('https://book.jd.com/booksort.html')

# 限制选择元素的范围是 tag 为 em 元素的内部
element = driver.find_elements_by_tag_name('em')
for i in element:
  print(i.text)

二、操控元素的基本方法

I 点击元素

  • click()方法,前面也提过,补充一点:调用 WebElement对象的 click 方法去点击元素的时候, 浏览器接收到自动化命令,点击的是该元素的中心点位置

II 输出框

  • send_keys() ,如果输入框已有内容,可以调用clear方法清除
element = wd.find_element_by_id("input")

element.clear() # 清除输入框已有的字符串
element.send_keys('子明') # 输入新字符串

III 获取元素信息

1.获取文本信息

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

【注】如果元素没有展示在页面上,或者没有完全展示在界面上,这个使用text属性获取文本内容肯定会有问题,出现这种情况,可以尝试 element.get_attribute(‘innerText’) ,或者 element.get_attribute(‘textContent’)

2.获取元素属性

  • get_attribute() 方法 来获取元素的属性值
# 以百度搜索框为例
element = driver.find_element_by_id('kw')
print(element.get_attribute('class'))

3.获取整个元素对应的HTML

  • 要获取整个元素对应的HTML文本内容,可以使用 element.get_attribute(‘outerHTML’),如果只是想获取某个元素 内部 的HTML文本内容,可以使用 element.get_attribute(‘innerHTML’)

4.获取输出框里面的文字

  • 对于input输入框的元素,要获取里面的输入文本,用text属性是不行的,可以使用 element.get_attribute(‘value’)

三、frame切换/窗口切换

I frame

python selenium 输出_selenium_02

  • 这是QQ邮箱的html页面,在html语法中,frame元素或者iframe元素的内部会包含一个被嵌入的另一份html文档。我们是不能直接操作被嵌套在里面的元素的,要先切换到嵌套的html里面,使用 WebDriver 对象的 switch_to 属性
# driver.switch_to.frame(iframe_reference)
# frame_reference可以是frame元素的属性name或者ID 

driver.switch_to.frame(mainFrame)
  • 进去了,怎么切回来呢?
driver.switch_to.default_content()

II 窗口

  • 在网页上操作的时候,我们经常遇到,点击一个链接或者按钮,就会打开一个新窗口 ,但是我们的 WebDriver对象对应的还是老窗口,自动化操作也还是在老窗口进行,这个时候需要切换窗口
# 使用Webdriver对象的switch_to属性的 window方法
driver.switch_to.window(handle)
# 但是WebDriver对象有window_handles 属性,这是一个列表对象,里面包括了当前浏览器里面所有的窗口句柄。
# 这个时候需要用点小技巧去解决,用微软bing搜索当例子
for handle in driver.window_handles:
    # 先切换到该窗口
    wd.switch_to.window(handle)
    # 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
    if 'Bing' in driver.title:
        # 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
        break

四、选择框的处理

I radio框

python selenium 输出_selenium_03

  • radio框选择选项,直接用WebElement的click方法,模拟用户点击就可以了。
# 默认是第三个和第五个,现在选择第一个和第五个
from selenium import webdriver
import time

driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

driver.get('https://www.html5tricks.com/demo/css3-styled-checkbox-radiobox/index.html')

# 这个地方用到了后面的知识,有人就会问,为啥要用css表达式呢,不用普通方法,客官不急,咱往后看再回来看
element = driver.find_element_by_css_selector('[for=rad]')

# 这个地方选择睡眠2秒,因为在我们进行网页操作的时候,有的元素内容不是可以立即出现的,可能会等待一段时间
"""
比如 百度搜索一个词语,我们点击搜索后,浏览器需要把这个搜索请求发送给百度服务器,百度服务器进行处理后,把搜索结果返回给我们。
所以从点击搜索到得到结果,需要一定的时间,只是通常百度服务器的处理比较快,我们感觉好像是立即出现了搜索结果。因为我们的代码执行的速度比百度
服务器响应的速度快,可能就会报selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element:
 {"method":"id","selector":"1"}的错误,而等待记载时间只是导致这个错误之一,下面会给一些方法去解决这个问题,1.检查程序是否写错 
 2.是否需要切换iframe 3.是否需要加等待时间 4.是否需要用js的方法来scroll滚动条 5.涉及到check的话check是否可以点击的。
"""
time.sleep(2)
element.click()

【注】那到底设置多长时间合理呢?太短1s,可能解决不了问题,太长20s,浪费大量时间。Selenium提供了一个合理的解决方案:当发现元素没有找到的时候, 并不立即返回 找不到元素的错误。而是周期性(每隔半秒钟)重新寻找该元素,直到该元素找到,或者超出指定最大等待时长,这时才 抛出异常(如果是 find_elements 之类的方法, 则是返回空列表)。

# Selenium 的 Webdriver对象有个方法叫 implicitly_wait,该方法接受一个参数,用来指定最大等待时长时间
driver.implicitly_wait(5)  # 每隔半秒寻找一次元素,最多等待5秒

但是是不是time.sleep()就没作用了呢?在一些场景还是得用到,比如:你想详细的看到元素被操作的过程

II checkbox框

python selenium 输出_css_04

  • 对checkbox进行选择,也是直接用 WebElement 的 click 方法,模拟用户点击选择。需要注意的是,要选中checkbox的一个选项,必须先获取当前该复选框的状态 ,如果该选项已经勾选了,就不能再点击。否则反而会取消选择。
from selenium import webdriver
import time

driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

driver.get('https://www.html5tricks.com/demo/css3-styled-checkbox-radiobox/index.html')

# 第一个勾选
element = driver.find_element_by_css_selector('[for=chk]')

time.sleep(1)
element.click()

# 第二个不勾选
element = driver.find_element_by_css_selector('[for=chk2]')

time.sleep(1)
element.click()

III select框

1.基本方法

python selenium 输出_css_05

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

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

driver = webdriver.Edge(executable_path='msedgedriver.exe绝对路径')

driver.get('https://www.jq22.com/yanshi20815')

driver.switch_to_frame("iframe")

# 创建Select对象
s = Select(driver.find_element_by_id("id_select"))

# 基本方法
# 1.根据选项的value属性值选择元素,例:<option value="湖南">湖南</option>
s.select_by_value('湖南')

# 2.根据选项的次序(从0开始选择元素), 例: 江苏是第二个,选中江苏
s.select_by_index(1)

# 3.根据选项的可见文本选择元素, 例:<option value="湖南">湖南</option>
s.select_by_visible_text('湖南')  # 第二个湖南

# 4.根据选项的value属性值去除选中元素
s.deselect_by_value("湖南")

# 5.根据选项的次序去除选中元素
s.deselect_by_index(1)

# 6.根据选项的可见文本去除选中元素
s.deselect_by_visible_text("湖南")

# 7.去选中所有元素(没有参数)
s.deselect_all()

2.select单选框

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

driver = webdriver.Edge(executable_path='msedgedriver.exe绝对路径')

driver.get('https://www.jq22.com/yanshi20815')

driver.switch_to_frame("iframe")

# 创建Select对象
s = Select(driver.find_element_by_id("id_select"))

# 通过select对象选中湖南
s.select_by_value("湖南")

3.select多选框

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

driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

driver.get('https://www.jq22.com/yanshi20815')

driver.switch_to_frame("iframe")

# 创建Select对象
s = Select(driver.find_element_by_id("id_select"))

# 清除已经选到的(唯一一个多选不同于单选的细节)
s.deselect_all()

# 通过select对象选中湖南,江苏,江西 
s.select_by_value("湖南")
s.select_by_value("江苏")
s.select_by_value("江西")

五、css表达式

I 原理

  • 1.在选择框那一部分就用到了css表达式,那是因为如果我们要选择的元素没有id、class 属性,或者有些我们不想选择的元素也有相同的 id、class属性值,这个时候就用到了CSS selector 语法选择元素。
  • 2.通过 CSS Selector 选择单个元素的方法

find_element_by_css_selector(CSS Selector参数)

  • 3.选择所有元素的方法

find_elements_by_css_selector(CSS Selector参数)

II 根据tag名,id,class,其他属性选择元素

# 百度搜索框为例
from selenium import webdriver

driver = webdriver.Edge(executable_path='msedgedriver.exe绝对路径')

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

# 1.根据id属性 选择元素的语法是在id号前面加上一个井号: #id值
element = driver.find_element_by_css_selector("#kw")
element.send_keys('子明\n')

# 2.根据class属性选择元素的语法是在 class 值前面加上一个点: .class值
element = driver.find_element_by_css_selector(".s_ipt")
element.send_keys('子明\n')

# 3.根据tag名选择元素的CSS Selector语法非常简单,直接写上tag名
element = driver.find_elements_by_css_selector("input")
element[7].send_keys('子明\n')

# 4.根据其他属性来选择元素,语法是用一个方括号 [] 
element = driver.find_element_by_css_selector("[name='wd']")  # 根据name属性
element.send_keys('子明\n')

III 选择子元素和后代元素

python selenium 输出_sed_06

  • 1.from后面的第一个span是其子元素,后面的span都是其后代元素(相邻才是直接子元素,隔代便是后代子元素,比如后面的一排input,而后代元素包括后代子元素)
  • 2.选择子元素的语法(可以多层选择)

元素1 > 元素2 > 子元素3

  • 3.选择后代元素的语法,一个或多个空格隔开

元素1 元素2

IV 按次序选择

from selenium import webdriver
import time

driver = webdriver.Edge(executable_path='msedgedriver.exe绝对路径')

driver.get('https://www.baidu.com/')
driver.implicitly_wait(3)
# 1.父元素的第几个子节点,nth-child (还是以百度搜索框为例)
# input:nth-child(2)会有2个结果,很奇怪的是,如果你用find_element×××竟然返回的是后面一个,具体情况俺也不太清楚
# input是节点类型限制,tag名为input的第二个子节点,也是是其他元素来限制,比如id啥的,但是这样的话,为啥不直接就按id来选择元素呢?
# 为了突出这个知识点,所以采用了tag名,有多个input标签,但是用父元素的第2个子节点,还是有2个元素
elements = driver.find_elements_by_css_selector("input:nth-child(2)") 

for element in elements:
    if element.get_attribute("type") == "text":
        element.send_keys("子明\n")

# 2.选择的是父元素的倒数第几个子节点 ,nth-last-child
element = driver.find_element_by_css_selector("input:nth-last-child(3)")
element.send_keys("子明\n")

# 3.父元素的第几个某类型的子节点, nth-of-type
elements = driver.find_elements_by_css_selector("input:nth-of-type(1)")  # 第一个input类型的子元素

for element in elements:
    if element.get_attribute("type") == "text":
        element.send_keys("子明\n")

# 4.父元素的倒数第几个某类型的子节点, nth-last-of-type
elements = driver.find_elements_by_css_selector(" input:nth-last-of-type(1)")  # 百度框那个span下面就一个input,正倒数一样

for element in elements:
    if element.get_attribute("type") == "text":
        element.send_keys("子明\n")

# 5.选择的是父元素的偶数节点:nth-child(even). 选择的是父元素的奇数节点:nth-child(odd)[选不到百度框,就不举例了]
# 选择的是父元素的某类型偶数节点: nth-of-type(even). 选择的是父元素的某类型奇数节点: nth-of-type(odd) [用法是同上一样的]
elements = driver.find_elements_by_css_selector("input:nth-child(even)")

for element in elements:
    if element.get_attribute("type") == "text":
        element.send_keys("子明\n")

V 组选择,兄弟节点

1.组选择

  • 如果同时需要 tag 名为 input ,id 为 kw 的元素,此时需要逗号( , )隔开,称为组选择

input , #kw

2.兄弟节点

  • 那很多的input就是兄弟节点,而要选择紧跟的兄弟节点,语法为加号(+),比如:span + input (百度搜索框html的 span 和 input )
  • 要选择 span 后面所有的input兄弟节点 span ~ input

【注】更多css选择器语法,请参考: css选择器参考手册

六、Xpath选择器

  • xpath跟css一样,也是一种灵活、强大的选择元素的方式,既然已经有了CSS,为什么还要学习 Xpath呢?
  • 有些场景 用 css 选择web 元素很麻烦,而xpath却比较方便。
  • Xpath 还有其他领域会使用到,比如爬虫框架 Scrapy,手机App框架 Appium。(爬虫挺好用的,比正则效率高,也比正则好学一点)

I 基本知识

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

/html/body/div/div/div/div/div/form/span/input (百度搜索框)

  • 2.需要选择网页中某个元素,不管它在什么位置,任意位置需要前面加//,这就是相对路径

//form/span/input (还是有2个元素,后面咋可以加限定条件,比如input[@id=“kw”])

  • 3.通配符(*)选择某一节点的所有子节点,比如:span后面所有子节点 //span/*

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

python selenium 输出_sed_07

from selenium import webdriver

driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

driver.get('https://book.jd.com/booksort.html')
driver.implicitly_wait(3)

# 先选择到dd节点
elements = driver.find_elements_by_xpath('//dl/dd')

# 在选择em
for element in elements:
    em = element.find_element_by_xpath('.//a')  # 这个地方一定是./×××,不能直接是//,表示当前路径下的a标签,就是dd后面的a标签
    print(em.text)

II 根据属性选择

# xpath没有css那么麻烦,所有属性选择都是[@属性名='属性值'](以下例子都是以百度框为例)
# 1.根据id
element = driver.find_element_by_xpath('//input[@id="kw"]')
element.send_keys("子明\n")

# 2.根据class
element = driver.find_element_by_xpath('//input[@class="s_ipt"]')
element.send_keys("子明\n")

# 3.根据其他属性
element = driver.find_element_by_xpath('//input[@name="wd"]')
element.send_keys("子明\n")

# 4.属性值包含字符串 (第一种比较常用,后面的了解就行)
	# 4.1 某属性值包含某字符串
	 //input[contains(@type,'text')]  # input节点下有包含字符串text的type属性
	# 4.2 某属性以 ×××字符串开头
	 //input[starts-with(@type,'t')] # input节点下以字符串t开头的type属性
	# 4.3 某属性以 ×××字符串结尾
	//input[ends-with(@type,'xt')] # xpath2.0的语法,现在浏览器不支持

III 按次序选择

from selenium import webdriver
import time

driver = webdriver.Edge(executable_path='msedgedriver.exe的绝对路径')

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

# 1.某节点的第几个元素
element = driver.find_element_by_xpath('//span/input[1]')
element.send_keys("子明\n")

# 2.某类型倒数第几个子元素
element = driver.find_element_by_xpath('//span/input[last()]')  #如果是倒数第二个[last()-1] last()本身就是倒数第一个,减1就倒数第二个
element.send_keys("子明\n")

# 范围选择
element = driver.find_element_by_xpath('//input[@id="kw"][position()<=1]')  # 直接//input[position()<=1]有多个元素,懒的去写一个判断
element.send_keys("子明\n")

IV 组选择,兄弟节点,父节点

1.组选择

  • css中用的是逗号隔开,xpath中用的是竖线( | ) 隔开
•   
//input | //a (所有的input和a节点)
2.兄弟节点
• xpath可以选择前面的兄弟节点,preceding-sibling:: 
  
//a[@class=‘quickdelete’]/ preceding-sibling::input(一个class属性为quickdelete的a节点前面的input兄弟节点)
• css中用的是波浪线(~),xpath中后续的兄弟节点用到的是 following-sibling:: 
  
//span[@class=‘soutu-btn’]/ following-sibling::input (一个class属性为soutu-btn的span节点后面的input兄弟节点)
3.父节点
• css不能选择到父节点,而xpath却可以,某个元素的父节点用 /.. 表示 
  
//input/.. (input的父节点)

七、总结

  • 思维导图