Selenium 是一个 Web 应用的自动化框架。

通过它,我们可以写出自动化程序,像人一样在浏览器里操作web界面。 比如点击界面按钮,在文本框中输入文字 等操作。

而且还能从web界面获取信息。 比如获取12306票务信息,招聘网站职位信息,财经网站股票价格信息 等等,然后用程序进行分析处理。

我们写的自动化程序 需要使用 客户端库

我们程序的自动化请求都是通过这个库里面的编程接口发送给浏览器。

比如,我们要模拟用户点击界面按钮, 自动化程序里面就应该 调用客户端库相应的函数, 就会发送 点击元素 的请求给 下方的 浏览器驱动。 然后,浏览器驱动再转发这个请求给浏览器。

这个自动化程序发送给浏览器驱动的请求 是HTTP请求。

客户端库从哪里来的? 是Selenium组织提供的。

Selenium组织提供了多种 编程语言的Selenium客户端库, 包括 java,python,js, ruby等,方便不同编程语言的开发者使用。

我们只需要安装好客户端库,调用这些库,就可以发出自动化请求给浏览器咯。


浏览器驱动 也是一个独立的程序,是由浏览器厂商提供的, 不同的浏览器需要不同的浏览器驱动。 比如 Chrome浏览器和 火狐浏览器有 各自不同的驱动程序。

浏览器驱动接收到我们的自动化程序发送的界面操作请求后,会转发请求给浏览器, 让浏览器去执行对应的自动化操作。

浏览器执行完操作后,会将自动化的结果返回给浏览器驱动, 浏览器驱动再通过HTTP响应的消息返回给我们的自动化程序的客户端库。

自动化程序的客户端库 接收到响应后,将结果转化为 数据对象 返回给 我们的代码。

我们的程序就可以知道这次自动化操作的结果如何了。


我们再总结一下,selenium 自动化流程如下:

  1. 自动化程序调用Selenium 客户端库函数(比如点击按钮元素)

  2. 客户端库会发送Selenium 命令 给浏览器的驱动程序

  3. 浏览器驱动程序接收到命令后 ,驱动浏览器去执行命令

  4. 浏览器执行命令

  5. 浏览器驱动程序获取命令执行的结果,返回给我们自动化程序

  6. 自动化程序对返回结果进行处理

一:安装

Selenium环境的安装主要就是安装两样东西: 客户端库浏览器 驱动

安装客户端库

不同的编程语言选择不同的Selenium客户端库。

对应我们Python语言来说,Selenium客户端库的安装非常简单,用 pip 命令即可。

打开 命令行程序,运行如下命令

pip install selenium

安装浏览器驱动

浏览器驱动 是和 浏览器对应的。 不同的浏览器 需要选择不同的浏览器驱动。

目前主流的浏览器中,谷歌 Chrome 浏览器对 Selenium自动化的支持更加成熟一些。强烈推荐大家使用 Chrome浏览器。

可以点击这里,下载安装谷歌浏览器

确保Chrome浏览器安装好以后,请大家打开下面的连接,访问Chrome 浏览器的驱动下载页面

Chrome 浏览器驱动下载地址

测试版chromedriver浏览器驱动下载地址

注意浏览器驱动 必须要和浏览器版本匹配,下图红圈里面的版本号 就是和浏览器版本号对应的

比如:当前Chrome浏览器版本是87, 通常就需要下载87开头的目录里面的驱动程序 。

注意:驱动和浏览器的版本号越接近越好,但是略有差别,比如87和86 ,通常也没有什么问题。

下面的代码, 可以自动化的 打开Chrome浏览器,并且自动化打开百度网站,可以大家可以运行一下看看。

from selenium import webdriver

# 创建 WebDriver 对象,指明使用chrome浏览器驱动
wd = webdriver.Chrome(r'd:\webdrivers\chromedriver.exe')

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

其中,下面这行代码,就会运行浏览器驱动,并且运行Chrome浏览器

wd = webdriver.Chrome(r'd:\webdrivers\chromedriver.exe')

