天天看点

selenium模拟浏览器&PhantomJS

注意:最新版本的selenium停止对PhantomJS的支持(可以使用谷歌&火狐的无头浏览器),如果还想用PhantomJS,需要对selenium降级

卸载最新版本:pip3 uninstall selenium

安装老版本:pip3 install selenium==3.8.0

Python网络爬虫中最麻烦的不是那些需要登录才能获取数据的网站,而是那些通过JavaScript获取数据的网站。python对javascript的支持不太好,所以就需要模拟浏览器。这个模拟浏览器跟Mechanize模块稍有不同,Mechanize模块并不支持javascript,所以这里需要一款可以模拟真实浏览器的模块---Selenium模块

浏览器选择

在编写Python网络爬虫时,主要用到Selenium的Webdriver, Selenium的Webdriver不可能支持所有的浏览器,也没有必要支持所有浏览器

webdriver支持列表

查看模块的功能,最简单也是最方便的方法就是直接使用help命令

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)

在上面列表中, android和blackberry是移动端的浏览器,移动端和PC端两码事,可以先忽略,剩下的有谷歌,ie,火狐,opera等等,而PhantomJS可能很多人没有听说过

PhantomJS是一个基于webkit的服务端JavaScriptAPI,它全面支持web而不需浏览器支持,其快速,原生支持各种web标准:DOM处理,CSS选择器,JSON,Canvas和SVG。PhantomJS可以用于页面自动化,网络监测,网页截屏,以及无界面测试等。事实上,在爬JavaScript才能返回数据的网站时,没有比Selenium和PhantomJS更适合的组合了

windows下安装PhantomJS

下载地址:http://phantomjs.org/download.html

进入下载页面后,选择windows版本的Phantomjs下载,如果是其它系统,对应下载版本安装就好

selenium模拟浏览器&PhantomJS

下载完成后,解压压缩包,直接将解压后的Phantomjs.exe复制到python的目录中就可以了,如下图

selenium模拟浏览器&PhantomJS

在python环境中测试一下,如下

#!/usr/bin/env python
# coding: utf-8


from selenium import webdriver
driver = webdriver.PhantomJS()           

复制

Selenium  &  PhantomJS抓取数据

Selenium和PhantomJS配合,可以模拟浏览器获取包括JavaScript的数据,现在不单要获取网站数据,还需要过滤出"有效数据"才行,Selenium本身就带有一套自己的定位过滤函数,它可以很方便地从网站返回的数据中过滤出所需的“有效数据”.

获取百度搜索结果

鉴于Selenium.Webdriver的help文件太大,分屏显示又不太方便,干脆将帮助文件保存到文件中慢慢查看,执行命令

#!/usr/bin/env python
# coding: utf-8

import sys
from selenium import webdriver

browser = webdriver.PhantomJS()
out = sys.stdout
sys.stdout = open('browserHelp.txt', 'w')
help(browser)
sys.stdout.close()
sys.stdout = out
browser.quit()           

复制

运行截图

selenium模拟浏览器&PhantomJS

想获取"有效信息",第一步当然是网站获取返回数据,第二步就是定位"有效数据?imageView2/2/w/1620"的位置,第三步就是从定位中获取“有效数据”.

以百度搜索为例,使用百度搜索"Python Selenium",并保存第一页搜索结果的标题和链接。从服务器返回数据,由PhantomJS负责,获取返回的数据用Selenium.Webdriver自带的方法page_source,例如:

from selenium import webdriver
URL = 'https://www.baidu.com'
browser = webdriver.PhantomJS()
browser.get(URL)
html = browser.page_source
print(html)           

复制

运行结果:

selenium模拟浏览器&PhantomJS

第二种方法:直接用selenium&PhantomJS打开百度的主页,然后模拟搜索关键字。直接从Selenium&PhantomJS中返回数据,使用第二种方法,可以很清楚地看到Selenium&PhantomJS获取数据的过程

执行代码:

from selenium import webdriver
browser = webdriver.PhantomJS()
browser.get('https://www.baidu.com')
browser.implicitly_wait(10)
print(browser.page_source)           

复制

执行结果

selenium模拟浏览器&PhantomJS

PS:关注一个函数implicitly_wait()。使用Selenium&PhantomJS最大的优势是支持JavaScript,而PhantomJS浏览器解释JavaScript是需要时间的,这个时间是多少并不好确定,当然可以用time.sleep()强行休眠等待一个固定时间.但是这个时间定长了,浪费时间;定短了,又没能完整解释JavaScript,而implicitly_wait函数则完美地解决了这个问题,给implicitly_wait一个时间参数,implicitly_wait会智能等待,只要解释完成了就进行下一步,完全没有浪费时间

下面从网页的框架中选取表单框,并输入搜索的关键词,完成搜索的过程

获取搜索结果

Selenium本身给出了18个函数,总共有8种方法从返回数据中定位“有效数据”位置,这些函数分别是:

