十四、Selenium入门

1、Selenium

  Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器)。

  Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。

  Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是有时候需要让它内嵌在代码中运行,可以用一个叫 PhantomJS 的工具代替真实的浏览器。

  安装:`pip install selenium`

  selenium官方文档:https://selenium-python.readthedocs.io/index.html

2、PhantomJS

  PhantomJs是一个基于webkit的"无界面"(headless)浏览器,它会把网站加载到内存并执行页面上的javascript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。

  把Selenium和PhantomJS结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理JavaScrip、Cookie、headers,以及任何我们真实用户需要做的事情。

  安装:`sudo apt-get install phantomjs`

  PhantomJS官方文档:https://phantomjs.org/documentation/

  不过现在最新版的selenium不再支持了,可以选择Chrome。

3、快速入门

  selenium库里有个叫webdriver的API,webdriver类似于可以加载网站的浏览器,它类似BeautifulSoup或其他Selector对象,用来查找页面元素,与页面上的元素进行交互(发送文本,点击等),以及执行其他动作来运运行网络爬虫。

  (1)获取id标签的文本内容:driver.find_element_by_id("id_name").text

  (2)获取标题:driver.title

  (3)生成当前页面快照并保存:driver.save_screenshot("filename.png")

  (4)id="kw"用来定位输入框,输入字符串:driver.find_element_by_id("kw").send_keys("爬虫")

  (5)id="su"用来定位搜索按钮,click()是模拟点击:driver.find_element_by_id("su").click()

  (6)获取网页渲染后的源代码:driver.page_source

  (7)获取当前页面Cookie:driver.get_cookies()

  (8)ctrl+a全选定位部分内容:driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')

  (9)ctrl+x剪切定位部分内容:driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')

  (10)模拟enter回车键:driver.find_element_by_id("su").send_keys(Keys.RETURN)

  (11)清楚选定部分的内容:driver.find_element_by_id("kw").clear()

  (12)获取当前url:driver.current_url

  (13)关闭当前页面,如果只有一个页面,会关闭浏览器:driver.close()

  (14)关闭浏览器:driver.quit()

# 导入webdriver
from selenium import webdriver
# 调用键盘按钮操作时需要引入的keys包
from selenium.webdriver.common.keys import Keys

import time

# 调用环境变量指定的PhantomJS浏览器创建浏览器对象
driver = webdriver.Chrome()

# 如果没有在环境变量指定chromedriver位置,则需要引用可执行文件
#driver = webdriver.Chrome(executable_path="/usr/bin/chromedriver")

# get方法会一直等到页面被完全加载,然后才会继续程序,通常测试会选择time.sleep(2)
driver.get("https://www.baidu.com")

# 获取页面中 为head_wrapper的id标签的文本内容
# data = driver.find_element_by_id("head_wrapper").text
# 打印获取到的数据
# print(data)
"""
百度热榜
�换一换
1同一个世界同一个妈
4直播:相信未来义演再开唱
2奥巴马批评特朗普疫情应对
5强基计划直播
3吉林一女洗衣工确诊后再传11人
6今天,最想对妈妈说的话
"""

# 打印页面标题
# print(driver.title)
# 百度一下,你就知道

# 生成当前页面快照并保存
#driver.save_screenshot('baidu.png')


# # id="kw"是百度搜索输入框,输入字符串“爬虫”
# driver.find_element_by_id("kw").send_keys("爬虫")

# # id="su"是百度搜索按钮,click是模拟点击
# driver.find_element_by_id("su").click()

# # 延时2s,保证获取到实际的内容
# time.sleep(2)
# # 获取新页面的快照
# driver.save_screenshot("爬虫.png")


# 打印网页渲染后的源代码
# print(driver.page_source)


# 获取当前页面cookie
# print(driver.get_cookies())


# # 输入框重新输入内容
driver.find_element_by_id("kw").send_keys("python")
# driver.find_element_by_id("su").click()

# ctrl+a全选输入框内容
# driver.find_element_by_id('kw').send_keys(Keys.CONTROL, "a")
# ctrl+x剪切输入框内容
# driver.find_element_by_id("kw").send_keys(Keys.CONTROL, "x")

# 模拟enter回车键
driver.find_element_by_id("su").send_keys(Keys.RETURN)

# 清空输入款内容
# driver.find_element_by_id('kw').clear()

# 获取当前url
print(driver.current_url)
"""
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=python&fenlei=256&rsv_pq=f56af1be000010cf&rsv_t=682eH4uSAFnDdURF0mggnYJfY6t28dxq2Irnjwx%2F4vQhRZrNLQQ1UnwAVVo&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=6&rsv_btype=i&inputT=132&rsv_sug4=132
"""

