Python: selenium使用基本步骤, webdriver 自动化, 模拟浏览器登录

 

Python: selenium使用基本步骤, webdriver 自动化, 模拟浏览器登录
Python: selenium使用基本步骤, webdriver 自动化, 模拟浏览器登录

 

  • selenium是什么:一个自动化测试工具(大家都是这么说的)
  • selenium应用场景:用代码的方式去模拟浏览器操作过程(如:打开浏览器、在输入框里输入文字、回车等),在爬虫方面很有必要

 

安装:

 

下载python的selenium安装包

你可以从这里 下载python的selenium安装包,但是更好的办法是用pip来安装。 Python3.7的标准库里就有现成的pip工具,可以用pip安装selenium:

pip install selenium

你可能会想用虚拟机来安装一个独立的Python环境,Python的pyvenc功能和虚拟机基本上是一样的。

 

windows用户的详细说明

注意:你需要联网来完成这个安装

  1. 安装python3.7 安装地址
  2. cmd.exe开启命令行,并用下面的命令安装selenium
C:\Python34\Scripts\pip.exe install selenium

现在你可以用python来运行你的测试脚本了。例如,如果你创建了一个Selenium脚本然后保存到文件C:\my_selenium_script.py,然后运行它:

C:\Python34\python.exe C:\my_selenium_script.py

 

安装chromedriver: 

https://chromedriver.chromium.org/downloads

 

基本步骤:

 

1、导入模块:

from selenium import webdriver  # 启动浏览器需要用到
from selenium.webdriver.common.keys import Keys  # 提供键盘按键支持(最后一个K要大写)

 

2、创建一个WebDriver实例:

driver = webdriver.Chrome("chromedriver驱动程序路径")
options = webdriver.ChromeOptions()
options.add_argument(
    '--user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36')
browser = webdriver.Chrome(executable_path='/var/www/html/selenium/chromedriver', chrome_options=options)

 

3、打开一个页面:

driver.get("http://www.python.org")  # 这个时候chromedriver会打开一个Chrome浏览器窗口,显示的是网址所对应的页面

 

4、关闭页面

driver.close()  # 关闭浏览器一个Tab
# or
driver.quit()  # 关闭浏览器窗口

 

高级-查找元素/定位元素:

在打开页面和关闭页面中间,就是各种操作!而查找元素这一点,和爬虫常见的HTML页面解析,定位到具体的某个元素基本一样,只不过,调用者是driver

element = driver.find_element_by_name("q")  

 

有多种策略可以在页面中定位元素。您可以根据自己的情况选择最合适的一种。Selenium提供了以下方法来查找页面中的元素:

  • 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

 

除了上面给出的公共方法外,还有两个私有方法可能对页面对象中的定位器很有用。这是两个私有方法:find_elementfind_elements

用法示例:

from selenium.webdriver.common.by import By

driver.find_element(By.XPATH, '//button[text()="Some text"]')
driver.find_elements(By.XPATH, '//button')

 

这些是类可用的属性:

ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"

 

通过XPath定位

XPath是用于在XML文档中定位节点的语言。由于HTML可以是XML(XHTML)的实现,因此Selenium用户可以利用这种强大的语言来定位Web应用程序中的元素。XPath扩展了(同时支持)通过id或name属性进行定位的简单方法,并开辟了各种新的可能性,例如在页面上定位了第三个复选框。

使用XPath的主要原因之一是当您没有想要查找的元素的合适的id或name属性时。您可以使用XPath以绝对术语(不建议使用)定位元素,也可以相对于具有id或name属性的元素定位。XPath定位器还可用于通过id和name以外的属性指定元素。

绝对XPath包含来自根(html)的所有元素的位置,因此,仅对应用程序进行一点点调整就可能导致失败。通过查找具有id或name属性的附近元素(最好是父元素),您可以根据关系找到目标元素。这种更改的可能性要小得多,并且可以使您的测试更可靠。

例如,考虑以下页面来源:

<html>
 <body>
  <form id="loginForm">
   <input name="username" type="text" />
   <input name="password" type="password" />
   <input name="continue" type="submit" value="Login" />
   <input name="continue" type="button" value="Clear" />
  </form>
</body>
<html>

表单元素可以这样定位:

login_form = driver.find_element_by_xpath("/html/body/form[1]")
login_form = driver.find_element_by_xpath("//form[1]")
login_form = driver.find_element_by_xpath("//form[@id='loginForm']")
  1. 绝对路径(如果仅对HTML进行少许更改,则会中断)
  2. HTML中的第一个表单元素
  3. 具有名为id的属性和值为loginForm的表单元素

 

