Python爬虫(四)—深入学习Selenium

Posted on 2019-05-29 23:36  走过萧萧路  阅读(142)  评论(0编辑  收藏  举报

前言

以下关于Selenium的内容讲解,强烈推荐深入了解的查看官方文档。

英文版:Selenium、 https://selenium-python.readthedocs.io/

Selenium介绍安装

  • 介绍
    selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium Remote Control)和测试的并行处理(Selenium Grid)。Selenium的核心Selenium Core基于JsUnit,完全由JavaScript编写,因此可以用于任何支持JavaScript的浏览器上。
    selenium可以模拟真实浏览器,自动化测试工具,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。
  • 安装使用 selenium
    virtualenv 来创建隔离的Python环境。
    pip install selenium
  • 选择下载浏览器驱动
    下载以下driver后,放到Python虚拟环境的 Scripts 文件夹下。
浏览器下载地址
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/
  • PhantomJS
    PhantomJS是一个而基于WebKit的服务端JavaScript API,支持Web而不需要浏览器支持,其快速、原生支持各种Web标准:Dom处理,CSS选择器,JSON等等。PhantomJS可以用用于页面自动化、网络监测、网页截屏,以及无界面测试。速度比Selenium快很多,最后进行讲解。

Selenium 的基本使用

  • 声明浏览器对象、访问页面
from selenium import webdriver

browser = webdriver.Chrome()

browser.get("http://www.baidu.com")
print(browser.page_source)
browser.close()
  • 查找单元素
    • 获取方式
      以下通过三种不同的方式去获取响应的元素,第一种是通过id的方式,第二个中是CSS选择器,第三种是xpath选择器,结果都是相同的。
from selenium import webdriver

browser = webdriver.Chrome()

browser.get("http://www.taobao.com")
input_first = browser.find_element_by_id("q")
input_second = browser.find_element_by_css_selector("#q")
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first)
print(input_second)
print(input_third)
browser.close()

CSS选择器、xpath选择器 可以直接采用chrome浏览器的右击复制,如下图:

chrome快捷复制节点.png

  • 查找元素方法
    • find_element_by_name
    • find_element_by_id
    • 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
      以上方法也可以通过By.NAME等进行获取。如以下代码
from selenium import webdriver

from selenium.webdriver.common.by import By

browser = webdriver.Chrome()

browser.get("http://www.taobao.com")

# 匹配的元素的ID
# input_first_By_ID = browser.find_element_by_id('q')
# 以下类似,都有两种方式。
input_first_By_ID = browser.find_element(By.ID, "q")

# 匹配的元素的xpath定位器
input_first_By_XPATH = browser.find_element(By.XPATH, "//*[@id=\"q\"]")

# 匹配的元素的name属性
input_first_By_NAME = browser.find_element(By.NAME, "q")

# 匹配的元素的文本
input_first_LINK_TEXT = browser.find_element(By.LINK_TEXT, "领淘金币抵钱")

# 匹配的元素的标签名称,例如:h1,a,span
input_first_CSS_SELECTOR = browser.find_element(By.CSS_SELECTOR, "#q")

print(input_first_CSS_SELECTOR)
browser.close()
"""
<selenium.webdriver.remote.webelement.WebElement (session="4ee277c466be7248d4c7e078cbf927db", element="0.09114132600392044-1")>
"""
  • 多元素查找
    与以上类似,只不过在以上的方法 find_element_by_css_selector -> find_elements_by_css_selector ,加一个s。

    并且在输出的时候是以list的形式返回,例如以上的输出修改为:
    [<selenium.webdriver.remote.webelement.WebElement (session=“cdbd8f4c90c313c9e94519414365f552”, element=“0.40080093360381364-1”)>]

疑问查看:WebDriver API https://selenium-python.readthedocs.io/api.html

from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome()

url = "http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable"
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
target = browser.find_element_by_css_selector('#droppable')
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()
  • 元素交互操作:输入、清空、点击
    对于获取的元素调用交互方法,主要是元素值的输入、清空、点击等操作。
    以下代码运行为:程序自动打开Chrome浏览器并打开淘宝输入ipad,然后删除,重新输入MakBook pro,并点击搜索。
from selenium import webdriver
import time

browser = webdriver.Chrome()
browser.get("http://www.taobao.com")
input_str = browser.find_element_by_id('q')
input_str.send_keys("ipad")
time.sleep(1)
input_str.clear()
input_str.send_keys("MakBook pro")
button = browser.find_element_by_class_name('btn-search')
button.click()
time.sleep(3)
browser.close()

chromeOptions

chromeOptions 是一个配置 chrome 启动是属性的类。通过这个类,我们可以为chrome配置如下参数(这个部分可以通过selenium源码看到)

  • 添加实验性质的设置参数 add_experimental_option
    代码如下:
# 实例化一个启动参数对象
options = webdriver.ChromeOptions()
# 设置浏览器窗口大小
options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
# 启动浏览器
browser = webdriver.Chrome(chrome_options=chrome_options)

