在 macOS 下搭建 WebPageTest 私有实例

WebPageTest 最新版本(17.08)的一个新功能,是增加了一个新的支持多平台的 Agent 端:wptagent

The biggest change by far is a new cross-platform agent (wptagent) that supports Linux, Windows, Mac and Android testing. Eventually wptdriver will be deprecated and all testing will be moved to the new agent.

得益于此,我们终于可以在 macOS 系统下搭建 WebPageTest 环境,不用再依赖 Windows 虚拟机了。而且,新的 wptagent 还支持 Android 设备(无需 root)。本文将介绍 macOS 系统下如何搭建 WebPageTest 服务端、测试端,以及如何使用 Android 设备进行测试。

虽然 macOS 自带 Apache 和 PHP,但我还是习惯于自己配置一套新环境,因此以下教程基于非自带 Apache 和 PHP。


安装 brew

brew(又叫 Homebrew)是 macOS 平台最有名的第三方包管理工具。由于 brew 几乎人人必备,因此这里不做过多介绍。没有用过的可以查看官网:https://brew.sh/,里面有中文教程。

安装 Apache 2.4

添加第三方仓库

由于 Apache 不在 brew 官方仓库中,因此需要添加第三方仓库。终端执行:

1
brew tap homebrew/apache

关闭并移除自带 Apache 自动加载脚本

终端执行:

1
2
sudo apachectl stop
sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 2>/dev/null

安装 Apache

终端执行:

1
brew install httpd24 --with-privileged-ports --with-http2

安装需要一段时间,大概1-3分钟,安装后会看到这样的提示:

1
/usr/local/Cellar/httpd24/2.4.27: 212 files, 4.4M, built in 1 minute 45 seconds

这里的路径(此处是/usr/local/Cellar/httpd24/2.4.27)需要记住,如果你的路径与此不同,则下面的操作需要自行修改路径:

1
2
3
4
sudo cp -v /usr/local/Cellar/httpd24/2.4.27/homebrew.mxcl.httpd24.plist /Library/LaunchDaemons
sudo chown -v root:wheel /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist
sudo chmod -v 644 /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist
sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist

配置 Apache

安装后,配置文件在/usr/local/etc/apache2/2.4/httpd.conf下。修改该文件:

  • 174行左右,将#LoadModule rewrite_module libexec/mod_rewrite.so取消注释
  • 185行左右,将User daemon改为User your_user_nameyour_user_name为用户名)
  • 186行左右,将Group daemon改为 Group staff
  • 216行左右,将#ServerName www.example.com:80改为ServerName 0.0.0.0:80
  • 240行左右,将DocumentRoot "/usr/local/var/www/htdocs"改为DocumentRoot "/Users/your_user_name/WebPageTest/www"your_user_name 为用户名,此处路径可自行确定)
  • 241行左右,将<Directory "/usr/local/var/www/htdocs">改为<Directory "/Users/your_user_name/WebPageTest/www">(与上一条的路径一致)
  • 261行左右,将AllowOverride None改为AllowOverride All

启动 Apache

  1. 创建路径/Users/your_user_name/WebPageTest/www
  2. 创建index.html文件,内容随意,如<p>Hello World<p>
  3. 在终端中输入sudo apachectl -k restart重启 Apache 服务
  4. 打开浏览器,输入localhost,显示Hello World(即第2步的index.html)说明 Apache 启动成功

安装 PHP 7

添加第三方仓库

由于 PHP 不在 brew 官方仓库中,因此需要添加第三方仓库。终端执行:

1
brew tap homebrew/php

安装依赖

安装 Xcode 的 Command Line Tool。终端执行:

1
xcode-select --install

根据提示安装即可。

安装 PHP

这里以 PHP 7.1 为例。终端执行:

1
brew install php71 --with-httpd24

安装后建立链接:

1
brew link php71

配置 PHP

安装后,配置文件在/usr/local/etc/php/7.1/php.ini下。修改该文件:

  • 404行左右,将memory_limit = 128M改为memory_limit = 256M
  • 671行左右,将post_max_size = 8M改为post_max_size = 10M
  • 824行左右,将upload_max_filesize = 2M改为upload_max_filesize = 10M

以上修改主要是为了满足 WebPageTest 的推荐配置,可根据实际情况修改。

Apache 支持 PHP

添加 PHP 模块