username元素可以这样定位:

username = driver.find_element_by_xpath("//form[input/@name='username']")
username = driver.find_element_by_xpath("//form[@id='loginForm']/input[1]")
username = driver.find_element_by_xpath("//input[@name='usern
  1. 具有输入子元素的第一个表单元素,该子元素具有名为name的属性和值为username的属性
  2. 表单元素的第一个输入子元素,其属性名为 id,值为loginForm
  3. 第一个输入元素具有名为“ name”的属性和值 username

 

“清除”按钮元素可以这样定位:

clear_button = driver.find_element_by_xpath("//input[@name='continue'][@type='button']")
clear_button = driver.find_element_by_xpath("//form[@id='loginForm']/input[4]")
  1. 输入属性名称name且值继续,属性名称为type且值按钮
  2. form元素的第四个输入子元素,其属性名为 id,值为loginForm

 

这些示例涵盖了一些基础知识,但是为了了解更多信息,建议您参考以下内容:

 

还有两个非常有用的附加组件,可以帮助发现元素的XPath:

  • XPath Checker-建议使用XPath,可用于测试XPath结果。
  • Firebug -XPath建议只是该非常有用的附件的许多强大功能之一。
  • XPath Helper-适用于Google Chrome

 

通过链接文本查找超链接

例如,考虑以下页面来源:

<html>
 <body>
  <p>Are you sure you want to do this?</p>
  <a href="continue.html">Continue</a>
  <a href="cancel.html">Cancel</a>
</body>
<html>

continue.html链接可以这样定位:

continue_link = driver.find_element_by_link_text('Continue')
continue_link = driver.find_element_by_partial_link_text('Conti')

 

通过CSS选择器定位元素

当您要通过CSS选择器语法查找元素时,请使用此选项。使用此策略,将返回具有匹配CSS选择器的第一个元素。如果没有元素具有匹配的CSS选择器,NoSuchElementException则将引发a。

例如,考虑以下页面来源:

<html>
 <body>
  <p class="content">Site content goes here.</p>
</body>
<html>

“ p”元素可以这样定位:

content = driver.find_element_by_css_selector('p.content')

Sauce Labs 在CSS选择器方面有很好的文档

 

高级-页面交互:

找到元素后,就是进行“交互”,如键盘输入(需提前导入模块)

element.send_keys(“some text”)  # 往一个可以输入对象中输入“some text”

 

甚至

element.send_keys(Keys.RETURN)  # 模拟键盘回车

 

一般来说,这种方式输入后会一直存在,而要清空某个文本框中的文字,就需要:

element.clear()  # 清空element对象中的文字

 

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

driver = webdriver.Firefox()
driver.get("http://www.python.org")
assert "Python" in driver.title
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
driver.close()

上面的脚本可以保存到文件中(例如: -python_org_search.py),然后可以像这样运行:

python python_org_search.py

您正在运行的python应该已经安装了selenium模块。

这是使用unittest模块的修改后的示例。这是对python.org搜索功能的测试:

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

class PythonOrgSearch(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Firefox()

    def test_search_in_python_org(self):
        driver = self.driver
        driver.get("http://www.python.org")
        self.assertIn("Python", driver.title)
        elem = driver.find_element_by_name("q")
        elem.send_keys("pycon")
        elem.send_keys(Keys.RETURN)
        assert "No results found." not in driver.page_source


    def tearDown(self):
        self.driver.close()

if __name__ == "__main__":
    unittest.main()

 

您可以从这样的外壳运行上述测试用例:

python test_python_org_search.py
.
----------------------------------------------------------------------
Ran 1 test in 15.566s

OK

以上结果表明测试已成功完成。

遍历示例

最初,所有必需的基本模块都已导入。该单元测试模块是内置Python基于Java的JUnit。该模块提供了组织测试用例的框架。该selenium.webdriver模块提供了所有的webdriver实现。当前支持的WebDriver实现是Firefox,Chrome,IE和Remote。该类提供键在键盘像RETURN,F1,ALT等。

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

测试用例类继承自unittest.TestCase。从TestCase类继承是告诉unittest模块这是一个测试用例的方法:

class PythonOrgSearch(unittest.TestCase):

的setUp是初始化的一部分,此方法将你要在这个测试用例类写的每一个测试函数之前被调用。在这里,您将创建Firefox WebDriver的实例。

def setUp(self):
    self.driver = webdriver.Firefox()

这是测试用例方法。测试用例方法应始终以字符test开头。此方法内的第一行创建对在setUp方法中创建的驱动程序对象的本地引用。

def test_search_in_python_org(self):
    driver = self.driver

driver.get方法将定位在给定的URL的网页。WebDriver将等待页面完全加载(即,已触发“ onload”事件),然后再将控制权返回给测试或脚本。值得注意的是,如果您的页面在加载时使用了很多AJAX,则WebDriver可能不知道何时完全加载。

driver.get("http://www.python.org")

下一行是一个断言,以确认标题中包含“ Python”一词:

self.assertIn("Python", driver.title)

WebDriver提供了多种使用find_element_by_ *方法之一查找元素的 方法。例如,可以使用find_element_by_name 方法通过其name属性找到输入文本元素。查找元素的详细说明可在“ 查找元素”一章中 找到

elem = driver.find_element_by_name("q")

接下来,我们要发送密钥,这类似于使用键盘输入密钥。可以使用从selenium.webdriver.common.keys导入的Keys类 发送特殊密钥:

elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)

提交页面后,如果有搜索结果,则应按照搜索得到结果。为了确保找到一些结果,请声明:

assert "No results found." not in driver.page_source

拆卸方法将每个测试方法之后被调用。这是执行所有清理操作的地方。在当前方法中,浏览器窗口关闭。您也可以调用quit方法而不是 close。该退出将退出整个浏览器,而关闭 将关闭一个标签,但如果它是唯一选项卡中打开,默认情况下大多数浏览器将完全退出:

def tearDown(self):
    self.driver.close()

最后一行是一些运行测试套件的样板代码:

if __name__ == "__main__":
    unittest.main()

 

将Selenium与远程WebDriver一起使用

要使用远程WebDriver,您应该正在运行Selenium服务器。要运行服务器,请使用以下命令:

java -jar selenium-server-standalone-2.x.x.jar

在运行Selenium服务器时,您可能会看到类似以下的消息:

15:43:07.541 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub

上一行说,您可以使用此URL连接到远程WebDriver。这里有些例子:

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

driver = webdriver.Remote(
   command_executor='http://127.0.0.1:4444/wd/hub',
   desired_capabilities=DesiredCapabilities.CHROME)

driver = webdriver.Remote(
   command_executor='http://127.0.0.1:4444/wd/hub',
   desired_capabilities=DesiredCapabilities.OPERA)

driver = webdriver.Remote(
   command_executor='http://127.0.0.1:4444/wd/hub',
   desired_capabilities=DesiredCapabilities.HTMLUNITWITHJS)

所需的功能是字典,因此可以使用显式指定值,而不是使用默认字典:

driver = webdriver.Remote(
   command_executor='http://127.0.0.1:4444/wd/hub',
   desired_capabilities={'browserName': 'htmlunit',
                         'version': '2',
                        'javascriptEnabled': True})

 

高级-等待页面加载(wait)

应用场景:含有ajax加载的page!因为在这种情况下,页面内的某个节点并不是在一开始就出现了,而在这种情况下,就不能“查找元素”,元素选择不到,就不好进行交互操作!
等待页面加载这两个模块经常是一起导入的:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

 

1. 休眠等待
添加休眠非常简单,只需要引入python的time包,调用其中的sleep()方法。
这一种休眠方式会强制休眠对应的时间长度,不管页面或元素是否显示,因此会出现影响运行效率的问题,长时间的休眠不建议使用。

用法:

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

time.sleep(0.1)   # 休眠0.1秒
time.sleep(3)   # 休眠3秒

 

2. 智能等待-隐式等待
通过添加implicitly_wait()方法就可以实现智能等待,其为是 webdirver 提供的一个超时等待,文档中的解释:隐式地等待一个元素被发现,或命令来完成。
当使用了隐式等待执行测试的时候,如果 WebDriver没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常。
换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM。一旦设置了隐式等待,则它存在整个 WebDriver 对象实例的声明周期中,隐式的等到会让一个正常响应的应用的测试变慢,它将会在寻找每个元素的时候都进行等待,这样会增加整个测试执行的时间。

用法:

driver.implicitly_wait(30)

 

3. 智能等待-显示等待
WebDriverWait()类: webdirver 提供的方法。简单来说就是WebDriver每隔一段时间就对页面元素进行检测,直到达到设定条件或超过设定时间,默认会抛出NoSuchElementException的异常。

文档解释:

WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
driver - WebDriver 的驱动程序(Ie, Firefox, Chrome 或远程)
timeout - 超时时间,默认以秒为单位
poll_frequency - 休眠时间的间隔(步长)时间,默认为 0.5 秒
ignored_exceptions - 超时后的异常信息,默认情况下抛 NoSuchElementException 异常。
WebDriverWait()一般由 until()或 until_not()方法配合使用,下面是 until()和 until_not()方法的说明。
until(method, message=’’)
调用该方法提供的驱动程序作为一个参数,直到返回值不为 False。
until_not(method, message=’’)
调用该方法提供的驱动程序作为一个参数,直到返回值为 False。

 

文档中提供的实例

from selenium.webdriver.support.ui import WebDriverWait 

element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId"))

is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).until_not(lambda x: x.find_element_by_id("someId").is_displayed())

 