# 关闭当前页面,如果只有一个页面,会关闭浏览器
time.sleep(3)
driver.close()

# 关闭浏览器
# driver.quit()

4、页面操作

  selenium的webdriver提供了各种方法来寻找元素

  假设有一个表单输入框:

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

  那么通过find_element_by_*等方法可以找到元素:

# 获取id标签值
element = driver.find_element_by_id("passwd-id")

# 获取name标签值
element = driver.find_element_by_name("user-name")

# 获取标签名值
element = driver.find_element_by_tag_name("input")

# 通过XPath来匹配
element = driver.find_element_by_xpath("//input[@id='passwd-id']")

5、定位UI元素(WebElements)

  5.1 关于元素的选取,有如下的API单个元素选取:

    `find_elements_by_id`

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

  5.2 selenium.webdriver.common.by下有一个By,可以结合find_element()一起使用

    导入By`from selenium.webdriver.common.by import By`

    (1)By ID

<div id = "cool" > ... < /div >

element = driver.find_element_by_id("cool")
------------------------ or -------------------------
element = driver.find_element(by=By.ID,value="cool")

    (2)By Class Name

<div class = "cheese" > <span > Cheddar < /span > </div >
<div class = "cheese" > <span > Gouda < /span > </div >

element = driver.find_elements_by_class_name("cool")
------------------------ or -------------------------
element = driver.find_elements(by=By.CLASS_NAME,value="cheese")

    (3)By Link Text   

<a href = "http://www.google.com/search?q=cheese" > cheese < /a >

element = driver.find_elements_by_link_text("cool")
------------------------ or -------------------------
element = driver.find_elements(by=By.LINK_TEXT,value="cheese")

    (4)By Partial Link Text

<a href = "http://www.google.com/search?q=cheese" >search for  cheese < /a >

element = driver.find_elements_by_partial_link_text("cool")
------------------------ or -------------------------
element = driver.find_elements(by=By.PARTIAL_LINK_TEXT,value="cheese")

    (5)By CSS

<div id = "food" > <span class = "dairy" > milk < /span > <span class = "dairy aged" > cheese < /span > </div >

element = driver.find_elements_by_css_selector("#food span.dairy.aged")
------------------------ or -------------------------
element = driver.find_elements(by=By.CSS_SELECTOR, "#food span.dairy.aged")

    (6)By XPath

<input type = "text" name = "example" / >
<INPUT type = "text" name = "other" / >

element = driver.find_elements_by_xpath("//input")
------------------------ or -------------------------
element = driver.find_elements(by=By.XPATH, "//input")      

    (7)By Tag Name

<iframe src = "..." > </iframe >

element = driver.find_elements_by_tag_name("iframe")
------------------------ or -------------------------
element = driver.find_elements(by=By.TAG_NAME, "iframe")

    (8)By Name

<input name = "cheese" type = "text"/>

element = driver.find_elements_by_name("cheese")
------------------------ or -------------------------
element = driver.find_elements(by=By.NAME, "cheese")

6、鼠标动作链

  通过导入ActionChains类,来实现在页面上模拟一些鼠标操作,比如双击、右击、拖拽或者按住不动等。

# 导入webdriver
from selenium import webdriver
# 调用键盘按钮操作时需要引入的keys包
from selenium.webdriver.common.keys import Keys
# 导入ActionChains类
from selenium.webdriver import ActionChains
import time

driver = webdriver.Chrome()
driver.get("https://www.baidu.com")

# 鼠标移动到"新闻",`ac`定义了元素的位置
ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]")
ActionChains(driver).move_to_element(ac).perform()
time.sleep(2)
# 鼠标移动到”hao123“
ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[2]")
ActionChains(driver).move_to_element(ac).perform()


# 在ac位置单击
# ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]")
# ActionChains(driver).move_to_element(ac).click(ac).perform()

# 在ac位置双击
# ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]")
# ActionChains(driver).move_to_element(ac).double_click(ac).perform()
# 因为同时在这个地方双击,所以会弹出两个相同的窗口

# 在ac位置右击
# ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]")
# ActionChains(driver).move_to_element(ac).context_click(ac).perform()

# 在ac位置左键单击hold住
# ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]")
# ActionChains(driver).move_to_element(ac).click_and_hold(ac).perform()