find_element(self, by=By.ID, value=None)
find_element_by_class_name(self, name)
find_element_by_css_selector(self, css_selector)
find_element_by_id(self, id_)
find_element_by_link_text(self, link_text)
find_element_by_name(self, name)
find_element_by_partial_link_text(self, link_text)
find_element_by_tag_name(self, name)
find_element_by_xpath(self, xpath)

find_elements(self, by=By.ID, value=None)
find_elements_by_class_name(self, name)
find_elements_by_css_selector(self, css_selector)
find_elements_by_id(self, id_)
find_elements_by_link_text(self, text)
find_elements_by_name(self, name)
find_elements_by_partial_link_text(self, link_text)
find_elements_by_tag_name(self, name)
find_elements_by_xpath(self, xpath)           

复制

这18个函数前面的9个带element的函数将返回第一个符合参数要求的element,后面9个带elements的函数将返回一个列表,列表中包含所有符合参数要求的element.

上面函数中,不带by的函数,配合参数可以替代其他的函数.例如:find_element(by='id',value='abc')就可以替代find_element_by_id('abc')。同理find_elements(by='id',value='abc')也可以代替find_elements_by_id('abc').

这8种定位方法组合应用,灵活配合,可以获取定位数据中的任意位置。

在使用浏览器请求数据时,用find_element_by_name、find_element_by_class_name、find_element_by_id、find_element_by_tag_name会比较方便。一般的表单,元素都会有name,class,id,这样定位会比较方便。如果仅仅是为了获取“有效数据”的位置,那还是find_element_by_xpath和find_element_by_css比较方便,强烈推荐find_element_by_xpath,真的是超级方便

先定位文本框,输入搜索关键词并向服务器发送数据,在浏览器中打开百度,定位输入框查看代码,如下图:

selenium模拟浏览器&PhantomJS

从上图中可以看出文本框里有class,name,id属性,可以使用find_element_by_class_name、find_element_by_id、find_element_by_name来定位。执行命令:

testElement = browser.find_element_by_class_name('s_ipt')
testElement = browser.find_element_by_name('wd')
testElement = browser.find_element_by_id('kw')   # 这三个任选其一都可以定位到
testElement.clear()
testElement.send_keys('Python selenium')  # 在输入框中输入关键字           

复制

回到浏览器中,定位submit按钮,如下

selenium模拟浏览器&PhantomJS

从上图中看出,submit按键有id,class属性,可以用find_element_by_class_name和find_element_by_id来定位,执行命令:

submitElement = browser.find_element_by_class_name('bg s_btn btnhover')
submitElement = browser.find_element_by_id('su')  # 这两个任选一个
submitElement.click()
print(browser.title)           

复制

代码:

from selenium import webdriver
browser = webdriver.PhantomJS()
browser.get('https://www.baidu.com')
browser.implicitly_wait(10)
testElement = browser.find_element_by_class_name('s_ipt')
testElement.send_keys('Python selenium')
submitElement = browser.find_element_by_id('su')
submitElement.click()
print(browser.title)           

复制

运行结果:

Python selenium_百度搜索

此时browser已经获取到了搜索的结果了

获取有效数据位置

获取“有效数据”位置或者说是element,先定位搜索结果的标题和链接。在浏览器打开百度搜索Python seleninum,在搜索结果页面中查看源代码

selenium模拟浏览器&PhantomJS

在这里发现了比较特别的属性class="c-tools?imageView2/2/w/1620"

selenium模拟浏览器&PhantomJS

发现共有10个结果,可以用find_elements_by_class_name定位所有的搜索结果了,执行命令

resultElements = browser.find_elements_by_class_name("result c-container ")
print(len(resultElements))           

复制

从位置中获取有效数据

有效数据的位置确定后,如何从位置中过滤出有效的数据呢?一般就是获取element的文字或者获取Element中某个属性值。

Selenium有自己独特的方法:

import json
resultElements = browser.find_elements_by_class_name("c-tools")
print(len(resultElements))
value = resultElements[0].get_attribute('data-tools')
valueDic = json.loads(value)
print(valueDic.get('title'))
print(valueDic.get('url'))           

复制

执行结果

10

Selenium with Python — Selenium Python Bindings 2 ...

http://www.baidu.com/link?url=CSU8JkNWTcCvLT0miYp8_frqdg7UTLGNjYJyv5cbc71oTDC_ZZNxUIbfu5bZa9Xu

完整代码如下:

遍历resultElements列表,可以获取所有的搜索结果的title和url,已将Selenium&PhantomJS爬虫运行了一遍

from selenium import webdriver
browser = webdriver.PhantomJS()
browser.get('https://www.baidu.com')
browser.implicitly_wait(10)
testElement = browser.find_element_by_id('kw')
testElement.send_keys('Python selenium')
submitElement = browser.find_element_by_id('su')
submitElement.click()

import json
resultElements = browser.find_elements_by_class_name("c-tools")
for i in resultElements:
    value = i.get_attribute('data-tools')
    valueDic = json.loads(value)
    print(valueDic.get('title'))
    print(valueDic.get('url'))           

复制

运行结果:

selenium模拟浏览器&PhantomJS