こんにちは!この記事はGRIPHONE Advent Calendar 2021 3日目の記事です。
PHPでWebサイトをスクレイピングしてE2Eテスト等をするための便利なライブラリであるsymfony/pantherを試してみたいと思います。また、実行環境として、こちらも便利なGitHub Actionsを利用したいと思います。
symfony/pantherのインストール
まずはsymfony/panther
をインストールします。
$ composer require symfony/panther
Using version ^1.1 for symfony/panther
./composer.json has been created
Running composer update symfony/panther
Loading composer repositories with package information
Updating dependencies
Lock file operations: 16 installs, 0 updates, 0 removals
- Locking php-webdriver/webdriver (1.12.0)
- Locking psr/container (1.1.2)
- Locking psr/log (3.0.0)
- Locking symfony/browser-kit (v5.3.4)
- Locking symfony/deprecation-contracts (v2.5.0)
- Locking symfony/dom-crawler (v5.3.7)
- Locking symfony/http-client (v5.3.11)
- Locking symfony/http-client-contracts (v2.5.0)
- Locking symfony/panther (v1.1.1)
- Locking symfony/polyfill-ctype (v1.23.0)
- Locking symfony/polyfill-mbstring (v1.23.1)
- Locking symfony/polyfill-php72 (v1.23.0)
- Locking symfony/polyfill-php73 (v1.23.0)
- Locking symfony/polyfill-php80 (v1.23.1)
- Locking symfony/process (v5.3.12)
- Locking symfony/service-contracts (v2.5.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 16 installs, 0 updates, 0 removals
- Downloading psr/log (3.0.0)
- Downloading symfony/http-client-contracts (v2.5.0)
- Downloading symfony/polyfill-php80 (v1.23.1)
- Downloading symfony/process (v5.3.12)
- Downloading symfony/polyfill-php72 (v1.23.0)
- Downloading symfony/deprecation-contracts (v2.5.0)
- Downloading psr/container (1.1.2)
- Downloading symfony/service-contracts (v2.5.0)
- Downloading symfony/polyfill-php73 (v1.23.0)
- Downloading symfony/http-client (v5.3.11)
- Downloading symfony/polyfill-mbstring (v1.23.1)
- Downloading symfony/polyfill-ctype (v1.23.0)
- Downloading symfony/dom-crawler (v5.3.7)
- Downloading symfony/browser-kit (v5.3.4)
- Downloading php-webdriver/webdriver (1.12.0)
- Installing psr/log (3.0.0): Extracting archive
- Installing symfony/http-client-contracts (v2.5.0): Extracting archive
- Installing symfony/polyfill-php80 (v1.23.1): Extracting archive
- Installing symfony/process (v5.3.12): Extracting archive
- Installing symfony/polyfill-php72 (v1.23.0): Extracting archive
- Installing symfony/deprecation-contracts (v2.5.0): Extracting archive
- Installing psr/container (1.1.2): Extracting archive
- Installing symfony/service-contracts (v2.5.0): Extracting archive
- Installing symfony/polyfill-php73 (v1.23.0): Extracting archive
- Installing symfony/http-client (v5.3.11): Extracting archive
- Installing symfony/polyfill-mbstring (v1.23.1): Extracting archive
- Installing symfony/polyfill-ctype (v1.23.0): Extracting archive
- Installing symfony/dom-crawler (v5.3.7): Extracting archive
- Installing symfony/browser-kit (v5.3.4): Extracting archive
- Installing php-webdriver/webdriver (1.12.0): Extracting archive
- Installing symfony/panther (v1.1.1): Extracting archive
3 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
13 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
1.1.1
のバージョンのインストールが完了です。
chromedriverのインストール
まずは、mac上で開発できるように、brewを用いてインストールしておきます。symfony/panther
のREADME.md
にはgeckodriver
もインストールしていますが、今回は使用しないのでインストールしていません。
$ brew install chromedriver
確認したときのバージョンは96.0.4664.45
になります。
スクレイピングしてスクリーンショットを撮ってみる
README.mdに書かれているサンプルコードを参考にしながら、とりあえず動くであろうソースコードを書いてみました。
<?php
use Symfony\Component\Panther\Client;
require __DIR__.'/vendor/autoload.php';
$client = Client::createChromeClient();
$crawler = $client->request('GET', 'https://tech.griphone.co.jp/');
$client->takeScreenshot('screen.png');
これで実行してみました。
すると、以下のようなポップアップが表示され、実行に失敗してしまいました。
“chromedriver”は、開発元を検証できないため開けません。
このアプリケーションにマルウェアが含まれていないことを検証できません。このファイルは”Homebrew Cask”より今日の20:32にsites.google.comからダウンロードされました。
一度手動でchromedriverを実行しておく必要がありそうです。
インストール先は/usr/local/bin/chromedriver
なので、open /usr/local/bin/
などでFinderを開きます。Finderを開き、先程インストールした chromedriverを右クリックして開くを選択します。
一度実行したらOKです。もう一度実行してみましょう。
$ php test.php
$
エラーなく実行されました。
$ ls
README.md composer.json composer.lock screen.png test.php vendor
そして、ちゃんとscreen.pngファイルが生成されてました。以下がscreen.pngになります。
お寿司が美味しそうです。
スクショ画像をSlackに投稿する
次に生成したスクリーンショットの画像をSlackに投稿してみましょう。Slackボットを作成する手順は省略しますが、Bot Scopesにfiles:write
が必要になるので注意してください。
<?php
use Symfony\Component\Panther\Client;
require __DIR__.'/vendor/autoload.php';
$client = Client::createChromeClient();
$crawler = $client->request('GET', 'https://tech.griphone.co.jp/');
$client->takeScreenshot('screen.png');
$header = [];
$header[] = 'Content-Type: multipart/form-data';
$file = new CurlFile('screen.png', 'image/png');
// Slackに投稿する
$slackApiKey = $argv[1];
$channel = $argv[2];
$postItems = [
'token' => $slackApiKey,
'channels' => $channel,
'file' => $file,
'title' => 'tech.griphone.co.jp',
'filename' => 'screen.png',
'filetype' => 'png',
];
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_URL, "https://slack.com/api/files.upload");
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postItems);
$body = curl_exec($curl);
$errno = curl_errno($curl);
$error = curl_error($curl);
curl_close($curl);
先程のソースコードに対して、雑なSlackに投稿する処理を追加しました。
コマンドの第一引数にSlackボットのUser OAuth Token、第二引数に投稿先のSlackのチャンネルを渡すように実行します。
これで実行してみます。
$ php test.php [トークン(xoxb-XXXXXXXXXXXXXX)] [チャンネル名]
このように、Slackに投稿することができました。
GitHub Actionsで実行する
一通りの処理ができたので、次にGitHub Actionsで実行してみたいと思います。
GitHub ActionsでPHPのバージョンを固定して実行するために、shivammathur/setup-phpを利用させていただきました。
また、PHP8.1もリリースされたので、PHP8.1で実行してみましょう。GitHub Actionsのワークフロー内でphp -vを実行するとこのようにPHP 8.1.0が使われていることが確認できます。
$ php -v
PHP 8.1.0 (cli) (built: Nov 25 2021 11:25:43) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.0, Copyright (c) Zend Technologies
with Zend OPcache v8.1.0, Copyright (c), by Zend Technologies
with Xdebug v3.2.0-dev, Copyright (c) 2002-2021, by Derick Rethans
ワークフローのymlファイルは以下のように作成しました。
name: スクレイピング
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: actions/checkout@v2
uses: actions/checkout@master
- uses: shivammathur/setup-php@v2
with:
php-version: 8.1
tools: composer:v2
- name: initialize
run: |
php -v
composer install
- name: scraping
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
SLACK_BOT_CHANNEL: ${{ secrets.SLACK_BOT_CHANNEL }}
run: |
php test.php ${SLACK_BOT_TOKEN} ${SLACK_BOT_CHANNEL}
Bot User OAuth Tokenとチャンネルはシークレットで指定するようにしてみました。(チャンネルはベタ書きでも良いかもですが)以下のようにSettingsのSecretsから登録します。
Actionsのトリガーとして、workflow_dispatch
を設定することで、手動で実行できるようにしてみました。
これを実行すると以下のように正常に実行できるかと思います。
さて、Slackにはどのように投稿されたでしょうか?
おお、無事に投稿されています。しかし画像をよく見てみましょう。
よく見ると一部文字が文字化けのようになっています。どうやら日本語のフォントが存在しないようです。
日本語フォントをインストールする
日本語のフォントを表示させるために、今回はipaフォントを利用させていただきました。
name: スクレイピング
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: actions/checkout@v2
uses: actions/checkout@master
- uses: shivammathur/setup-php@develop
with:
php-version: 8.1
tools: composer:v2
- name: initialize
run: |
php -v
sudo apt install fonts-ipafont
composer install
- name: scraping
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
SLACK_BOT_CHANNEL: ${{ secrets.SLACK_BOT_CHANNEL }}
run: |
php test.php ${SLACK_BOT_TOKEN} ${SLACK_BOT_CHANNEL}
途中でsudo apt install fonts-ipafont
を追加して、フォントをインストールしています。
これでもう一度スクリプトを実行したいと思います。
投稿された画像をダウンロードして確認してみました。
ちゃんと日本語も表示されました。
まとめ
今回、symfony/panther
を利用してGitHub Actions上で実行し、Slackにスクレイピングした結果を投稿することができました。これでE2Eテストの結果等をSlackに投稿することも簡単に実現できそうです。