# 将ac1拖拽到ac2位置
ac1 = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]")
ac2 = driver.find_element_by_xpath("//div[@id='s-top-left']/a[2]")
ActionChains(driver).drag_and_drop(ac1,ac2).perform()

7、SELECT表单

  碰到<select></select>标签的下拉框,直接点击下拉框中的选项不一定可行。

  Selenium专门提供了Select类来处理下拉框,

# 导入webdriver
from selenium import webdriver
from selenium.webdriver.support.ui import Select
import time

driver = webdriver.Chrome()
driver.get("http://course.hbpu.edu.cn/G2S/ShowSystem/Index.aspx")

# 找到class的选项卡
"""
<select class="left search" onchange="searchChange(this)" style="margin-top:2px;">
    <option value="OrganiseSearch.aspx">组织结构</option>
    <option value="SpecialtySearch.aspx">专业</option>
    <option value="TeacherSearch.aspx">教师</option>
    <option value="CourseSearch.aspx">课程</option>
    <option value="WebsiteSearch.aspx">课程网站</option>
</select>
"""
# 定位后构造选择器
select_ = Select(driver.find_element_by_xpath("//select"))

# 操作select_来选择,可以通过index,value,visible_text
select_.select_by_index(2)
time.sleep(2)
select_.select_by_value("SpecialtySearch.aspx")
time.sleep(2)
select_.select_by_visible_text("课程")
# 状态是”教师“>>>"专业>>>”课程“

  以上是三种选择下拉框的方式,它可以根据索引来选择,可以根据值来选择,可以根据文字来选择。

  说明:(1)index索引从0开始

     (2)value是option标签的一个属性值,并不是显示在下拉框中的值

     (3)visible_text是在option标签文本中的值,是显示在下拉框的值

  如果全部取消选择:`select.deselect_all()`

8、弹窗处理

  当触发了某个事件之后,页面出现了弹窗提示,处理这个提示或者获取提示信息的方法:

  `alert = driver.switch_to_alert()`

9、页面切换

  切换浏览器个页面窗口的方法:`driver.switch_to.window("this is window name")`

  使用window_handles方法来获取每个窗口的操作对象:

  ```

  for    handle    in    driver.window_handles:

    driver.switch_to_window(handle)

  ```

10、页面前进或后退

  操作页面的前进和后退功能:

  ```

  driver.forward()  #前进

  driver.back()  #后退

  ```

11、Cookies

  获取页面每个Cookies值,用法如下:

  ```

  for    cookie    in    driver.get_cookies():

    print("{} -> {}".format(cookie['name'],cookie['value']))

  ```

  删除Cookies,用法如下:

  ```

  # 通过name

  driver.delete_cookie("CookieName")

  # 删除所有

  driver.delete_all_cookies()

  ```

12、页面等待

  现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但是你的代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。

  为了避免这种元素定位困难而且会提高产生 ElementNotVisibleException 的概率。所以 Selenium 提供了两种等待方式,一种是隐式等待,一种是显式等待。

  隐式等待是等待特定的时间,显式等待是指定某一条件直到这个条件成立时继续执行

  12.1 显式等待

    显式等待指定某个条件,然后设置最长等待时间,如果在这个时间还没有找到元素,那么便会抛出异常。

from selenium import webdriver
from selenium.webdriver.common.by import By
# 导入WebDriverWait库,负责循环等待
from selenium.webdriver.support.ui import WebDriverWait
# 导入expected_conditions类,负责条件触发
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
try:
    # 页面一致循环,直到id="myDynamicElement"出现
    element=WebDriverWait(driver,10).until(
        EC.presence_of_element_located((By.ID,"myDynamicElement"))
    )
finally:
    driver.quit()

    如果不写参数,程序默认会0.5s调用一次来查看元素是否已经生成,如果本来元素就是存在,那么会立即返回。

    expected_conditions中内置的等待条件,可以直接调用这些条件,而不用自己写某些等待条件:

    `title_is`

    `title_contains`

    `persence_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-it is Displayed and Enabled`

    `staleness_of`

    `element_to_be_selected`

    `element_located_to_be_selected`

    `element_selection_state_to_be`

    `element_location_selection_state_to_be`

    `alert_is_present`

  12.2 隐式等待

    隐式等待比较简单,就是简单地设置一个等待时间,单位为秒。

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10) #等待10s
driver.get('http://www.baidu.com')
myDynamicElement = driver.find_element_by_id("myDynamicElement")

    如果不设置,则默认等待时间为0。    

原文地址:https://www.cnblogs.com/nuochengze/p/12865227.html