python_new
  • Introduction
  • First Chapter
  • 一、python基础
    • 1.1 常识
      • sys
    • 1.2 基础语法(1)
    • 1.2 基础语法(2)
    • 1.3 常见问题求解
    • 1.4 算法
  • 二、爬虫
    • urllib库(1)
      • urllib库(2)
    • requests模块(1)
      • requests模块(2)
    • 2.1 爬虫基础(3)HTTP原理
    • 2.1 爬虫基础(4)会话和Cookies
    • 2.1 爬虫基础(5)数据存储
      • Mysql存储
      • MongoDB存储
      • Redis存储
    • 2.3 正则表达式
    • 2.4 解析库lxml
      • BeautifulSoup
      • pyquery(1)
      • pyquery(2)
    • 2.5 selenium(1)
    • 2.5 seleium(2)
    • 2.6 Json
    • 2.7 scrapy
      • scrapy(2)
    • 2.9 异步加载
    • 2.6 Splash
  • ORM框架
    • SQLAlchemy
  • Django
    • 1、初阶(一)
    • 初学:投票教程(一)
    • 初学:投票教程(二)
    • 初学:投票教程(三)
    • 初学:投票教程(总结)
    • 模型(一)
    • 模型(二)
    • 视图(一)
    • 视图(二)
    • 模板(一)
    • django实际使用笔记
  • 面试题收集总结
    • 数据结构原理
    • 算法篇
      • 排序
    • 题目篇
  • python数据分析
    • 基础了解(一)
    • 基础了解(二)
    • 基础了解(三)
  • 多线程
  • 深度学习
    • 疑问
  • keras(一)
  • 神经网络
  • 图像识别
  • Docker
    • 一、基础了解
Powered by GitBook
On this page

Was this helpful?

  1. 二、爬虫

2.5 selenium(1)

Previouspyquery(2)Next2.5 seleium(2)

Last updated 6 years ago

Was this helpful?

1、分析代码报错原因,

2、增加对于官方文档的了解,节点交互,动作链等功能的补充

一、介绍

Ajax加载其实是JavaScript动态渲染页面的一种情形,通过直接分析Ajax,我们仍然可以借助requests或urllib来实现数据爬取。