注意,等号右边 返回的是 WebDriver 类型的对象,我们可以通过这个对象来操控浏览器,比如 打开网址、选择界面元素等。
而下面这行代码,就是使用 WebDriver 的 get 方法 打开网址 百度

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

执行上面这行代码时,自动化程序就发起了 打开百度网址的 请求消息 ,通过浏览器驱动, 给 Chrome浏览器。

Chome浏览器接收到该请求后,就会打开百度网址,通过浏览器驱动, 告诉自动化程序 打开成功。

执行完自动化代码,如果想关闭浏览器窗口可以调用WebDriver对象的 quit 方法,像这样 wd.quit()

二:浏览器驱动目录加入环境变量Path

前面,我们的代码创建 WebDriver对象时,需要指定浏览器驱动路径,比如

wd = webdriver.Chrome(r'd:\webdrivers\chromedriver.exe')

这样写有几个问题:

一是,比较麻烦, 每次写自动化代码都 要指定路径。

二是,如果你的代码给别人运行,他的电脑上存放浏览器驱动的路径不一定和你一样(比如他的电脑是苹果Mac电脑),得改脚本。

三是,Selenium 升级到版本 4 以后, 即将废弃上面这种 指定驱动路径 的写法,运行会有如下告警

DeprecationWarning: executable_path has been deprecated, please pass in a Service object

指定驱动路径,需要改成这样

from selenium.webdriver.chrome.service import Service
wd = webdriver.Chrome(service=Service(r'd:\webdrivers\chromedriver.exe'))

这样写起来就更麻烦了。

有什么好办法呢?

我们可以把浏览器驱动 所在目录 加入环境变量 Path , 写代码时,就可以无需指定浏览器驱动路径了,像下面这样

wd = webdriver.Chrome()

因为,Selenium会自动在环境变量 Path 指定的那些目录里查找名为chromedriver.exe 的文件。

一定要注意的是, 加入环境变量 Path 的,

不是浏览器驱动全路径,比如 d:\webdrivers\chromedriver.exe

而是 浏览器驱动所在目录,比如 d:\webdrivers

那么,selenium又是如何 自动化地 在网页上 点击、输入、获取信息,将在接下来的章节要学习。

三:关闭 chromedriver 打印信息

缺省情况下 chromedriver被启动后,会在屏幕上输出不少日志信息,如下

DevTools listening on ws://127.0.0.1:19727/devtools/browser/c19306ca-e512-4f5f-b9c7-f13aec506ab7
[21564:14044:0228/160456.334:ERROR:device_event_log_impl.cc(211)] [16:04:56.333] Bluetooth: bluetooth_adapter_winrt.cc:1072 Getting Default Adapter failed.

可以这样关闭

from selenium import webdriver

# 加上参数,禁止 chromedriver 日志写屏
options = webdriver.ChromeOptions()
options.add_experimental_option(
    'excludeSwitches', ['enable-logging'])

wd = webdriver.Chrome(
    r'd:\webdrivers\chromedriver.exe', 
    options=options  # 这里指定 options 参数
)

四:扩展知识

浏览器和驱动之间的接口是各浏览器厂商私有的,通常我们无需关心。

喜欢刨根问底的朋友,可以参考 这个链接,了解Chrome浏览器和Chrome之间的接口

五: selenium 环境管理

通常使用selenium时候我们需要自己单独去下载对应各浏览器版本的webdriver,并在后期针对不同操作系统(mac、windows、linux)或者不同浏览器版本都要反复选择对应版本webdriver

为了解决以上问题,webdriver-manage第三方库营运而生,它可以自动帮你识别当前运行环境下系统信息以及对应浏览器信息,并自动下载对应的webdriver,再也不用担心webdriver版本问题!!!

下载第三方库

https://pypi.org/project/webdriver-manager/

pip install webdriver-manager

Chrome用法

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())

Firefox用法

from selenium import webdriver
from webdriver_manager.firefox import GeckoDriverManager

driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())

IE用法

from selenium import webdriver
from webdriver_manager.microsoft import IEDriverManager

driver = webdriver.Ie(IEDriverManager().install())

