python模块详解 | selenium

关于Selenium

selenium_logo_large

Selenium是⼀个⽤于测试⽹站的⾃动化测试⼯具,⽀持各种浏览器包括Chrome、Firefox、Safari等主流界⾯浏览器,同时也⽀持phantomJS⽆界⾯浏览器。另外,selenium用来爬虫也是杠杠的,可以应对大多数的反爬。

配置selenium环境

  • 安装Selenium - pip install selenium

  • 配置chromedriver

    Selenium3.x调⽤浏览器必须有⼀个webdriver驱动⽂件

    驱动下载 👉 selenium各浏览器驱动下载地址

    1. Windows - 将下载的exe驱动文件,移动到python安装目录下的Scripts文件夹下
    2. MacOS - 打开「访达」按下快捷键shift+command+G(或前往文件夹),输入open /usr/local/bin回车。在新打开的文件夹中,把浏览器驱动复制进去即可

更多配置方法 👉 参考浏览器驱动环境配置

⼊门参考⽂献 👉 Selenium⼊门

IE环境配置 👉 http://t.zoukankan.com/ppppying-p-6143658.html

配置浏览器参数

options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options=options)
  • https://zhuanlan.zhihu.com/p/60852696

  • 静默模式 - options.add_argument('--headless')

  • 忽略提示语 - options.add_argument('disable-infobars')

  • 谷歌文档提到需要加上这个属性来规避bug - options.add_argument('--disable-gpu')

  • 隐藏滚动条 - options.add_argument('--disable-gpu')

  • 解决DevToolsActivePort文件不存在的报错 - options.add_argument('--no-sandbox')

  • 指定浏览器分辨率 - options.add_argument('window-size=1600x900')

  • 开启管理者模式

    options.add_experimental_option('excludeSwitches', ['enable-automation']) 
    
  • 不加载图片

    options.add_argument('blink-settings=imagesEnabled=false')
    
  • 禁止图片和css加载

    prefs = {"profile.managed_default_content_settings.images": 2, 'permissions.default.stylesheet': 2}
    options.add_experimental_option("prefs", prefs)
    
  • 指定下载文件目录

    save_path = "C:\"
    prefs = {"download.default_directory": save_path}
    option.add_experimental_option("prefs", prefs)
    
  • 允许多文件下载弹窗

    prefs = {"download.prompt_for_download": False}
    option.add_experimental_option("prefs", prefs)
    
  • 禁止弹出“您的连接不是私密连接”

    options.add_argument('ignore-certificate-errors')
    
  • 设置代理

    from selenium import webdriver
    proxy = "https://127.0.0.1:8080"
    options = webdriver.ChromeOptions()
    options.add_argument(f"--proxy-server={proxy}")
    
    driver = webdriver.Chrome(options=options)
    driver.get("")
    
  • 使用用户配置文件

    options.add_argument('--user-data-dir=/Users/billie/Library/Application Support/Google/Chrome/default')
    

    image-20210621102119098

定位元素

8种常规定位方法:id,name,class_name,tag_name,link_text,partial_link_text,xpath,css_selector

参考官网 👉 selenium元素定位

定位⼀个元素 定位多个元素(返回一个列表) 含义
find_element_by_id find_elements_by_id id
find_element_by_name find_elements_by_name name
find_element_by_xpath find_elements_by_xpath xpath表达式
find_element_by_link_text find_elements_by_link_text 完整超链接文本
find_element_by_partial_link_text find_elements_by_partial_link_text 部分超链接文本
find_element_by_tag_name find_elements_by_tag_name 标签名
find_element_by_class_name find_elements_by_class_name 类名
find_element_by_css_selector find_elements_by_css_selector css选择器

