phpQueryでスクレイピング

■出来ること
・phpQueryを使ってDMM英会話の講師の予約可能情報をメールで通知。
・講師のスケジュールをジョブ(cron)で定期的に管理
（ex.30分ごとにジョブを実行し、スケジュールに空きがあればメール通知をする)

■実装した理由
何度もWebページで予約状況を確認するのは非効率（いつ講師のスケジュールが更新されるかわからないので、都度見に行く必要がある）の為、ジョブ実行→メール通知で効率化する為。

■実装する上での前提条件
PHP、phpQueryインストール済み、サーバーなどの環境構築も済み

■通知メール本文例

```
A（ア）←講師名
https://eikaiwa.dmm.com/teacher/index/0000000001　←該当リンク（クリックで該当のぺージに遷移する）
G（ジー）
https://eikaiwa.dmm.com/teacher/index/0000000002
2 ←予約可能回数
2020-09-18 22:00:00　←予約可能日時
2020-09-18 22:30:00　←同上
......
.......
```

〇ソース

```scraping.php
<?php
// phpQueryの読み込み(自身のパスを指定)
require('/xxxxx/phpQuery/phpQuery/phpQuery.php');
// 講師のindexページ
$url = "https://eikaiwa.dmm.com/teacher/index/";
// 講師の番号(urlの末尾につける数字(xxxx←該当の数字を入れる))
$arr_index_num = ['xxxx', 'xxxxx', 'xxxxx', 'xxxxx'];
// メール送信(実行)フラグ
$mail_send_flg = false;
// 予約可能回数
$reserve_avail_count = 0;
// メールに載せるメッセージ
$msg_for_mail = array();
// メールに載せるメッセージ加工用の変数（改行)
$result = "";

// スクレイピング開始
foreach ($arr_index_num as $value) {
        $local_url = $url . $value;
        $data = file_get_contents($local_url); // データを取得
        sleep(1); // 1秒間スリープ

        $scraping = phpQuery::newDocument(mb_convert_encoding($data, 'HTML-ENTITIES', 'UTF-8'));
        $name = $scraping->find('.area-detail > h1')->text();
        array_push($msg_for_mail, $name); // 名前を配列にセット
        array_push($msg_for_mail, $local_url); // 各講師のリンクを配列にセット

        $element_a_multi = $scraping->find('[id*="a:5"]'); // 予約可能データを全件取得
        $time = "/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/"; // 日付の正規表現(yyyy-MM-dd HH:mm:ss)
        $reserve_avail_count = count($element_a_multi); // 予約可能回数

        // 予約可能回数が1以上ならメール送信処理を進める
        if ($reserve_avail_count >= 1) {
                $mail_send_flg = true;
                array_push($msg_for_mail, $reserve_avail_count); // 予約可能回数を配列にセット
                foreach ($element_a_multi as $value) {
                        $element_a_each = pq($value); //pq関数は、要素レベルを扱うjQueryの$()に相当する関数
                        preg_match($time, $element_a_each, $match); // 正規表現をつかって一致する日付を取得する
                        $reserve_date = $match[0];
                        array_push($msg_for_mail, $reserve_date); // 予約可能日時を配列にセット
                }
        }
}
// 文字列結合。改行する。
foreach ($msg_for_mail as $value) {
        $result .= $value . PHP_EOL;
}

// メール送信フラグがtrueの場合
if ($mail_send_flg) {
        sendMail($result);
}

/**
 * メール送信メソッド
 */
function sendMail($result) {
        $mail_body = $result;
        mb_language("Japanese");
        mb_internal_encoding("UTF-8");

        $to = "test12344321test@test.abc"; // 送り先メールアドレスを指定する
        $subject = "DMM英会話＿予約可能状況";
        // xxxxxxはメールアドレスを設定する
        $headers = "From: xxxxxxxxxxx" . "\r\n" .
                "Reply-To: xxxxxxxxxxx" . "\r\n" .
                "Return-Path: xxxxxxxxxxx" . "\r\n" .
                "X-Mailer: PHP/" . phpversion();

        mail($to, $subject, $mail_body, $headers);
}
```

〇ジョブ

```cronの設定(ex.30分ごとに実行)
*/30 * * * * PHPのディレクトリ 実行するPHPファイル名
```

■参考URL:
[【PHP】バッチ処理をcronで自動実行する](https://qiita.com/yukibe/items/cd5b59122804223698d0)
[・phpQueryのDLページ]
(https://code.google.com/archive/p/phpquery/downloads)

■あとがき
今後は、DBを使って予約可能状況の管理をする予定です。
(ex.各講師の予約可能状況をDBに保存。次回、ジョブが走った時に予約可能状況に差分があればメール通知する）