selenium

官网:https://www.selenium.dev
安装:pip install selenium

安装 ChromeDriver

  • 根据 chrome 版本下载:https://chromedriver.chromium.org/downloads

  • 解压下载的 zip

  • 把解压出来的文件 chromedriver 复制或者移动到 /usr/local/bin 目录下

Demo

test_selenium.py

from selenium import webdriver
import time


def test_selenium():
    # 获取浏览器驱动
    driver = webdriver.Chrome()
    # 访问百度
    driver.get("https://www.baidu.com/")
    # 等待
    time.sleep(2)
    # 退出
    driver.quit()

执行:pytest test_selenium.py

元素的定位与操作

元素定位

  • id
  • name
  • class_name
  • tag_name
  • link_text 文本链接
  • partial_link_text 模糊匹配
  • xpath

元素操作

  • click()
  • clear()
  • send_keys()
  • ActionChains 鼠标键盘
    • 鼠标
      • click
      • click_and_hold
      • context_click 右键
      • double_click
      • drag_and_drop(source, target) 拖动
      • Perform 执行
    • 键盘
      • key_down 按下
      • key_up 松开
      • send_keys(Keys.按键) 输入某个按键
      • Perform 执行
  • TouchAction 兼容H5页面
    • tap 点击
    • double_tap 双击
    • tap_and_hold
    • move 移动未释放
    • release 释放
    • scroll 按住滚动
    • scroll_from_element 从某个元素开始按住滚动
    • long_press 长按
    • flick 手势滑动
    • flick_element 从某个元素开始滑动
    • Perform 执行

在百度首页输入关键字进行搜索

test_selenium.py

from selenium import webdriver
import time


class TestBaidu:
    def setup(self):
        # 获取浏览器驱动
        self.driver = webdriver.Chrome()
        # 访问百度
        self.driver.get("https://www.baidu.com/")

    def test_selenium(self):
        time.sleep(2)
        # 定位到搜索框,输入关键字
        self.driver.find_element_by_id("kw").send_keys("selenium")
        time.sleep(2)
        # 定位到百度一下按钮,点击
        self.driver.find_element_by_id("su").click()

    def teardown(self):
        time.sleep(2)
        # 退出
        self.driver.quit()

模拟键盘鼠标操作

from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys

...             
            # 定位到一个按钮
        button = self.driver.find_element_by_id("test_button")
        # 定位到一个文本链接
        link_text = self.driver.find_element_by_link_text("test_link")

        # 定位到两个元素
        drag_element = self.driver.find_element_by_id("test_drag")
        drop_element = self.driver.find_element_by_id("test_drop")

        action = ActionChains(self.driver)
        # 点击
        action.click(button)
        # 点击按住
        action.click_and_hold(button)
        # 右键
        action.context_click(button)
        # 双击
        action.double_click(button)
        # 鼠标移动到这个文本链接
        action.move_to_element(link_text)
        # 将一个元素拖拽到另一个元素上
        action.drag_and_drop(drag_element, drop_element)

        # 键盘输入回车键
        action.send_keys(Keys.ENTER)

        # 执行
        action.perform()
...

等待的方式

  • time.sleep() 等待的时间是固定的
  • implicitly_wait() 隐式等待,设置一次,对全局的 driver 都启用相同的等待时间,找到元素就不再等待
  • WebDriverWait 显示等待,根据传入的条件判断是否继续等待
    • selenium 提供 expected_conditions 方法
    • expected_conditions 方法提供了 element_to_be_clickable 等判断条件

隐式等待

...
    def setup(self):
        # 获取浏览器驱动
        self.driver = webdriver.Chrome()
        # 隐式等待
        self.driver.implicitly_wait(2)
        # 访问百度
        self.driver.get("https://www.baidu.com/")
...

显示等待

...  
  def test_selenium(self):
        # 定位到搜索框,输入关键字
        self.driver.find_element_by_id("kw").send_keys("selenium")
        # 判断百度一下按钮是不是可点击的状态
        ture_or_false = expected_conditions.element_to_be_clickable((By.ID, "su"))
        # 如果是,就不再等待,如果不是,就继续等待,最多等待10秒
        WebDriverWait(self.driver, 10).until(ture_or_false)
        # 点击百度一下按钮
        self.driver.find_element_by_id("su").click()
...

多窗口处理

句柄,是窗口的 id

先获取当前窗口的句柄,使用 driver.current_window_handle

然后获取所有窗口的句柄,使用 driver.window_handles

窗口切换,使用 driver.switch_to.window()

窗口切换的例子:

因为 setup 和 teardown 比较常用,所以这里把他们添加到了 base.py 中

base.py

from selenium import webdriver


class Base:
    def setup(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(3)

    def teardown(self):
        self.driver.quit()

窗口切换

test_window.py

import sys
sys.path.append("..")

from this_is_selenium.base import Base


class TestWindow(Base):

    def test_window(self):
        # 访问百度
        self.driver.get("https://www.baidu.com")
        # 点击登录,点击之后,后有一个弹框
        self.driver.find_element_by_link_text("登录").click()
        # 点击弹框中的立即注册,点击之后,会在新窗口打开注册页面
        self.driver.find_element_by_link_text("立即注册").click()
        # 当前窗口的句柄
        now_window = self.driver.current_window_handle
        # 所有窗口的句柄
        all_window = self.driver.window_handles
        # 遍历所有窗口的句柄
        for window in all_window:
            # 如果不是当前窗口
            if window != now_window:
                # 切换窗口
                self.driver.switch_to.window(window)
        # 在新窗口的注册页面输入用户名
        self.driver.find_element_by_id("TANGRAM__PSP_4__userName").send_keys("username")

frame 切换

frame 是框架,在一个页面中可能存在多个 frame ,相互独立,所以会出现在这个 frame 中定位不到另一个 frame 中的元素的情况。这个时候需要切换 frame 。

driver.switch_to.frame()

driver.switch_to.default_content() 切换到默认 frame

driver.switch_to.parent_frame() 切换到父级 frame

执行 JS

execute_script 执行

return 返回 js 的返回结果

execute_script arguments 传参

test_js.py

import sys
sys.path.append("..")
from this_is_selenium.base import Base
import time


class TestJS(Base):
    # 执行 js 控制滚动条
    def test_js(self):
        self.driver.get("https://www.baidu.com")
        # 浏览器窗口最大化
        self.driver.maximize_window()
        # 搜索关键字
        self.driver.find_element_by_id("kw").send_keys("selenium")
        # 点击百度一下按钮
        self.driver.find_element_by_id("su").click()
        time.sleep(3)
        # 执行 js 获取当前页面的 title
        js_title = "return document.title"
        print(self.driver.execute_script(js_title))
        time.sleep(3)
        # 执行 js 将滚动条拖到底部
        js_scroll = "document.documentElement.scrollTop=10000"
        self.driver.execute_script(js_scroll)
        # 点击用户反馈
        self.driver.find_element_by_link_text("用户反馈").click()
        time.sleep(3)

有的日期控件是只读的,通过 selenium 不能赋值,可以通过执行 js 脚本

  1. 获取到日期控件:date_input = document.getElementById("train_date")
  2. 去掉日期控件的只读属性:date_input.removeAttribute("readonly")
  3. 赋值:date_input.value="1949-09-30"

test_dateinput.py

import sys
sys.path.append("..")
from this_is_selenium.base import Base
import time


class TestDataInput(Base):

    def test_dateinput(self):
        self.driver.get("https://www.12306.cn/index/")
        self.driver.maximize_window()
        self.driver.execute_script('date_input=document.getElementById("train_date")')
        self.driver.execute_script('date_input.removeAttribute("readonly")')
        print(self.driver.execute_script('return date_input.value="1949-09-30"'))
        time.sleep(3)
      

执行:pytest test_dateinput.py -vs

执行结果:

collected 1 item                                                                                                                                                                                                          

test_dateinput.py::TestDataInput::test_dateinput 1949-09-30
PASSED

文件上传

send_keys("文件路径")

弹框处理

switch_to.alert()

accept() 确认

  • driver.switch_to.alert.acceppt()

dismiss 取消

text 获取弹框上面的文本信息

复用浏览器

不重新打开新的浏览器。应用场景:比如有时候需要通过手机扫码登录,selenium 无法实现扫码操作。可以通过复用浏览器的方式,因为复用的浏览器会记录浏览器的会话状态。

命令行输入 chrome -remote-debugging-port=9999

chrome_arg = webdeiver.ChromeOptions()
chrome_arg.debugger_address = '127.0.0.1:9999'
self.driver = webdriver.Chrome(options=chrome_arg)
self.driver.get('...')

使用 cookie

...
# 登录
...
# 获取
cookies = driver.get_cookies()
# 添加
for i in cookies:
    driver.add_cookie(i)

page object 设计模式

页面 --> 类

首页 --> class HomePage

注册页 --> class RegisterPage

登录页 --> class LoginPage

...

pages

首页有哪些功能:进入注册页,进入登录页...

home_page.py

class HomePage:
    def goto_register(self):
        pass
  def goto_login(self):
    pass

注册页有哪些功能:注册...

register_page.py

class RegisterPage:
    def register(self):
    pass

登录页有哪些功能:进入注册页,登录,忘记密码...

login_page.py

class LoginPage:
  def goto_register(self):
        pass
  
  def login(self):
    pass
  
    def forget_password(self)
    pass

实现功能

home_page.py

class HomePage:
  def __init__(self):
    self.driver = webdriver.Chrome()
    self.driver.implicitly_wait(10)
    self.driver.get("...")
    
    def goto_register(self):
        self.driver.find_element_by_id("register").click()
    return RegisterPage(self.driver)
  
  def goto_login(self):
    self.driver.find_element_by_id("login").click()
    return LoginPage(self.driver)

register_page.py

class RegisterPage:
  def __init__(self, driver):
    self.driver = driver
    
    def register(self):
    pass

login_page.py

class LoginPage:
  def __init__(self, driver):
    self.driver = driver
  
  def goto_register(self):
        self.driver.find_element_by_id("register").click()
    return RegisterPage(self.driver)
  
  def login(self):
    pass
  
    def forget_password(self)
    pass

测试

cases

test_register.py

class TestRegister:
  def test_register(self):
    home = HomePage()
    home.goto_register().register()
    
  def test_register_from_login(self):
    home = HomePage()
    home.goto_login().goto_register().register()
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 洞见SELENIUM自动化测试 写在最前面:目前自动化测试并不属于新鲜的事物,或者说自动化测试的各种方法论已经层出...
    厲铆兄阅读 6,663评论 3 47
  • 快速入门 Selenium是一个简便的Web应用软件测试工具。Selenium的组件Selenium IDE支持录...
    python测试开发阅读 2,079评论 0 16
  • 自动化介绍:UI自动化测试 Selenium简介:测试web应用程序用户界面(ui)的常用框架pip instal...
    nayli阅读 293评论 1 8
  • 这篇文章在介绍官网的同时使用了比较多的脚本示例,示例里遇到的问题有部分在本篇文章进行了解释,还有一篇文章专门记录了...
    顾顾314阅读 12,791评论 3 32
  • ​ 一、前言 由于requests模块是一个不完全模拟浏览器行为的模块,只能爬取到网页的HTML文档信息,无法解析...
    梵音11阅读 847评论 0 0