在 Apache 配置文件/usr/local/etc/apache2/2.4/httpd.conf的175行左右(即一堆#LoadModule xxx后)添加:

1
LoadModule php7_module /usr/local/opt/php71/libexec/apache2/libphp7.so

添加主页 index.php

在 Apache 配置文件/usr/local/etc/apache2/2.4/httpd.conf的273行左右,即:

1
2
3
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>

中,在index.html前添加index.php,即:

1
2
3
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>

添加 PHP 支持

在 Apache 配置文件/usr/local/etc/apache2/2.4/httpd.conf的277行左右(即上一步的位置后面)添加:

1
2
3
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>

测试效果

/Users/your_user_name/WebPageTest/www下创建index.php,代码为:

1
2
3
<?php
phpinfo();
?>

重启 Apache,浏览器访问localhost看到下图即为配置成功:

下载并启动 WebPageTest

WebPageTest GitHub:https://github.com/WPO-Foundation/webpagetest

下载地址:https://github.com/WPO-Foundation/webpagetest/releases

下载最新版本即可,这里以 webpagetest_17.08.zip 为例。

下载后解压,得到wwwagentwptagent等目录,其中www为服务端,agent为 Windows 测试端(本次不使用),wptagent为最新的多平台测试端(也就是本次使用的测试端)。将 wwwwptagent文件夹(前者是服务端,后者是测试端)移动到/Users/your_user_name/WebPageTest下,重启 Apache。打开浏览器,访问localhost/install如下图:

接来下就是根据提示信息安装相关依赖。

安装 WebPageTest 依赖

安装 APC

终端执行:

1
brew install php71-apcu

安装 FFmpeg

终端执行:

1
brew install ffmpeg

如果提示已经安装某个版本,需升级(否则可能导致录视频失败):

1
brew upgrade ffmpeg

安装 ImageMagick

终端执行:

1
brew install imagemagick

如果提示已经安装某个版本,需升级(否则可能导致截图失败):

1
brew upgrade imagemagick

安装 ExifTool

终端执行:

1
brew install exiftool

安装 Python 2.7 及相关依赖包

macOS 已经自带 Python 2.7.10。但由于自带 Python 默认没有 pip,且为了避免影响系统,这里自行安装 Python 2.7。

使用 brew 安装 Python 2.7

1、终端执行:

1
brew install python

2、安装完毕后,执行:

1
python --version

查看版本是否为2.7.14(即新安装的版本是否替代了系统自带版本)。如果还是2.7.10则需要继续以下步骤

3、终端执行:

1
sudo vim /etc/paths

查看/usr/local/bin是否在/usr/bin前面。如果不在,将/usr/local/bin移到/usr/bin前面

4、终端执行:

1
ls -l /usr/local/bin | grep python

查看是否存在 pip 和 python。如果不存在,记录 pip2 和 python2 的软链接路径,执行:

1
2
3
cd /usr/local/bin
ln -s ../Cellar/python/2.7.14/bin/pip2 pip
ln -s ../Cellar/python/2.7.14/bin/python2 python

注意,这里的路径一定要以实际情况(即pip2python2的软链接路径)为准

5、再次执行:

1
python --version

此时版本应该是新安装的版本了。

使用 pip 安装依赖包

终端执行:

1
pip install convert compare Pillow pyssim dateutils dnspython monotonic psutil requests ujson

配置 WebPageTest 服务端

设置配置文件

www/settings目录和www/settings/custom_metrics目录下.sample复制一份,并删除.sample后缀。

由于使用非 macOS 自带 Apache 且路径为用户路径,因此无需对 Installation Check 页面 Filesystem 下的文件夹进行权限修改。

修改 location.ini

此处提供一个例子,以两个测试端为例:测试端1(Test_PC)为 macOS 平台,包括 Chrome 和 Firefox 浏览器;测试端2(Test_Mobile)为 Android 平台,包括 Chrome 浏览器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
; 以下为测试地点,即 WebPageTest 首页 Test Location 中的选项
; key 包括 1、2、3... 和 default
; 1、2、3... 的 value 为对应地点名(不能重复)
; default 的 value 对应默认地点名
[locations]
1=Test_PC
2=Test_Mobile
default=Test_PC

; 以下为测试地点的详情项,locations 中每一个 value 都应该对应这里的一个 section
; key 包括 1、2、3... 和 label、group,label 为该地点的标签名,group 为组信息
; 1、2、3... 的 value 为对应浏览器节点名(不建议直接用浏览器名,以免多个地点的浏览器名重复)
; label 的 value 随意填写,只要不与其他地点的值重复就行(对应 WebPageTest 首页 Test Location 下拉框中每个组下的选项)
; group 的 value 随意填写,可与其他地点的值重复(对应 WebPageTest 首页 Test Location 下拉框中的组)
; 这里 Test_PC 以 Firefox 和 Chrome 为例
[Test_PC]
1=WPT_Firefox
2=WPT_Chrome
label=macOS
group=Desktop

[Test_Mobile]

1=Android_Chrome
label=Android Chrome
group=Mobile

; 以下为浏览器的详情项,测试地点详细项中的每一个浏览器节点名都应该对应这里的一个 section
; key 包括 browser 和 label
; browser 的 value 为浏览器名,同一个浏览器节点下不得重复(对应 WebPageTest 首页 Browser 下拉框中的选项)
; label 的 value 随意填写,只要不与其他 label 重复就行
[WPT_Firefox]
browser=Firefox
label="macOS - Firefox"

[WPT_Chrome]

browser=Chrome
label="macOS - Chrome"

[Android_Chrome]

browser=Chrome
label="Android - HTC One M9"
type=nodejs,mobile
connectivity="WiFi"

运行 WebPageTest 测试端

准备工作

终端执行:

1
sudo visudo

此时进入 vim 编辑模式(等同于sudo vim /etc/sudoers,但后者即使 sudo 也会提示无编辑权限),找到:

1
2
root        ALL = (ALL) ALL
%admin ALL = (ALL) ALL

在下面添加一行:

1
your_user_name ALL = (ALL) NOPASSWD:ALL

此操作完成后,再执行 sudo 命令就不需要输入密码了。此操作为官网文档推荐操作:

It is recommended that the agent itself not run as admin/root but that it can elevate without prompting which means disabling UAC on windows or adding the user account to the sudoers file on Linux and OSX (NOPASSWD in visudo).

macOS 测试端

终端执行:

1
2
cd ~/WebPageTest/wptagent
python wptagent.py -vvvv --server http://127.0.0.1/work/ --location WPT_Chrome

说明:

  1. wptagent 依赖于 Python 2.7,不支持 Python 3.x
  2. -vvvv是日志的显示级别,可根据实际情况添加该参数
  3. --server是必填项,后面跟服务端地址(需要加http://且加/work/
  4. --location是必填项,后面跟服务单配置的地点名(此处应该为浏览器节点名)
  5. 执行此命令后,如果开启最高日志级别,会先看到Waiting for Idle...,稍等一段时间即可。如果等待时间过长,可以 Ctrl+C 停止,重新执行一次
  6. Chrome 和 Firefox 正常安装(不更改名称),无需做任何配置(无需修改browsers.ini),wptagent 会自动去相应路径调起浏览器

注意:

  1. 测试时,如果已经运行了 Chrome 或 Firefox 浏览器,已经打开的标签页会被关闭,请提前做好准备
  2. 只有 Chrome 浏览器支持修改 Headers(包括 Script 中setCookie命令)

Android 测试端

终端执行:

1
2
cd ~/WebPageTest/wptagent
python wptagent.py -vvvv --server http://127.0.0.1/work/ --location Android_Chrome --android

说明:

  1. wptagent 依赖于 Python 2.7,不支持 Python 3.x;Android 设备作为测试端还依赖于 adb,这里不赘述
  2. -vvvv是日志的显示级别,可根据实际情况添加该参数
  3. --server是必填项,后面跟服务端地址(需要加http://且加/work/
  4. --location是必填项,后面跟服务单配置的地点名(此处应该为浏览器节点名)
  5. --android代表测试端是 Android 设备
  6. 如果有多台设备(adb devices有多个结果),需要带上--device参数,后面跟 Android SN 码(即adb devices的中的设备编码)
  7. Android 端仅 Chrome 支持全功能,需提前安装好 Chrome 浏览器

注意:

1、如果报错AttributeError: 'Process' object has no attribute 'cpu_affinity',编辑wptagent/internal/adb.py,搜索proc.cpu_affinity([0]),将proc.cpu_affinity([0])注释,并添加pass(注意缩进)

1
2
3
4
5
6
7
8
9
10
11
12
def start(self):
""" Do some startup check to make sure adb is installed"""
import psutil
ret = False
out = self.run(self.build_adb_command(['devices']))
if out is not None:
ret = True
# Set the CPU affinity for adb which helps avoid hangs
for proc in psutil.process_iter():
if proc.name() == "adb.exe" or proc.name() == "adb" or proc.name() == "adb-arm":
# proc.cpu_affinity([0])
pass

2、如果提示Device not ready, high temperature,编辑wptagent/internal/adb.py,搜索if 'temp' in battery and battery['temp'] >,将> 36.0改大,如> 40.0

1
2
3
4
5
6
if 'level' in battery and battery['level'] < 50:
logging.info("Device not ready, low battery: %d %%", battery['level'])
is_ready = False
if 'temp' in battery and battery['temp'] > 36.0:
logging.info("Device not ready, high temperature: %0.1f degrees", battery['temp'])
is_ready = False

同理,如果提示Device not ready, low battery,将上面< 50改低,如< 20


参考文档:在 MacOS Sierra 上安装 Apache 和多个版本的 PHP

如果你喜欢我的文章,欢迎打赏。