同城WebDriverWait要和expected_conditions.py文件配合使用,expected_conditions.py提供了一系列用于元素判断的方法,按需使用对应的方法即可。

 

几个方法实例:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# 等待元素出现在DOM
WebDriverWait(self._driver).until(EC.presence_of_element_located((By.ID, value)))

# 等待元素显示在页面
WebDriverWait(self._driver,10).until(EC.visibility_of_element_located((By.NAME, value)))

# 等待元素从页面消失
WebDriverWait(self._driver, 10, 0.2).until_not(EC.visibility_of_element_located((By.CLASS_NAME, value))))

# 等待页面的title显示
WebDriverWait(self._driver, 5,0.2).until(EC.title_contains(title))

 

WebDriverWait

wait模块的WebDriverWait类是显性等待类,先看下它有哪些参数与方法:

selenium.webdriver.support.wait.WebDriverWait(类)

__init__
    driver: 传入WebDriver实例,即我们上例中的driver
    timeout: 超时时间,等待的最长时间(同时要考虑隐性等待时间)
    poll_frequency: 调用until或until_not中的方法的间隔时间,默认是0.5秒
    ignored_exceptions: 忽略的异常,如果在调用until或until_not的过程中抛出这个元组中的异常,
            则不中断代码,继续等待,如果抛出的是这个元组外的异常,则中断代码,抛出异常。默认只有NoSuchElementException。