Edge用法

from selenium import webdriver
from webdriver_manager.microsoft import EdgeChromiumDriverManager

driver = webdriver.Edge(EdgeChromiumDriverManager().install())

Opera用法

from selenium import webdriver
from webdriver_manager.opera import OperaDriverManager

driver = webdriver.Opera(executable_path=OperaDriverManager().install())

案例

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/8/29 12:29
# @Author  : shisuiyi
# @File    : 01_openbrowser.py

from selenium import webdriver #引入webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time #time模块


browser = webdriver.Chrome(ChromeDriverManager().install())
url="http://www.baidu.com"
print('url is '+url)

browser.get(url) #发送url请求
time.sleep(1) #等待时间
print(browser.title)#打印title
print('actual url is '+browser.current_url)#打印当前url

keyword=browser.find_element('id',"kw")#识别搜索框
keyword.send_keys("selenium")#输入搜索内容
#也可以这么写:browser.find_element_by_id("kw").send_keys("selenium")

botton=browser.find_element('id',"su")#识别按钮
botton.click()#点击按钮
#也可以这么写:browser.find_element_by_id("su").click()

time.sleep(4)
browser.quit() #关闭所有与当前driver相关的窗口
#browser.close() #关闭当前窗口


六:selenium如何绕开登录

  1. windows,打开浏览器通过指令:chrome://version/查找缓存地址

  2. mac系统缓存地址:/Users/xxx/Library/Caches/Google/Chrome/Default/Cache xxx为用户名

  3. 通过传入本地缓存来实现缓存获取,参数:–user-data-dir

  4. 调用本地缓存时需要关闭所有正在应用的浏览器窗体

  5. 因为需要加载本地缓存,启动浏览器之后运行脚本的第一条指令会非常缓慢,如果要提速,手动输入一个请求url即可

  6. 一般不推荐使用,需要绕过验证码操作的时候可以添加需要找到chrome的User Data文件夹,替换下面代码中的路径

profile_directory = r'--user-data-dir=C:\Users\DXG\AppData\Local\Google\Chrome\User Data'
options = webdriver.ChromeOptions()
options.add_argument(profile_directory)
driver_path = r'D:/chromedriver/chromedriver.exe'
driver = webdriver.Chrome(executable_path=driver_path,options=options)

注意:在操作前必须先将chrome关闭

或者利用cookies跳过登陆

# 不输入用户名和密码,获取cookie实现登录
# 登录成功后,cookies里面会保存sessionid
# 将该sessionid添加到driver里面
# 注意: 1.selenium启动某个浏览器时,它启动的是一个全新的浏览器
#          没有带任何cookie,需要程序加载这些cookie
#        2.必须首先加载网站,这样Selenium 才能知道cookie 属于哪个网站,即使加载网站的行为对我们没任何用处
#        3.退出或者注销登录,sessionid失效,下次访问生成新的sessionid

# 方法一 手动获取sessionid
import time
from selenium import webdriver

driver = webdriver.Chrome()
driver.get('http://127.0.0.1:8000')  # 先加载网站
driver.maximize_window()
driver.add_cookie({'name': 'sessionid', 'value': '5u8jziskb2065vssla8ea5s7yvh2ucag'})
driver.get('http://127.0.0.1:8000')
driver.refresh()
time.sleep(5)
driver.quit()


# 方法二 代码自动获取cookie

driver1 = webdriver.Chrome()
driver1.maximize_window()
driver1.get('http://127.0.0.1:8000/api-auth/login/?next=/')
driver1.find_element_by_id('id_username').send_keys('admin')
driver1.find_element_by_id('id_password').send_keys('123')
driver1.find_element_by_id('submit-id-submit').click()
time.sleep(2)
save_cookie = driver1.get_cookies()  # 列表里面有两个字典cookie信息,一个是登录之前的,一个是登录之后的
print(save_cookie)
driver1.quit()
driver2 = webdriver.Chrome()
driver2.maximize_window()
# 必须首先加载网站,这样selenium才知道cookie是属于哪个网站的
driver2.get('http://127.0.0.1:8000/api-auth/login/?next=/')
print(driver2.get_cookies())
driver2.delete_all_cookies()  # 一旦加载网站,即使没登录,也会产生一个cookie,需要删除cookie
for cookie in save_cookie:
    driver2.add_cookie(cookie) # 添加driver1登录成功之后的cookie