ps:除了上面的公共方法,也有两个在页面对象定位器的私有方法: find_element、find_elements

  • xpath定位的N种写法

    1. driver.find_element_by_xpath("//*[@id=‘kw’]")
    2. driver.find_element_by_xpath("//*[@name=‘wd’]")
    3. driver.find_element_by_xpath("//input[@class=’s_ipt’]")
    4. driver.find_element_by_xpath("/html/body/form/span/input")
    5. driver.find_element_by_xpath("//span[@class=‘soutu-btn’]/input")
    6. driver.find_element_by_xpath("//form[@id=‘form’]/span/input")
    7. driver.find_element_by_xpath("//input[@id=‘kw’ and @name=‘wd’]")
  • css定位的N种写法

    1. driver.find_element_by_css_selector("#kw")
    2. driver.find_element_by_css_selector("[name=wd]")
    3. driver.find_element_by_css_selector(".s_ipt")
    4. driver.find_element_by_css_selector(“html > body > form > span > input”)
    5. driver.find_element_by_css_selector(“span.soutu-btn> input#kw”)
    6. driver.find_element_by_css_selector(“form#form > span > input”)
  • link_text定位的写法(实例)

    假如⻚⾯上有⼀组⽂本链接(link_text)

      <a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
      <a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
    

    通过link_text定位:

    1. driver.find_element_by_link_text(“新闻”)
    2. driver.find_element_by_link_text(“hao123”)

    通过partial_link_text定位:

    1. driver.find_element_by_partial_link_text(“新”)
    2. driver.find_element_by_partial_link_text(“hao”)
    3. driver.find_element_by_partial_link_text(“123”)

元素操作

  • size # 获取元素的尺寸,返回一个字典:{‘x’: 000, ‘y’: 000}
  • text # 获取元素的文本
  • location # 获取元素坐标,先找到要获取的元素,再调用该方法,返回一个字典:{‘height’: 000, ‘width’: 000}
  • tag_name # 返回元素的tagName
  • clear() # 清除元素的内容
  • send_keys() # 模拟按键输入
  • click() # 点击元素
  • submit() # 提交表单
  • get_attribute(name) # 获取属性值
  • is_displayed() # 设置该元素是否可见
  • is_enabled() # 判断元素是否被使用
  • is_selected() # 判断元素是否被选中

ps:如果需要输入中文,防止编码错误使用send_keys(u"中文用户名")。

浏览器操作

  • title # 返回页面标题
  • page_source # 返回页面源码
  • current_url # 获取当前页面的URL
  • refresh() # 刷新浏览器
  • set_window_size() # 设置浏览器的大小
  • set_window_position() # 设置浏览器的坐标
  • set_window_rect() # 设置浏览器的矢量
  • maximize_window() # 最大化窗口
  • minimize_window() # 最小化窗口
  • close() # 关闭页面
  • quit() # 关闭窗口

鼠标事件

  • ActionChains(driver) # 构造ActionChains对象

  • click(on_element) # 左击

  • context_click(on_element) # 右键,另存为等行为

  • double_click(on_element) # 左键双击,地图web可实现放大功能

  • drag_and_drop(source,target) # 左键拖动,源元素按下左键移动至目标元素释放

  • drag_and_drop_by_offset(source, xoffset, yoffset) # 拖拽到某个坐标然后松开

  • key_down(value, element=None) # 按下某个键盘上的键

  • key_up(value, element=None) # 松开某个键

  • move_by_offset(xoffset, yoffset) # 鼠标从当前位置移动到某个坐标

  • move_to_element(on_element) # 鼠标悬停

  • move_to_element_with_offset(to_element, xoffset, yoffset) # 移动到距某个元素(左上角坐标)多少距离的位置

  • click_and_hold(on_element) #左键点击不松开

  • perform() # 在通过调用该函数执行ActionChains中存储行为

  • 例:

    from selenium import webdriver
    from selenium.webdriver.common.action_chains import ActionChains #引⼊ ActionChains 类
    driver = webdriver.Firefox()
    driver.get("https://www.baidu.com")
    element= driver.find_element_by_link_text("设置") #定位元素
    ActionChains(driver).move_to_element(element).perform() #对定位到的元素执⾏⿏标悬停操作
    

键盘事件

参考:http://selenium-python.readthedocs.org/api.html

提供键盘按键操作的类:webdriver.common.keys

from selenium.webdriver.common.keys import Keys
  • send_keys(Keys.ENTER) # 按下回车键
  • send_keys(Keys.TAB) # 按下Tab制表键
  • send_keys(Keys.SPACE) # 按下空格键space
  • send_keys(Kyes.ESCAPE) # 按下回退键Esc
  • send_keys(Keys.BACK_SPACE) # 按下删除键BackSpace
  • send_keys(Keys.SHIFT) # 按下shift键
  • send_keys(Keys.CONTROL) # 按下Ctrl键
  • send_keys(Keys.ARROW_DOWN) # 按下鼠标光标向下按键
  • send_keys(Keys.CONTROL,‘a’) # 组合键全选Ctrl+A
  • send_keys(Keys.CONTROL,‘c’) # 组合键复制Ctrl+C
  • send_keys(Keys.CONTROL,‘x’) # 组合键剪切Ctrl+X
  • send_keys(Keys.F1…Fn) # 键盘 F1…Fn
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()
driver.get('XXXX')
ele = driver.find_element_by.......
ele.send_keys(Keys.ENTER)

设置元素等待

  • 隐式等待

    driver.implicity_wait(10)

    为浏览器对象设定一个等待时间,得不到某个元素就等待一段时间

  • 显式等待

    ele = WebDriverWait(driver, timeout).until(method,message)

    明确地等到某个元素出现或某个元素的可点击等条件,等不到,就一直等,在规定的时间内没有找到,则抛出异常

    #显式等待
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    #显式等待的函数
    def explicit_wait(driver, way, path):
         try:
            ele = WebDriverWait(driver, 150).until(
              EC.presence_of_element_located((way, path)),
              message=''
            )
            return ele
         except Exception as e:
            print('元素寻找失败: ' + str(e))
            return False
    
    ele = explicit_wait(driver, By.XPATH, '//div[@class="pagination_index"]')#显式等待在DOM中找到目标元素
    

    until()方法de源码

    def until(self, method, message=''):
            """Calls the method provided with the driver as an argument until the \
            return value is not False."""
            screen = None
            stacktrace = None
    
            end_time = time.time() + self._timeout
            while True:
                try:
                    value = method(self._driver)
                    if value:
                        return value
                except self._ignored_exceptions as exc:
                    screen = getattr(exc, 'screen', None)
                    stacktrace = getattr(exc, 'stacktrace', None)
                time.sleep(self._poll)
                if time.time() > end_time:
                    break
            raise TimeoutException(message, screen, stacktrace)
    

EC

  • title_is - 判断当前页面的title是否完全等于(==)预期字符串,返回布尔值
  • title_contains - 判断当前页面的title是否包含预期字符串,返回布尔值
  • presence_of_element_located - 判断某个元素是否被加到了dom树里,并不代表该元素一定可见
  • visibility_of_element_located - 判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于0
  • visibility_of - 跟上面的方法做一样的事情,只是上面的方法要传入locator,这个方法直接传定位到的element就好了
  • presence_of_all_elements_located - 判断是否至少有1个元素存在于dom树中。举个例子,如果页面上有n个元素的class都是‘column-md-3‘,那么只要有1个元素存在,这个方法就返回True
  • text_to_be_present_in_element - 判断某个元素中的text是否 包含 了预期的字符串
  • text_to_be_present_in_element_value - 判断某个元素中的value属性是否 包含 了预期的字符串
  • frame_to_be_available_and_switch_to_it - 判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False
  • invisibility_of_element_located - 判断某个元素中是否不存在于dom树或不可见
  • element_to_be_clickable - 判断某个元素中是否可见并且是enable的,这样的话才叫clickable
  • staleness_of - 等某个元素从dom树中移除,注意,这个方法也是返回True或False
  • element_to_be_selected - 判断某个元素是否被选中了,一般用在下拉列表
  • element_selection_state_to_be - 判断某个元素的选中状态是否符合预期
  • element_located_selection_state_to_be - 跟上面的方法作用一样,只是上面的方法传入定位到的element,而这个方法传入locator
  • alert_is_present - 判断页面上是否存在alert

多表单切换

在Web应⽤中经常会遇到frame/iframe表单嵌套⻚⾯的应⽤,WebDriver只能在⼀个⻚⾯上对元素识别与定位,对于frame/iframe表单内嵌⻚⾯上的元素⽆法直接定位。这时就需要通过switch_to.frame()⽅法将当前定位的主体切换为frame/iframe表单的内嵌⻚⾯中。

  • switch_to.frame() / switch_to_frame()

将当前定位的主体切换为frame/iframe表单的内嵌⻚⾯,默认可以直接取表单的 idname属性。如果iframe没有可⽤的id和name属性,则可以通过查找iframe标签,进⾏定位。

  • switch_to.default_content() / switch_to_default_content()

跳回最外层的⻚⾯

  • # 先通过 xpath 定位到 iframe
    ele_iframe = driver.find_element_by_xpath('//*[@class="if"]')
    # 再将定位对象传给 switch_to_frame()方法
    driver.switch_to.frame(ele_iframe)
    driver.switch_to_default_content() 
    

多窗⼝切换

在⻚⾯操作过程中有时候点击某个链接会弹出新的窗⼝,这时就需要主机切换到新打开的窗⼝上进⾏操作。WebDriver提供了switch_to.window()⽅法,可以实现在不同的窗⼝之间切换。

  • current_window_handle #返回当前窗⼝的句柄

  • window_handles #返回所有窗⼝的句柄,一个列表

  • switch_to.window() #⽤于切换到相应的窗⼝,与上⼀节的switch_to.frame()类似,前者⽤于不同窗⼝的切换,后者⽤于不同表单之间的切换

  • 例:

    c_win = driver.current_window_handle
    driver.switch_to_window(c_win)
    

对话框操作

在WebDriver中处理JavaScript所⽣成的alert、confirm以及prompt⼗分简单,具体做法是使⽤ switch_to.alert switch_to_alert()⽅法定位到 alert/confirm/prompt,然后使⽤text/accept/dismiss/send_keys 等⽅法进⾏操作。

  • switch_to_alert() / switch_to.alert # 切入到警告框

  • text # 返回 alert/confirm/prompt 中的⽂字信息

  • accept() # 接受现有警告框

  • dismiss() # 解散现有警告框

  • send_keys(keysToSend) # 发送⽂本⾄警告框。keysToSend:发送⾄警告框的⽂本。

  • 例:

    al = driver.switch_to_alert()
    al.accept()
    al.text
    

复选框操作

  • is_selected() #返回布尔值,判断是否被选中

1、单选框(radio)

2、复选框(checkbox)

3、下拉框(select)

导⼊选择下拉框Select类,使⽤该类处理下拉框操作:

from selenium.webdriver.support.ui import Select

<select>类型的下拉框

  • 选择下拉框选项的⽅法
    • select_by_value(“选择值”) # 相当于我们使⽤⿏标选择下拉框的值
    • select_by_index(“索引值”) # 以传入的index值来查找匹配的元素并选择对应选项(索引从0开始计数)
    • select_by_visible_text(“文本”) # 选择所有文本显示的option元素,
  • 返回options信息的方法
    • options # 返回所有的选项的列表,其中选项都是WebElement元素
    • all_selecetd_options # 返回所有被选中的选项的列表,其中选项均为WebElement元素,输出所有被选中的选项,适合于能多选的下拉框
    • first_selected_option # 返回第一个被选中的选项
  • 取消下拉框选择的方法
    • deselect_by_index() #以传入的索引值来查找匹配的元素并取消选择
    • deselect_by_value() #以传入的value属性值来查找匹配的元素并取消选择
    • deselect_by_visible_text() #以传入的文本内容来查找匹配的元素并取消选择
    • deselect_all() #将所有的选项清除

ps:上述方法仅用于多选下拉框,即设置了multiple=“multiple”属性的「select标签」,这种下拉框可以多选。

from selenium.webdriver.support.ui import Select
ele = driver.find_element_by_...
all_options = Select(ele).options
Select(ele).select_by_value('选项A') # 按值xu,无返回值

文件上传

selenium没有提供直接的文件上传功能,目前主要有以下几种解决方案:

  • send_keys()
  • AutoIT
  • python pywin32 模块

1、send_keys()

对于通过input标签实现的上传功能,可以将其看作是⼀个输⼊框,定位到用于上传的input标签,接着通过send_keys()指定本地⽂件路径的⽅式,实现⽂件上传。 例:

from selenium import webdriver
import os
driver = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('upfile.html')
driver.get(file_path)
# 定位上传按钮,添加本地⽂件
driver.find_element_by_name("file").send_keys('D:\\upload_file.txt')
driver.quit()

2、AutoIT

AutoIT通过操作Windows窗口控件来实现自动化任务。selenium通过AutoIT来操作Windows窗口,实质是通过python代码来调用AutoIT生成的脚本.exe文件,即利用AutoIT编写适合的脚本,然后将脚本编译成可执行文件,在自动化测试实现时,直接调用此脚本实现文件上传。

ps:编写脚本和编译需要借助AutoIT提供的工具,但是脚本编译成可执行文件后,可直接使用,不需要安装AutiIT。

  • AutoIT下载:https://www.autoitscript.com/site/
  • AutoIT的使用:
  1. 探测控件(AutoIt Window Info工具)
  2. 编写脚本(Autoit Window Info编辑器)
  3. 验证脚本(Autoit Window Info 👉 Tool 👉 go)
  4. 编译成可执行文件(Compile Script to.exe)
  5. 调用可执行文件
  6. 参数化(在python程序中向可执行文件传入参数)
  7. 多个参数化(实现多文件上传)

3、pywin32

pywin32式用于访问Windows系统API的python模块,最核心的方法是:

  • win32api #用python对win32的本地API库进行封装
  • win32con #win32的常量定义
  • win32gui #

文件下载

文件下载(另存为),跟文件上传类似,可以使用AutoIt、win32api解决

1、win32api

  • 例:下载搜狗图片

    import win32api,win32con
    driver.get(sg_url)
    ActionChains(driver).move_to_element(driver.find_element_by_link_text('图片')).click().perform()#点击跳转到图片
    time.sleep(1)
    ActionChains(driver).move_to_element(driver.find_element_by_xpath('//*[@id="feed_list"]/div[1]/ul/li[1]/a/img')).context_click().perform()
    win32api.keybd_event(40,0,0,0)#40对应的是向下键,由于’另存为‘在菜单的顺序为7,所以需操作7次
    time.sleep(1)
    win32api.keybd_event(40,0,0,0)
    time.sleep(1)
    win32api.keybd_event(40,0,0,0)
    time.sleep(1)
    win32api.keybd_event(40,0,0,0)
    time.sleep(1)
    win32api.keybd_event(40,0,0,0)
    time.sleep(1)
    win32api.keybd_event(40,0,0,0)
    time.sleep(1)
    win32api.keybd_event(40,0,0,0)
    time.sleep(1)
    win32api.keybd_event(13,0,0,0)
    time.sleep(1)
    win32api.keybd_event(13,0,0,0)
    

cookie操作

有时候我们需要验证浏览器中cookie是否正确,因为基于真实cookie的测试是⽆法通过⽩盒和集成测试进⾏的。WebDriver提供了操作Cookie的相关⽅法,可以读取、添加和删除cookie信息。

WebDriver操作cookie的⽅法:

  • get_cookies() #获得所有cookie信息

  • get_cookie(name) #返回字典的key为“name”的cookie信息

  • add_cookie(cookie_dict) #添加cookie。

    “cookie_dict”指字典对象,必须有‘name’和‘value’两个key,可选的key是‘path’,‘domin’,‘secure’,‘expiry’,‘httponly‘

    -name:cookie的名称

    -value:cookie对应的值,动态生成

    -domain:服务器域名

    -expiry:cookie有效终止日期

    -path:path属性定义了web服务器上哪些路径下的页面可获取服务器设置的cookie-httpOnly:防脚本攻击

    -secure:在cookies中标记该变量,表明只有当浏览器和web server之间的通信协议为加密认证协议时

  • delete_cookie(name,optionsString) #删除cookie信息

    “name”是要删除的cookie的名称,“optionsString”是该cookie的选项,⽬前⽀持的选项包括“路径”,“域”

  • delete_all_cookies() #删除所有cookie信息

  • 例:

from selenium import webdriver
import time
browser = webdriver.Chrome("F:\Chrome\ChromeDriver\chromedriver")
browser.get("http://www.youdao.com")
#1.打印cookie信息
print('=====================================')
print("打印cookie信息为:")
print(browser.get_cookies)
#2.添加cookie信息
dict={'name':"name",'value':'Kaina'}
browser.add_cookie(dict)
print('=====================================')
print('添加cookie信息为:')
#3.遍历打印cookie信息
for cookie in browser.get_cookies():
print('%s----%s\n' %(cookie['name'],cookie['value']))
#4.删除⼀个cookie
browser.delete_cookie('name')
print('=====================================')
print('删除⼀个cookie')
for cookie in browser.get_cookies():
print('%s----%s\n' %(cookie['name'],cookie['value']))
print('=====================================')
print('删除所有cookie后:')
#5.删除所有cookie,⽆需传递参数
browser.delete_all_cookies()
for cookie in browser.get_cookies():
print('%s----%s\n' %(cookie['name'],cookie['value']))
time.sleep(3)
browser.close()

登录操作

在实际的web应用中,用户登录时通常要求用户输入验证码,验证码大多分为四类:识图验证码、计算验证码、滑块验证码以及语音验证码,这里介绍识图验证码。

两种解决方案:

1、通过cookies绕过登录

  • 原理:先通过一次手动的登录,登录成功后可以获取到对应的cookies,之后,在下一次的访问中,只需要向driver对象添加cookies,即可绕过登录和验证码过程,直接登录。
  • 实例:selenium自动化 | 通过获取cookies登录
  • 更多关于cookies的操作:十三、cookie操作

2、借助识别工具识别验证码

百度AI开放平台:http://ai.baidu.com/

  • 操作方法简介
    1. 使用百度账号登录百度AI开放平台,进入控制台,选择文字识别,点击创建应用
    2. 点击管理应用,获取访问百度服务所需的验证信息AppID、API Key、Secret Key
    3. 安装使用python SDK:pip install baidu-aip
  • 识别过程简介
    1. 截取当前显式验证码的网页图片
    2. 裁剪网页图片得到验证码大图
    3. 调用百度AI平台识别验证码
  • 实例selenium自动化 | 借助百度AI开放平台识别验证码登录职教云

JavaScript操作

虽然WebDriver提供了操作浏览器的前进和后退⽅法,但对于浏览器滚动条并没有提供相应的操作⽅法。在这种情况下,就可以借助JavaScript来控制浏览器的滚动条。

WebDriver提供了此方法执⾏JavaScript代码:

execute_script() 

js代码的相关操作:

  • 输入操作

    • document.getElementById(' ').value=' ';
    • $("id").val("");
  • 单击操作

    • document.getElementById(' ').click();
  • 焦点操作

    • e = driver.find_element_by_id("su")
    • driver.execute_script("arguments[0].blur();" , e) # 移除焦点操作
    • driver.execute_script("arguments[0].blur();" , e) # 赋予焦点操作
  • 浏览器操作

    • window.open(url); # 打开网页地址
    • return document.documentElement.scrollWidth; # 获取网页宽度
    • return document.documentElement.scrollHeight; # 获取网页长度
    • window.resizeTo(width,height); # 绝对方法,设置浏览器窗口的实际大小,即“变化到多少”
    • window.resizeBy(width,height); # 相对方法,在当前大小上增加所指定的参数值,即“变化了多少”
    • window.moveTo(width,height); # 绝对方法,设置窗口新的绝对位置
    • window.moveBy(width,height); # 相对方法,在当前位置上增加所指定的参数值
    • history.forward(); # 控制浏览器前进
    • history.back(); # 控制浏览器后退
    • history.go(number | url);
      • 参数可以是数字number,即要访问的url在history的url列表中的相对位置。(-1表示上一个页面,1表示前进一个页面,0则是刷新页面)
      • 参数可以是一个字符串,字符串必须是局部或完整的url,该函数会去匹配包含字符串的第一个url
    • history.go(0);, location.reload(); , location=location; , location.assign(location); , location.replace(location); # 刷新浏览器
    • window.close(); # 关闭浏览器
  • 鼠标操作

    • 创建事件

      • document.createEvent('MouseEvents');
    • 初始化返回的的时间对象

      • event.initMouseEvent(type,canBuble,cancelable,view,detail,screenX,screenY,clientY,ctrlKey,altKey,metaKey,button,relatedTarget);
      • type:click(单击),dbclick(双击),mouseover(鼠标悬停)
    • 触发事件

      • arguments[0].dispatchEvent()
    • 例:

      e = driver.find_element_by_name("name")
      js = 
      """
          var event = document.createEvent('MouseEvents');
          event.initMouseEvent('click',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
          arguments[0].dispatchEvent(event);
      """ 
      driver.execute_script(js, e)
      
  • 滚动条操作

    • 水平滚动
      • document.documentElement.scrollLeft = 100 # scrollLeft的初始值为0,最初显示页面最左边的内容,随数值变大,向右滑动
    • 垂直滚动
      • document.documentElement.scrollTop = 100 # scrollTop的初始值为0,随数值变大,向下滑动
    • 滚动到指定坐标
      • window.scrollTo(x,y)
      • document.documentElement.scrollTo(x,y)
      • driver.execute_script("arguments[0].scrollIntoView()", driver.find_element...)
    • 滚动到指定的像素数
      • window.scrollBy(x,y)
      • document.documentElement.scrollBy(x,y)
    • 滚动页面元素到可视区域
      • documents[0].scrollIntoView()
  • HTML视频操作

    • 加载

      • driver.execute_script(“return arguments[0].load()",video)
    • 播放

      • driver.execute_script(“return arguments[0].play()",video)
    • 暂停

      • driver.execute_script(“return arguments[0].pause()",video)
    • 例:

      driver.get('https://www.w3school.com.cn/tiy/t.asp?f=html_video')
      driver.switch_to_frame('iframeResult')
      video=driver.find_element_by_xpath('/html/body/video')
      video.click()
      driver.execute_script('return arguments[0].load()',video)
      driver.execute_script('return arguments[0].play()',video)
      driver.execute_script('return arguments[0].pause()',video)
      

窗⼝截图

⾃动化⽤例是由程序去执⾏的,因此有时候打印的错误信息并不⼗分明确。如果在脚本执⾏出错的时候能对当前窗⼝截图保存,那么通过图⽚就可以⾮常直观地看出出错的原因。selenium提供了截图函数get_screenshot_as_file()来截取当前窗⼝:

  • set_window_size() - 设置窗口分辨率
  • get_screenshot_as_file() - 截取当前窗⼝,保存至本地
from selenium import webdriver

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

# 设置窗口分辨率
width = driver.execute_script("return document.documentElement.scrollWidth")
height = driver.execute_script("return document.documentElement.scrollHeight")
driver.set_window_size(width, height)

# 截取当前窗⼝,并指定截图图⽚的保存位置
driver.get_screenshot_as_file("D:\\baidu_img.jpg")
driver.quit()

下面是一些常见状况的解决方案:

反屏蔽

driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
   'source''Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
from selenium import webdriver
from selenium.webdriver import ChromeOptions

option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_experimental_option('useAutomationExtension'False)
driver = webdriver.Chrome(options=option)
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
   'source''Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
driver.get('https://antispider1.scrape.center/')

页面加载超时

  • 方法1: driver.set_page_load_timeout() +driver.set_script_timeout()

    from selenium import webdriver
    from selenium.common.exceptions import TimeoutException
    
    driver = webdriver.Chrome()
    driver.set_page_load_timeout(10)  # 
    driver.set_script_timeout(10)  # 
    
    try:
    	driver.get('https://static4.scrape.center/')
    except TimeoutException:
      driver.execute_script('window.stop()')
      print('页面加载超时')
    
  • 方法2:配置浏览器参数

    from selenium import webdriver
    from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
    
    #get直接返回,不再等待界面加载完成
    desired_capabilities = DesiredCapabilities.CHROME
    desired_capabilities["pageLoadStrategy"] = "none"
    
    driver = webdriver.Chrome()
    driver.get()
    

填写表单的几种姿势

  1. send_keys()

    ele = driver.find_element_by_xpath('//*')
    ele.send_keys('')
    
  2. execute_script()

    js = '$("#kssj").val("");'  # 将id为kssj的元素设置为空
    js = 'document.getElementsByClassName("el-input_inner")[7].value="";'  # 通过class name定位元素,设置其值
    driver.execute_script(js)  
    

页面元素点击的几种姿势

  1. click()

    ele = driver.find_element_by_xpath('//*')
    ele.click()
    
  2. send_keys()

    from selenium.webdriver.common.keys import Keys
    ele = driver.find_element_by_xpath('//*')
    ele.send_keys(Keys.ENTER)
    
  3. 显式等待+click()

    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.exception import TimeoutException
    
    def explicit_waits(driver, xpath, timeout=10):
         try:
            return WebDriverWait(driver, timeout).until(
              EC.presence_of_element_located((By.XPATH, xpath)),
              message=''
            )
         except TimeoutException as e:
            print('元素寻找失败:' + repr(e))
            return False
    
    ele = explicit_waits(driver, '//div[@class="pagination_index"]')
    ele.click()
    
  4. ActionChains()

    from selenium.webdriver.common.action_chains import ActionChains 
    
    ActionChains(driver)
    	.move_to_element(driver.find_element_by_xpath('//*'))
      .click()
      .perform()
    
  5. execute_script()

    js = 'document.getElementById("").click();'
    driver.execute_script(js)
    
  6. execute_script() + ele

    js = 'arguments[0].click();'
    ele = driver.find_element_...
    driver.execute_script(js, ele) #
    

js获取身份验证信息

js = 'return window.localStorage;'
js = 'return window.sessionStorage;'
js = 'return document.cookie;'

控制已打开的浏览器

在使用selenium进行自动化测试中我们有时会遇到这样的情况:

我们需要手动打开浏览器,进入到所需的页面,执行一些手动任务,如输入表单、输入验证码,登陆成功后,然后再开始运行自动化脚本。

这种情况下如何使用selenium来接管先前已打开的浏览器呢?

这里给出Google Chrome浏览器的解决方案。

我们可以利用Chrome DevTools协议。它允许客户检查和调试Chrome浏览器。

(1)步骤1:启动浏览器

  • Windows

    chrome_path = 'C:\\Users\\Billie\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe'  # chrome.exe所在目录,注:双斜杠
    user_data_dir = 'C:\\selenium_ui_auto\\chrome_temp'
    os.system(f'start {chrome_path} --remote-debugging-port=9222 --user-data-dir="{user_data_dir}"')  # 注:双斜杆;start
    
  • macOS

    chrome_path = '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'
    user_data_dir = '~/ChromeProfile'
    os.system(f'{chrome_path} --remote-debugging-port=9222 --user-data-dir="{user_data_dir}";')
    

    cmd命令中的路径存在空格,导致命令出错

    • 措施一

      在路径前后加上双引号,如"user_data_dir"

    • 措施二

      在路径前后加上双引号,以及前面再加上一个双引号,如 start "" "{chrome_path}"

    chrome_path = "C:\Program Files\Google\Chrome\Application\chrome.exe"
    user_data_dir = "C:\Users\police\AppData\Local\Google\Chrome\User Data"
    os.system(rf'start "" "{chrome_path}" --remote-debugging-port=9222 --user-data-dir="{user_data_dir}"')
    

(2)步骤2:捕获调试浏览器

options = Options()
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
driver = webdriver.Chrome(options=options) # 如浏览器不存在,则会在约一分钟(或半分钟)等待之后,报错-WebDriverException

⚠️注:如若捕获不到调试浏览器

  • 可能原因:「chromedriver.exe进程冲突
  • 解决方案:检查任务管理器中是否有多个chromedriver.exe的进程,全部停止任务,重试即可捕获成功。

⚠️注:如遇到捕获浏览器之后,元素操作(比如点击、输入)失败,而在常规启动的浏览器中没有此问题

  • 可能原因:「Chrome的位数与计算机位数不符」。比如64位的计算机,装了32位的Chrome,则会出现上述情况。
  • 解决方案:按同位数安装Chrome浏览器。


8325 字