常用的参数如下:

  1. 设置为开发者模式 (‘excludeSwitches’, [‘enable-automation’)
  2. 不加载图片,加快访问速度 (“prefs”, {“profile.managed_default_content_settings.images”: 2})
  3. 模拟手机打开网页 (‘mobileEmulation’, {‘deviceName’: ‘Apple iPhone 4’})
  4. 关闭保存密码提示
options = webdriver.ChromeOptions() 
prefs = {} 
# 设置这两个参数就可以避免密码提示框的弹出
prefs['credentials_enable_service'] = False 
prefs['profile.password_manager_enabled'] = False 
options.add_experimental_option('prefs', prefs) 
browser = webdriver.Chrome(chrome_options=options)
启动参数作用
–user-agent="设置请求头的User-Agent
–window-size=1366,768设置浏览器分辨率(窗口大小)
–headless无界面运行(无窗口)
–start-maximized最大化运行(全屏窗口)
–incognito隐身模式(无痕模式)
–disable-javascript禁用javascript
–disable-infobars禁用浏览器正在被自动化程序控制的提示
  • 添加扩展应用 (add_extension, add_encoded_extension)
  • 设置 chrome 二进制文件位置 (binary_location)
  • selenium源码
    在目录 \env\Lib\site-packages\selenium\webdriver\chrome\optitions.py 下。
class Options(object):
    KEY = "goog:chromeOptions"

    def __init__(self):
        self._binary_location = ''
        self._arguments = []
        self._extension_files = []
        self._extensions = []
        self._experimental_options = {}
        self._debugger_address = None
        self._caps = DesiredCapabilities.CHROME.copy()

执行JavaScript

  • 调用js方法
    下面的例子是通过登录知乎然后通过js翻到页面底部,并弹框提示。
from selenium import webdriver

browser = webdriver.Chrome()
browser.get("http://www.zhihu.com/explore")
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')
  • 获取元素属性、文本值
    可以通过 get_attribute(‘class’) 获取元素的class属性、href属性、文本值等。
from selenium import webdriver

browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo)
print(logo.get_attribute('class'))  # zu-top-link-logo
print(logo.text)  # 知乎
  • 获取ID,位置,标签名
from selenium import webdriver

browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
input = browser.find_element_by_class_name('zu-top-add-question')
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)
"""
0.8051799500933536-1
{'x': 758, 'y': 7}
button
{'height': 32, 'width': 66}
"""

Frame

涉及到切入到frame中以及切出来的问题,常用的是switch_to.from()和switch_to.parent_frame(),如以下代码:

import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)

browser.switch_to.frame('iframeResult')

source = browser.find_element_by_css_selector('#draggable')
print(source)
try:
    logo = browser.find_element_by_class_name('logo')
except NoSuchElementException:
    print('NO LOGO')

browser.switch_to.parent_frame()

logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)

等待 Waits

以下内容基本摘自:https://selenium-python.readthedocs.io/waits.html

  • 显式等待
    WebDriverWait与ExpectedCondition相结合是一种可以实现的方法。EC.presence_of_element_located()是确认元素是否已经出现。
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.Firefox()
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()

在抛出TimeoutException之前等待最多10秒,除非它发现元素在10秒内返回。默认情况下,WebDriverWait每500毫秒调用一次ExpectedCondition,直到它成功返回。对于所有其他ExpectedCondition类型,ExpectedCondition类型的布尔返回true或非null返回值成功返回。

  • 常用的判断条件如下
预期条件目的
title_is标题是某内容
title_contains标题包含某内容
presence_of_element_located元素加载出,传入定位元组,如(By.ID,‘p’)
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_itframe加载并切换
invisibility_of_element_located元素不可见
element_to_be_clickable元素可点击
staleness_of判断一个元素是否仍在DOM,可判断页面是否已经刷新
element_to_be_selected元素可选择,传元素对象
element_located_to_be_selected元素可选择,传入定位元组
element_selection_state_to_be传入元素对象以及状态,相等返回True,否则返回False
element_located_selection_state_to_be传入定位元组以及状态,相等返回True,否则返回False
alert_is_present是否出现Alert
  • 自定义等待条件
    如果以前的便捷方法都不符合您的要求,您还可以创建自定义等待条件。可以使用带有__call__方法的类创建自定义等待条件,该方法在条件不匹配时返回False。示例 : 略…
  • 隐式等待
    到了一定的时间发现元素还没有加载,则继续等待我们指定的时间,如果超过了我们指定的时间还没有加载就会抛出异常,如果没有需要等待的时候就已经加载完毕就会立即执行。
from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(10)
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)

其他操作

  • 浏览器的前进和后退
    • 后退:back()
    • 前进:forward()
import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.get('https://www.python.org/')
browser.back()
time.sleep(1)
browser.forward()
browser.close()
  • cookie操作
    • get_cookies()
    • delete_all_cookes()
    • add_cookie()
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())

browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'zhaofan'})

print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())
  • 选项卡管理
    通过执行js命令实现新开选项卡window.open()
    不同的选项卡是存在列表里browser.window_handles
    通过browser.window_handles[0]就可以操作第一个选项卡
import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.execute_script('window.open()')
print(browser.window_handles)
browser.switch_to_window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(1)
browser.switch_to_window(browser.window_handles[0])
browser.get('https://python.org')
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException

browser = webdriver.Chrome()
try:
    browser.get('https://www.baidu.com')
except TimeoutException:
    print('Time Out')
try:
    browser.find_element_by_id('hello')
except NoSuchElementException:
    print('No Element')
finally:
    browser.close()

selenium 模拟手机

有些操作,需要模拟手机才能继续进行,例如微信的公众号、服务号。直接上代码,模拟手机型号等属性。

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

mobile_emulation = {"deviceName": "Pixel 2 XL",
                    }
options = Options()
options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Chrome(chrome_options=options)
...

PhantomJS

from selenium import webdriver

browser = webdriver.PhantomJS()

browser.get("http://www.baidu.com")
print(browser.page_source)
browser.close()

由于selenium对phantomjs不再支持,因此会警告:UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead

个人博客:Loak 正 - 关注人工智能及互联网的个人博客
文章地址:Python爬虫(四)—深入理解Selenium