menu Chancel's blog
rss_feed
Chancel's blog
有善始者实繁,能克终者盖寡。

Python使用Browsermob实践

作者:Chancel Yang, 创建:2020-04-01, 字数:4737, 已阅:795, 最后更新:2024-03-10

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安装

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

Bash
sudo apt update

我的初始系统环境如下

  • Python >= 3.6.2
  • pip3

3. 部署

3.1. 安装Chrome/ChromeDriver

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

TEXT
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 Version Chrome Version
78.0.3904.11 78
77.0.3865.40 77
77.0.3865.10 77
76.0.3809.126 76
76.0.3809.68 76
76.0.3809.25 76
76.0.3809.12 76
75.0.3770.90 75
75.0.3770.8 75
74.0.3729.6 74
73.0.3683.68 73
72.0.3626.69 72

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

3.2. 安装Browsermob

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

Bash
sudo apt-get install openjdk-8-jdk

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

Bash
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能够正常运行,确保没有错误输出(如果地址占用属于正常情况无需理会)

TEXT
./browsermob-proxy

启动browsermob的Python代码示例

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

Python
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()

[[replyMessage== null?"发表评论":"发表评论 @ " + replyMessage.m_author]]

account_circle
email
web_asset
textsms

评论列表([[messageResponse.total]])

还没有可以显示的留言...
[[messageItem.m_author]] [[messageItem.m_author]]
[[messageItem.create_time]]
[[getEnviron(messageItem.m_environ)]]
[[subMessage.m_author]] [[subMessage.m_author]] @ [[subMessage.parent_message.m_author]] [[subMessage.parent_message.m_author]]
[[subMessage.create_time]]
[[getEnviron(messageItem.m_environ)]]