until
    method: 在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False
    message: 如果超时,抛出TimeoutException,将message传入异常

until_not 与until相反,until是当某元素出现或什么条件成立则继续执行,
        until_not是当某元素消失或什么条件不成立则继续执行,参数也相同,不再赘述。
    method
    message

 

看了以上内容基本上很清楚了,调用方法如下:

WebDriverWait(driver, 超时时长, 调用频率, 忽略异常).until(可执行方法, 超时时返回的信息)

 

这里需要特别注意的是until或until_not中的可执行方法method参数,很多人传入了WebElement对象,如下:

WebDriverWait(driver, 10).until(driver.find_element_by_id('kw'))  # 错误

 

这是错误的用法,这里的参数一定要是可以调用的,即这个对象一定有 __call__() 方法,否则会抛出异常:

TypeError: 'xxx' object is not callable

 

在这里,你可以用selenium提供的 expected_conditions 模块中的各种条件,也可以用WebElement的 is_displayed() 、is_enabled()is_selected() 方法,或者用自己封装的方法都可以,那么接下来我们看一下selenium提供的条件有哪些:

 

expected_conditions

expected_conditions类所提供的预期条件判断的方法如下:

  • title_is(title):预期页面标题匹配title
  • title_contains(title):预期页面标题包含title
  • presence_of_element_located(locator):预期指定位置的元素出现在DOM中
  • url_contains(url):预期url包含在当前页面的url中
  • url_to_be(url):预期url与当前页面url完全匹配
  • url_changes(url):预期url不等于当前页面url
  • visibility_of_element_located(locator):预期指定位置的元素可显示出来
  • visibility_of(element):预期指定元素对象可见
  • text_to_be_present_in_element(locator, text_):预期指定文本与指定元素的文本相同
  • text_to_be_present_in_element_value(locator, text_):预期指定文本与指定元素的属性value值相同
  • frame_to_be_available_and_switch_to_it(locator):预期指定的iframe是可以被切换的,并且自动切换到iframe中
  • invisibility_of_element_located(locator):预期指定元素即不可见也不存在DOM中。
  • element_to_be_clickable(locator):预期指定位置的元素是可见,并且可被点击的。
  • element_to_be_selected(element):预期指定元素是已选中的
  • element_located_to_be_selected(locator):预期指定位置的元素是已
  • alert_is_present():预期当前存在alert弹窗

上面是所有17个condition,与until、until_not组合能够实现很多判断,如果能自己灵活封装,将会大大提高脚本的稳定性。

今天就分享这些内容,有什么问题可以留言给我交流,希望能帮助到有需要的同学。

 

 

 

 

 

 

本文:Python: selenium使用基本步骤, webdriver 自动化, 模拟浏览器登录

 

 

One Comment

Leave a Reply