[Python] - 爬虫之 Selenium 的使用

Selenium 介绍

SeleniumThroughWorks 一个强大的基于浏览器的开源自动化测试工具,它通常用来编写 Web 应用的自动化测试。

现在所说的 Selenium 即为 Selenium 2,又名 WebDriver,是一个用来进行复杂重复的 Web 自动化测试的工具。

关于 Selenium 的学习,我请教了从事 Python 多年的朋友,他推荐最好最快的方法就是看 Selenium-python 官方文档, 我打开一看,内容挺多,关键还是纯英文,吓了一跳。后来想,还是抽时间慢慢啃吧,反正基本内容是看的懂的。

重在静心、用心看。


安装

安装 Selenium
  • pip 方式安装【推荐】
# Python 2.x
pip install selenium

# Python 3.x
pip3 install selenium
Mac OS 系统安装浏览器驱动器 Drivers
  • Selenium 的使用需要依赖浏览器的驱动 Drivers
  • 浏览器驱动放到位置在自己电脑的 /usr/bin 或者 /usr/local/bin 目录下

现在比较流行的浏览器驱动器及下载地址

浏览器驱动下载地址
Chromehttps://sites.google.com/a/chromium.org/chromedriver/downloads
Edgehttps://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
Firefoxhttps://github.com/mozilla/geckodriver/releases
Safarihttps://webkit.org/blog/6900/webdriver-support-in-safari-10/

快速入门

简单尝试

如果我们安装了 Selenium, 和浏览器的驱动,可以尝试如下:

# 引入 selenium 中的 webdriver
from selenium import webdriver
# 引入 webdriver 中的键盘控制 Keys,RETURN, F1, ALT etc.
from selenium.webdriver.common.keys import Keys

# 创建知道浏览器的 Driver
driver = webdriver.Chrome()
# 通过 Driver 打开浏览器并访问指定 URL
driver.get("http://www.python.org")
# 判断是否打开成功
assert "Python" in driver.title
# 获取 name 为 q 的元素, 此处为 input 输入框
element = driver.find_element_by_name("q") 
# 清空输入框内的内容
element.clear()
# 给输入框添加文字
element.send_keys('pycom')
# 模拟键盘的 RETURN 按键
element.send_keys(Keys.RETURN)
# 判断搜索是否成功
assert "No results found." not in driver.page_source
# 关闭驱动器
driver.close()

执行以上命令,会自动打开 Chrome 浏览器,并打开 http://www.python.org 网页,在搜索框中自动输入pycon, 并完成搜索,输出搜索结果。

是不是很轻大?


补充:assert 的用法

格式

# 如果 condition 是 True, pass; 否则报错
assert condition

示例

>>> assert True  # nothing happens
>>> assert False # AssertionError

使用 Selenium 写测试案例
  • Selenium 通常用来写测试案例
  • Selenium 本身不提供测试工具和框架,我们可以使用 Python 自到的测试模块 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.Chrome()

    def test_search_in_python_org(self):
        driver = self.driver
        driver.get("http://www.python.org")
        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()

运行结果:

.
----------------------------------------------------------------------
Ran 1 test in 9.557s

OK

结果显示:测试成功,花费总时间 9.557 秒


页面操作

使用 WebDriver 操作,第一件事就是去操作一个链接
正常的做法就是使用 get 方法

driver.get("http://www.baidu.com")

WebDriver 将等到页面完全加载(即 onload 事件执行完)然后返回控制您的测试或脚本。


和网页交互

WebDriver 提供了大量的方法来找到元素。

例如,给出下面一个元素:

<input type="text" name="passwd" id="passwd-id" />

通过如下方式查找出:

element = driver.find_element_by_id("passwd-id")
element = driver.find_element_by_name("passwd")
element = driver.find_element_by_xpath("//input[@id='passwd-id']")

同时我们可以通过文本去查找,但小心的是,文本必须是准确查找。当在 WebDriver 使用 XPATH 时,当有多处匹配的时候,只会返回第一个结果。如果匹配失败,会出现 NoSuchElementException 错误

WebDriver 有一个面向对象的 API, 对于不同的元素,使用相同的接口。意思是虽然 WebDriver 提供了有很多的方法,但并不是对每个元素都起作用的。不用担心,当我们调用一个方法时,如果不起作用,会抛出异常,可以使用 Exception 去捕捉。

所以对于一个 text field 元素,我们想输入文本

inputElement.send_keys("some text")

可以使用 clear()方法清空文本内容

inputElement.clear()

也可以模拟点击事件,通过 Keys 类来模拟点击显示更多箭头

element.send_keys("click for more", Keys.ARROW_DOWN)

填充表单

对于 HTML 中的 OPTION 标签,我们需要进行额外的方法操作

element = driver.find_element_by_xpath("//select[@name='name']")
all_options = element.find_elements_by_tag_name("option")
for option in all_options:
    print("Value is: %s" % option.get_attribute("value"))
    option.click()

使用这个方法,会依次选择每个 option 选项

可以看到,上面不是最有效的方式处理选择元素。WebDriver的支持只选择一个,称为“选择”,它提供了有用的交互方法

