1. 前提

Python作为爬虫利器的编程语言几乎无可挑剔,Selenium更是当之无愧最好之一的爬虫库,至于Browsermob估计听说的人就相对比较少了

Selenium的Wiki介绍

Selenium is a portable framework for testing web applications. Selenium provides a playback tool for authoring functional tests without the need to learn a test scripting language (Selenium IDE). It also provides a test domain-specific language (Selenese) to write tests in a number of popular programming languages, including C#, Groovy, Java, Perl, PHP, Python, Ruby and Scala. The tests can then run against most modern web browsers. Selenium runs on Windows, Linux, and macOS. It is open-source software released under the Apache License 2.0.

Selenium + webdriver 用来模拟用来模拟浏览器请求操作,同样类似的爬虫库还有 Pyppeteer/Requestium/arsenic等等

既然Selenium + webdriver 可以用来模拟用来模拟浏览器操作,为什么还需要Browsermob呢?

因为我们想获取浏览器的Request与Response的话,光靠Selenium办不到,需要引入Browsermob

BrowserMob Proxy allows you to manipulate HTTP requests and responses, capture HTTP content, and export performance data as a HAR file. BMP works well as a standalone proxy server, but it is especially useful when embedded in Selenium tests.

Browsermob可以在Selenium运行时作为独立代理服务器记录HTTP的Request/Response并提供API给Python代码调用,从而获取爬虫时的每一个请求详情

2. 环境

2.1. 先决条件

机器必须安装下面的软件

  • Chrome
  • Python
  • PIP包管理器
  • PIP包 - Selenium
  • JDK1.8(Browsermob依赖于Java JDk)

以及等会直接引入的两个依赖软件

  • ChromeDriver
  • Browsermob

请注意

  1. ChromeDriver依赖于Chrome浏览器,即使是无UI模式运行(大部分服务器都没装GUI界面的)也需要安装Chrome浏览器的
  2. Browsermob是二进制打包下载的,对于Windows他提供BAT文件,但无论什么系统环境都需要安装JDK,否则无法运行二进制文件

2.2. 环境参考

本次搭建采用虚拟机Ubuntu18.04,所有安装均是介于Ubuntu18.04安装

在虚拟安装系统之后,直接升级系统

sudo apt update

我的初始系统环境如下

  • Python >= 3.6.2
  • pip3

3. 部署

3.1. 安装Chrome/ChromeDriver

首先安装Chrome,直接到官网下载DEB包进行安装,可能会缺少部分依赖,请根据依赖情况具体安装即可

cd /tmp/
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb

安装完成后,使用指令 google-chrome –version查询版本

根据显示的版本到ChromeDriver - WebDriver for Chrome下载对应的ChromeDriver版本,下面是简单的版本对应列表

ChromeDriver VersionChrome Version
78.0.3904.1178
77.0.3865.4077
77.0.3865.1077
76.0.3809.12676
76.0.3809.6876
76.0.3809.2576
76.0.3809.1276
75.0.3770.9075
75.0.3770.875
74.0.3729.674
73.0.3683.6873
72.0.3626.6972

下载完成后放到特定位置,这个位置需要后面在代码中指明路径(也可以使用环境变量,自行Google环境变量的设置)

3.2. 安装Browsermob

Browsermob 依赖于Java环境,我们只需要安装JDK就行,所幸Ubuntu安装Java运行环境特别简单

sudo apt-get install openjdk-8-jdk

使用 java -version检查Java环境顺利安装后,安装Browsermob的PIP包

pip install browsermob-proxy

最后我们只需要到lightbody/browsermob-proxy - github的Release中下载Browsermob二进制文件,下载完成之后放到解压指定位置,与ChromeDriver相似的,要在代码中指出该依赖包的位置

4. 运行示例

4.1. Browsermob

假设我的Browsermob二进制文件存放于 /opt/script/script_package/browsermob-proxy-2.1.4/bin/browsermob-proxy

测试Browsermob能够正常运行,确保没有错误输出(如果地址占用属于正常情况无需理会)

./browsermob-proxy

启动browsermob的Python代码示例

from browsermobproxy import Server
options_dict = {'port': 39283}
server = Server(path="./BrowserMobProxy/bin/browsermob-proxy", options=options_dict)
server = Server(path='/opt/script/script_package/browsermob-proxy-2.1.4/bin/browsermob-proxy',)
server.start()
proxy = server.create_proxy()

这样启动之后,我们就开启了一个代理服务器

4.2. Selenium

假设我的ChromeDriver二进制文件存放于 /opt/script/script_package/chromedriver

下面代码用于提取网页中的MP4视频资源

原理是使用Selenium并启动无UI的Chrome访问网页,同时将上一步的Browsermob设置为Chrome的代理

从而抓取Request/Response,从Response中查询MinmeType为MP4的资源,并提取URL

from selenium.webdriver.chrome.options import Options
chrome_options = Options()
# 无头模式
chrome_options.add_argument('--headless')
# 忽略HTTPS证书错误
chrome_options.add_argument('--ignore-certificate-errors')
# 设置Browsermob的代理
chrome_options.add_argument(
    '--proxy-server={0}'.format('http://127.0.0.1:39283'))
# 这里的Proxy是创建Browsermob代理代码中的proxy对象
proxy.new_har("test", options={'captureHeaders': True, 'captureContent': True})
driver = webdriver.Chrome(
    executable_path='/opt/script/script_package/chromedriver', chrome_options=chrome_options)
driver.get('https://www.example.com')
result = proxy.har
for entry in result['log']['entries']:
    _url = entry['request']['url']
    if entry['response']['content']['mimeType'] is not None and 'mp4' in entry['response']['content']['mimeType']:
        print('视频地址:'+_url)
        return _url
driver.quit()