driver2.get('http://127.0.0.1:8000')
print(driver2.get_cookies())
time.sleep(3)
driver2.quit()

七:Selenium处理https 安全问题或者非信任站点

image-1668586008792

谷歌浏览器

#_*_ coding:utf-8 _*_
 
from selenium import webdriver
 

if __name__ == '__main__':
 
    options=webdriver.ChromeOptions()
 
    options.add_argument('--ignore-certificate-errors')
 
    driver=webdriver.Chrome(chrome_options=options)
 
    driver.get(u'https://cacert.org/')
 
    driver.close()

火狐浏览器

#_*_ coding:utf-8 _*_
 
from selenium import webdriver
 
 
if __name__ == '__main__':   
    profile=webdriver.FirefoxProfile()
    profile.accept_untrusted_certs=True
    driver=webdriver.Firefox(firefox_profile=profile)
    driver.get(u'https://cacert.org/')
    driver.close()

八:selenium脚本解决随机弹窗广告问题(来源:我去热饭

问题概述:各种随机不可预测的弹窗广告的出现,这种广告出现后需要点击一下x 或按钮等才能关掉,如果不关掉,则后续脚本无法正常运行,直接导致所有用例失败

推荐解决思路:

设置子线程进行巡逻,主线程该跑脚本跑脚本。子线程负责进行环境维护,出现弹窗就关掉仅此而已。当然子线程可以继续扩展,比如发现弹窗后截图,简单判断一下记录一下再关掉。除此之外,子线程还可以帮主线程的脚本运行提供其他各种辅助作用

但是子线程进行巡逻,自然不能跟主线程共用一个driver对象,否则这个driver就变成了既要同时执行用例脚本,又要无时无刻的去盯着随机弹窗广告,那会极大拖慢执行速度。所以子线程就可以选择再启动一个driver对象的方式。那此刻问题又来了:新的driver能控制主线程driver的浏览器么?正常情况下是不能控制的。除非按照下面思路进行设置:

  1. 用命令启动浏览器,启动的时候要带上端口,只有命令启动,才可以添加端口参数。

  2. 脚本开头创建启动项options,然后添加debugaddress,并设置为127.0.0.1:之前的端口,这样会让driver不新建浏览器,而是直接接着你命令启动的浏览器进行操作。

  3. 用thread库创建一个线程,内容就是新建一个driver实例作为子线程,用来辅助,也就是里面用一个when True来在整脚本生命周期内 无时无刻的去检查弹窗广告,一旦检查到,才去瞬间关闭,亲测好用。

  4. 你的主线该怎么运行就怎么运行,完全不用担心弹窗的事了,当然双线程,并且有个辅助线程一直在不断的监控,这样确实会更耗费系统资源。所以建议封装成对应的类,并且增加可控的创建和结束功能,在适当的情况下比如广告容易出现的用例执行时开启即可。结束的条件也可以多样化,比如点击几次广告后,该辅助线程就自动关闭。

子线程控制同浏览器demo代码

from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_experimental_option("debuggerAddress", "127.0.0.1:6789")  #手动命令启动浏览器需要设置端口未6789 :  --remote-debugging-port=6789
import threading

def a():
    driver = webdriver.Chrome(options=options)
    while True:
        try:
            driver.find_element(By.ID,'弹窗关闭的id').click()
            driver.switch_to.alert.accept()
        except:
            pass
        time.sleep(1) # 扫描监控时间
        # 退出驱动条件自行设计
        driver.quit()

t1 = threading.Thread(target=a)
t1.setDaemon(True) #守护线程,这样主脚本结束后 该线程也会结束。
t1.start()

 # 此处你可以正常写你的主线程的 脚本了
driver = webdriver.Chrome(options=options)
driver.get('')
...