from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_name('name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)

WebDriver 还提供了取消所有选中的选项

select = Select(driver.find_element_by_id('id'))
select.deselect_all()

假设在一个测试中,我们需要所有默认选中选项的列表,选择类提供了一个属性方法返回一个列表:

select = Select(driver.find_element_by_xpath("xpath"))
all_selected_options = select.all_selected_options

获取所有的可用的选项

options = select.options

当你完成表单的填充,下一步就是提交。
一种方式就是找到 submit 按钮,然后添加点击事件

# Assume the button has the ID "submit" :)
driver.find_element_by_id("submit").click()

另一种方式,WebDriver 提供了另外一个便利的 submit() 方法。当我们在表单元素中使用这个方法,WebDriver 会遍历所有的 DOM 直到
提交操作然后执行它。
如果元素不是在 from 表单中,将会抛出异常:NoSuchElementException

element.submit()

拖放

可以使用拖放,从某个元素的位置移动到另一个元素的位置上

element = driver.find_element_by_name("source")
target = driver.find_element_by_name("target")

from selenium.webdriver import ActionChains
action_chains = ActionChains(driver)
action_chains.drag_and_drop(element, target).perform()

弹出对话框

WebDriver 支持对话框的弹出处理。在触发打开弹出窗口的操作后,会打来一个对话框,可以通过以下方式处理对话框:

alert = driver.switch_to_alert()

将返回当前对话框对象。使用这个对象,我们可以接受,消失(取消),阅读其内容,甚至可以是输入操作。


导航:历史和位置

在浏览器的历史中向前和向后移动:

driver.forward()
driver.back()

Cookies

在同一域中,cookies 是有效的

# Go to the correct domain
driver.get("http://www.example.com")

# Now set the cookie. This one's valid for the entire domain
cookie = {‘name’ : ‘foo’, ‘value’ : ‘bar’}
driver.add_cookie(cookie)

# And now output all the available cookies for the current URL
driver.get_cookies()

元素查找

总体概述

在一个页面中,有各种各样的方法来定位元素

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_element
  • find_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"
通过 ID 查找

当我们知道某个元素的 id 属性时,可以使用 ID 方法查找
当匹配成功时,返回第一个元素;匹配失败,抛出异常:NoSuchElementException

代码示例:

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

查找表单:

login_form = driver.find_element_by_id('loginForm')
通过 Name 查找

当我们知道某个元素的 name 属性时,可以使用 Name 方法查找
当匹配成功时,返回第一个元素;匹配失败,抛出异常:NoSuchElementException

代码示例:

<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>

查找 username 和 password 元素

username = driver.find_element_by_name('username')
password = driver.find_element_by_name('password')

获取 “继续” 按钮, 此处只返回第一个按钮,也即是 value=”Login” 的按钮

continue = driver.find_element_by_name('continue')
通过 XPath 查找

XPath语言用于定位XML文档中的节点
使用XPath的主要原因之一是当你没有一个合适的id或名称属性时,XPath 能定位到

代码示例:

<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>

通过 XPath 定位元素

# method 1
login_form = driver.find_element_by_xpath("/html/body/form[1]")
# method 2
login_form = driver.find_element_by_xpath("//form[1]")
# method 3
login_form = driver.find_element_by_xpath("//form[@id='loginForm']")

解析:
method 1: 绝对路径(如果 HTML 元素发生改变,将会出错)
method 2: 获取 form 的第一个元素
method 3: 通过元素的属性和值获取元素

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='username']")
“Clear” 按钮查找
clear_button = driver.find_element_by_xpath("//input[@name='continue'][@type='button']")
clear_button = driver.find_element_by_xpath("//form[@id='loginForm']/input[4]")

更多 XPath 使用,请参考
* W3Schools XPath Tutorial
* W3C XPath Recommendation
* XPath Tutorial - with interactive examples.


通过链接文本定位超链接

当我们知道 链接文本的时候,但无法定位标签时,可以使用此方法

代码示例:

<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')
通过便签名获取元素

使用这个当你想找到一个元素通过元素名称

代码示例:

<html>
 <body>
  <h1>Welcome</h1>
  <p>Site content goes here.</p>
</body>
<html>

获取 h1 元素

heading1 = driver.find_element_by_tag_name('h1')
通过类名查找元素

通过class属性的名字找到一个元素

代码示例:

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

获取 p 标签所在的元素

content = driver.find_element_by_class_name('content')
通过CSS选择器定位元素

你想找到一个元素,通过CSS选择器的语法。

代码示例:

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

获取 p 标签所在的元素

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

等待 Waits

现在很多的网页采用 AJAX 技术。当我们加载一个网页时,里面的元素在不同的时间段加载,这使定位元素变得很困难。

使用 Waits , 我们可以消除这个问题。使用 Waits, 可以等到元素加载完毕后使用元素查找功能。

Selenium Webdriver 提供了两种类型的 等待: 隐式等待(implicit)显式等待(explicit)

显式等待(Explicit Waits)

显式等待是在等待某个条件进一步发生之前定义的代码操作
最极端的做法就是使用 time.sleep()
这里提供了一些方便的方法,只需要等待必需的,WebDriverWait结合ExpectedCondition是可以实现这一种方式

代码示例:

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

driver = webdriver.Chrome()
driver.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

这里将等待10秒钟,如果在10秒内找不到元素,就报超时 TimeoutException 异常

下面是一些内置的等待条件,你可以直接调用这些条件,而不用自己写某些等待条件了
* title_is
* title_contains
* presence_of_element_located
* visibility_of_element_located
* visibility_of
* presence_of_all_elements_located
* text_to_be_present_in_element
* text_to_be_present_in_element_value
* frame_to_be_available_and_switch_to_it
* invisibility_of_element_located
* element_to_be_clickable
* staleness_of
* element_to_be_selected
* element_located_to_be_selected
* element_selection_state_to_be
* element_located_selection_state_to_be
* alert_is_present

代码使用示例:

from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))

隐式等待(Implicit Waits)

隐式等待比较简单,就是简单地设置一个等待时间,单位为秒
当然如果不设置,默认等待时间为0

代码示例:

from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值