不过JavaScript动态渲染的页面不止Ajax这一种。比如中国青年网(详见

Selenium是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(selenium remote contol)和测试的并行处理(selenium grid)。Selenium的核心selenium core基于JsUnit,完全有JavaScript编写,因此可以用于任何支持JavaScript的浏览器。

为了解决这些问题,我们可以直接使用模拟浏览器运行的方式来实现,这样就可以做到在浏览器中看到是什么样,抓取的源码就是什么样,也就是可见即可爬。这样我们就不用再去管网页内部的JavaScript用了什么算法渲染页面,不用管网页后台的Ajax接口到底有哪些参数。

Python提供了许多模拟浏览器运行的库,如Selenium、Splash、PyV8、Ghost等。

Selenium可以模拟真实浏览器,自动化测试工具(这是什么?),支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。对于一些JavaScript动态渲染的页面来说,此种抓取方式非常有效。

二、基本使用

1、演示

在爬虫中,主要使用的是selenium的webdriver

from selenium import webdriver

help(webdriver)            # 节选部分回复结果,显示了可支持的浏览器类型
PACKAGE CONTENTS
    android (package)
    blackberry (package)
    chrome (package)
    common (package)
    edge (package)
    firefox (package)
    ie (package)
    opera (package)
    phantomjs (package)
    remote (package)
    safari (package)
    support (package)
    webkitgtk (package)

示例

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

browser = webdriver.Chrome()
try:
    browser.get('https://www.baidu.com')
    input = browser.find_element_by_id('kw')
    input.send_keys('Python')
    input.send_keys(Keys.ENTER)
    wait = WebDriverWait(browser, 10)
    wait.until(EC.presence_of_element_located((By.ID, 'content_left')))
    print(browser.current_url)
    print(browser.get_cookies())
    print(browser.page_source)
finally:
    browser.close()
# 我Kao,真厉害!

输出结果过长(节选)

https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=Python&rsv_pq=c94d0df9000a72d0&rsv_t=07099xvun1ZmC0bf6eQvygJ43IUTTUOl5FCJVPgwG2YREs70GplJjH2F%2BCQ&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug2=0&inputT=87&rsv_sug4=87
[{'secure': False, 'value': 'B490B5EBF6F3CD402E515D22BCDA1598', 'domain': '.baidu.com', 'path': '/', 'httpOnly': False, 'name': 'BDORZ', 'expiry': 1491688071.707553}, {'secure': False, 'value': '22473_1441_21084_17001', 'domain': '.baidu.com', 'path': '/', 'httpOnly': False, 'name': 'H_PS_PSSID'}, {'secure': False, 'value': '12883875381399993259_00_0_I_R_2_0303_C02F_N_I_I_0', 'domain': '.www.baidu.com', 'path': '/', 'httpOnly': False, 'name': '__bsi', 'expiry': 1491601676.69722}]
<!DOCTYPE html><!--STATUS OK-->...</html>

源代码过长,在此省略。可以看到,我们得到的当前URL、Cookies和源代码都是浏览器中的真实内容。 所以说,如果用Selenium来驱动浏览器加载网页的话,就可以直接拿到JavaScript渲染的结果了,不用担心使用的是什么加密系统。(那缺点呢?)

2、声明浏览器对象

from selenium import webdriver

browser = webdriver.Chrome()      # 调用谷歌浏览器,电脑需要安装Chromedriver
browser = webdriver.Firefox()     # 调用火狐浏览器,电脑需要安装Geckodriver
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()
# 提示:
# 将下载好的chromedriver.exe放置到环境变量路径下,方式是打开PATH,编辑,把python/script加入变量
# 然后把上面的文件放置在Script的文件夹中,运行exe后即可。

方法(*为重要的)

browser.add_cookie(self, cookie_dict) # 给当前会话添加cookies
browser.back()    # 在浏览历史中向后一步
browser.close()   # 关闭当前的窗口
browser.create_web_element(self, element_id) # 创建一个web元素,并有一个特定的element_id
browser.delete_all_cookies(self) # 删除会话中所有的cookies
browser.delete_cookies(self, name)# 删除一个给定名字的会话
browser.execute(self, driver_commmand, params = None) # 用command.CommandExecutor执行一个输入的命令,参数是若执行命令需要时输入的字典
browser.execute_async_script(self, script, *args) # 在当前窗口或框架下执行异步js程序
*browser.execute_script(self, script, *args) # 在当前窗口或框架下执行异步js程序
browser.file_detecor_context(self, file_detector_class, *args, **kargs) # 文件探测器?
browser.forward(self) # 在浏览历史中向前一步
browser.fullscreen_windos(self) # 全屏
*browser.get(self, url)
browser.get_cookies(self)
browser.get_log(self, log_type) # 得到日志
*browser.get_screenshot_as_base64(self) # 得到当前窗口的截图,以base64编码字符串格式输出,是HTML中嵌入式图像
browser.get_screenshot_as_file(self, filename) # 保存截图为png文件,
browser.get_screenshot_as_png(self) # 保存截图为二进制数据     
browser.get_window_position(self, windowHandle='current') # 得到窗口的位置,返回x,y的坐标
browser.page_source  # 得到当前网页的源码,是加载完全后的源码,如新垣结衣吧的例子

太多了,未完待续。。。

3、访问页面

我们可以用get()方法来请求网页,参数传入链接URL即可。比如,这里用get()方法访问淘宝,然后打印出源代码,

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('http://www.baidu.com')
print(browser.page_source)
browser.close()
#试运行的结果报错,ERROR:platform_sensor_reader_win.cc(242)] NOT IMPLEMENTED

运行后发现,弹出了Chrome浏览器并且自动访问了淘宝,然后控制台输出了淘宝页面的源代码,随后浏览器关闭。(错误原因?)

4、查找节点

Selenium可以驱动浏览器完成各种操作,比如填充表单、模拟点击等。比如,我们想要完成向某个输入框输入文字的操作,总需要知道这个输入框在哪里吧?而Selenium提供了一系列查找节点的方法,我们可以用这些方法来获取想要的节点,以便下一步执行一些动作或者提取信息。

4.1 单个节点

比如,想要从淘宝页面中提取搜索框这个节点,首先要观察它的源代码

可以发现,它的id是q,name也是q。此外,还有许多其他属性,此时我们就可以用多种方式获取它了。比如,find_element_by_name()是根据name值获取,find_element_by_id()是根据id获取。另外,还有根据XPath、CSS选择器等获取的方式。

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://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, input_second, input_third)
browser.close()
# 依然有242的错误

但输出结果正常

<selenium.webdriver.remote.webelement.WebElement (session="f9cdefaac0506acfb42590bfa71c06ec", element="0.3473649581666991-1")> 
<selenium.webdriver.remote.webelement.WebElement (session="f9cdefaac0506acfb42590bfa71c06ec", element="0.3473649581666991-1")>
<selenium.webdriver.remote.webelement.WebElement (session="f9cdefaac0506acfb42590bfa71c06ec", element="0.3473649581666991-1")>

常用的查找元素的方法,注意只会返回符合条件的第一个元素

find_element_by_name
find_element_by_id
find_element_by_xpath
find_element_by_link_text
find_element_by_paritial_link_text  # 这是什么?
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
  • 另外,Selenium还提供了通用方法find_element(),它需要传入两个参数:查找方式By和值。实际上,它就是find_element_by_id()这种方法的通用函数版本,比如find_element_by_id(id)就等价于find_element(By.ID, id),二者得到的结果完全一致。

from selenium import webdriver
from selenium.webdriver.common.by import By

browser = webdriver.Chrome()
browser.get("http://www.taobao.com")
input_first = browser.find_element(By.ID,"q")
print(input_first)
browser.close()

4.2 多个节点

如果查找的目标在网页中只有一个,那么完全可以用find_element()方法。但如果有多个节点,再用find_element()方法查找,就只能得到第一个节点了。如果要查找所有满足条件的节点,需要用find_elements()这样的方法。

比如,要查找淘宝左侧导航条的所有条目,

from selenium import webdriver

browser = webdriver.Chrome()
browser.get("http://www.taobao.com")
lis = browser.find_elements_by_css_selector('.service-bd li')
print(lis)
browser.close()

结果(节选)

[<selenium.webdriver.remote.webelement.WebElement (session="c26290835d4457ebf7d96bfab3740d19", element="0.09221044033125603-1")>, <selenium.webdriver.remote.webelement.WebElement (session="c26290835d4457ebf7d96bfab3740d19", element="0.09221044033125603-2")>, <selenium.webdriver.remote.webelement.WebElement (session="c26290835d4457ebf7d96bfab3740d19", element="0.09221044033125603-3")>...<selenium.webdriver.remote.webelement.WebElement (session="c26290835d4457ebf7d96bfab3740d19", element="0.09221044033125603-16")>]

可以看到,得到的内容变成了列表类型,列表中的每个节点都是WebElement类型。 也就是说,如果我们用find_element()方法,只能获取匹配的第一个节点,结果是WebElement类型。如果用find_elements()方法,则结果是列表类型,列表中的每个节点是WebElement类型。

这里列出所有获取多个节点的方法:

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

当然,我们也可以直接用find_elements()方法来选择,

lis = browser.find_elements(By.CSS_SELECTOR, '.service-bd li')

5、节点交互操作

Selenium可以驱动浏览器来执行一些操作,也就是说可以让浏览器模拟执行一些动作。比较常见的用法有:输入文字时用send_keys()方法,清空文字时用clear()方法,点击按钮时用click()方法。

下面以输入查找信息为例

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("ipone")                 
time.sleep(1)        
input_str.clear()                           
input_str.send_keys("MacBook")          
button = browser.find_element_by_class_name('btn-search') #还可以点按钮!!?厉害,我要试试
button.click()
# 可以执行,但跳出了更多的错误

这里首先驱动浏览器打开淘宝,然后用find_element_by_id()方法获取输入框,然后用send_keys()方法输入iPhone文字,等待一秒后用clear()方法清空输入框,再次调用send_keys()方法输入iPad文字,之后再用find_element_by_class_name()方法获取搜索按钮,最后调用click()方法完成搜索动作。

6、动作链

在上面的实例中,一些交互动作都是针对某个节点执行的。比如,对于输入框,我们就调用它的输入文字和清空文字方法;对于按钮,就调用它的点击方法。其实,还有另外一些操作,它们没有特定的执行对象,比如鼠标拖曳、键盘按键等,这些动作用另一种方式来执行,那就是动作链。

比如,现在实现一个节点的拖曳操作,将某个节点从一处拖曳到另外一处,可以这样实现:

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()
# 正常运行没有任何报错!

首先,打开网页中的一个拖曳实例,然后依次选中要拖曳的节点和拖曳到的目标节点,接着声明ActionChains对象并将其赋值为actions变量,然后通过调用actions变量的drag_and_drop()方法,再调用perform()方法执行动作,此时就完成了拖曳操作

方法

click(on_element=None)

7、执行JavaScript

对于某些操作,Selenium API并没有提供。比如,下拉进度条,它可以直接模拟运行JavaScript,此时使用execute_script()方法即可实现,

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')
# 也没有报错

这里就利用execute_script()方法将进度条下拉到最底部,然后弹出alert提示框。所以说有了这个方法,基本上API没有提供的所有功能都可以用执行JavaScript的方式来实现了。

这里实际上是执行一段js代码,也就是说,你可以自己编辑一段js代码来实现某个操作,然后由execute_script命令来执行。

更多的操作可以参见官方文档的交互动作介绍:

更多的动作链操作可以参考官方文档:

http://news.youth.cn/gn/),它的分页部分是由JavaScript生成的,并非原始HTML代码,这其中并不包含Ajax请求。比如ECharts的官方实例(详见http://echarts.baidu.com/demo.html#bar-negative),其图形都是经过JavaScript计算之后生成的。再有淘宝这种页面,它即使是Ajax获取的数据,但是其Ajax接口含有很多加密参数,我们难以直接找出其规律,也很难直接分析Ajax来抓取。
http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement
http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains。