用selenium完成自动化任务

Selenium 是一个控制浏览器的自动化软件,常常用来做自动化UI测试(浏览器端),既然可以代码控制, 那么就是自动化的一个好工具了。这一篇我们就来看看如何使用 Selenium 来搜索一下,由于 Selenium 打开一个全新的浏览器会话,我没有配置全局梯子,我们就以百度搜索为例。

安装

Selenium 一共支持5种语言: C#, JavaScript, Java, Python, Ruby。我以Python为例:

$ pip install selenium
...
$

这里我们就安装了语言所需要的部分,但是为了控制浏览器,我们还需要安装浏览器的相关驱动,Selenium 支持 Chrome, Firefox, Edge, Safari 四大浏览器,但是都要下载对应的 Driver 才行:

其余浏览器见 官网

驱动下载解压后,将可执行文件放到 PATH 里,我是直接放到 /usr/local/bin/chromedriver 这里。

简单示例

我们来看看如何进行搜索:

import logging
import time

from selenium import webdriver
from selenium.webdriver.chrome.options import Options


logging.basicConfig(level=logging.INFO)


DEBUG = True


def search_with_baidu(driver):
    driver.get("https://www.baidu.com")  # 打开页面

    input_text = driver.find_element_by_xpath('//*[@id="kw"]')  # 找到输入框
    click_to_search = driver.find_element_by_xpath('//*[@id="su"]')  # 找到搜索按钮

    input_text.send_keys("selenium tutorial")  # 输入内容
    click_to_search.click()  # 点击搜索


def search_baidu():
    if DEBUG:
        driver = webdriver.Chrome()
    else:
        chrome_options = Options()
        chrome_options.add_argument("--headless")
        # https://stackoverflow.com/questions/50642308/webdriverexception-unknown-error-devtoolsactiveport-file-doesnt-exist-while-t
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument('--disable-dev-shm-usage')
        driver = webdriver.Chrome(options=chrome_options)

    try:
        search_with_baidu(driver)
        time.sleep(10)
    except Exception:
        logging.exception("failed to search, sleep and retry...")
    finally:
        driver.close()
        driver.quit()


if __name__ == "__main__":
    search_baidu()

可以看到,大体的流程是:

  • 首先 driver = webdriver.Chrome() 获得一个driver
  • 之后就可以通过 driver 来进行各种浏览器操作,比如 find_element_by_xpath 来找到对应的元素
  • 获得的元素也可以进行各种操作,比如 send_keys, click
  • 最后通过 driver.close() 关闭页面,driver.quit() 退出会话

如果在本地执行,我们直接使用 driver = webdriver.Chrome(),如果想要在服务端运行, 那么就要使用 headless 模式来运行 Chrome,就是在启动的时候加上对应的参数即可。 区别在于,前者会弹出一个浏览器来,而后者是不需要图形界面就可以运行的,前者方便调试,后者方便在服务器上运行。

如果是使用 Selenium 来写UI自动化测试,那么还可以结合 Python 中的 unittest, pytest 等框架实现自动化测试。

API

接下来我们看看 Selenium 都有哪些 API 可以供我们操作。

浏览器相关操作

  • driver.get("https://selenium.dev") 打开页面
  • driver.current_url 获取当前页面
  • driver.back() 返回上一页
  • driver.forward() 前进一页(相当于点击浏览器的前进)
  • driver.refresh() 刷新页面
  • driver.title 获取当前页面标题
  • driver.close() 关闭当前页面
  • driver.switch_to.window(original_window) 切换窗口(Selenium 不区分Window和Tab)
  • driver.quit() 退出浏览器,请记得一定要执行这个,否则就进程泄漏了
  • width = driver.get_window_size().get("width")height = driver.get_window_size().get("height") 获取窗口大小
  • driver.set_window_size(1024, 768) 设置窗口大小
  • driver.maximize_window()driver.minimize_window() 最大化和最小化窗口
  • driver.fullscreen_window() 全屏,相当于按F11
  • driver.save_screenshot('./image.png') 截屏保存
  • ele = driver.find_element(By.CSS_SELECTOR, 'h1') + ele.screenshot('./image.png') 找到某个元素并且截屏
  • driver.execute_script('return arguments[0].innerText', header) 执行脚本

元素定位操作

# 查找单个元素
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector

# 查找多个元素
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector

输入输出操作

  • element.send_keys() 输入
  • element.clear() 清除输入
  • key_down()key_up() 分别是模拟按下某个键和放开某个键的过程,例如按下Shift然后松开:

    search = driver.find_element(By.NAME, "q")
    
    action = webdriver.ActionChains(driver)
    
    # Enters text "qwerty" with keyDown SHIFT key and after keyUp SHIFT key (QWERTYqwerty)
    action.key_down(Keys.SHIFT).send_keys_to_element(search, "qwerty").key_up(Keys.SHIFT).send_keys("qwerty").perform()
    

这样就会输出 QWERTY 而不是 qwerty。

其余操作

除了上述常见操作之外,Selenium 还支持很多其它操作,例如执行js脚本, 等待元素加载,设置代理等,详情查看 文档

总结

这篇文章我们看了一下 Selenium 这个工具的大概用法,了解了之后,就可以借助 Selenium 做很多事情了,比如 常规点的,自动化测试,比如不太常规的,签到,打卡等等。。。

好了,以上就是本篇内容。


ref:


更多文章
  • logrotate read only filesystem问题
  • Golang GIN写单测时,愉快的使用返回值
  • Python Queue源码分析
  • Go里优雅的使用全局配置
  • Golang sync.Map源码分析
  • Android滑动时隐藏FAB
  • Python中用tuple作为key
  • 一些常用的算法思维
  • 编写可维护的函数
  • 为什么要把配置保存在仓库里?
  • Android自动展示和关闭进度条
  • Kotlin/Java 列表Protobuf序列化
  • deeplink结合路由处理扩展App的能力
  • 怎么使用ViewModel 和 RecyclerView
  • Android手动挡MVVM