【初心者向け】Laravelでブラウザを操作して検索順位チェックツールを作ろう

Laravelでスクレイピングをしてみたら、「データが取得できない!」と困った経験はありませんか?

Laravelでスクレイピングをする際、多く使われるのは「Goutte」というライブラリです。ところが、Webサイトによってはセレクターが取得できない場合があります。

どうやら、WebサイトのデータをJavaScriptで表示していることが原因のようです。ちなみに、代表的な例は「Googleの検索結果」で、GoutteでURLを入力しても「セレクターがない!」と表示されます。

しかし、JavaScriptでページが表示されたあとなら、データが存在するためセレクターを指定できます。つまり、下記の順番で処理を実行すれば、スクレイピングが可能になります。

  1. ブラウザで対象のサイトを開く
  2. ページが表示される
  3. セレクターを指定する

実は、ブラウザを操作できるライブラリもあります。例えば、Pythonと組み合わせてスクレイピングで使われる「Selenium」が有名です。

Laravelにもブラウザを操作するテスト用の機能が搭載されており、便利なライブラリもあります。それらを組み合わせることで、「検索順位チェックツール」を作ることができました。

そこで、完成までに必要な準備手順をご紹介します。とはいえ、コマンドで動くシンプルな内容なので、ご自分で使いやすいようにカスタマイズしていただけたらと思います。

この記事では、Laravelで検索順位チェックツールを作る方法について解説しているので、ぜひ参考にしてください。

Google検索順位チェックツールの概要

まずはじめに、完成したソースコードを載せておきます。そのあと、手順や内容を順番に解説していきます。

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Laravel\Dusk\Browser;
use Symfony\Component\DomCrawler\Crawler;
use Revolution\Salvager\Facades\Salvager;
use Illuminate\Support\Facades\DB;

class ファイル名 extends Command
{
  protected $signature = 'コマンド名';
  protected $description = 'Command description';
  public function __construct()
  {
    parent::__construct();
  }
  public function handle()
  {
    DB::table('テーブル名')->truncate();
    Salvager::browse(function (Browser $browser) use (&$crawler) {
      $crawler = $browser->visit('https://www.google.com/')
      ->keys('input[name=q]', 'キーワード', '{enter}')
      ->crawler();
      for ($i=1; $i < ページ数; $i++) {
        $urls = $crawler->filter('.g')->each(function (Crawler $node) {
          $title = $node->filter('h3')->count() != 0 ?  $node->filter('h3')->text() : null;
          $href = $node->filter('a')->attr('href');
          $href = substr($href, 0, strpos($href, '/', 8) + 1);
          return [
            'title' => $title,
            'url' => $href,
          ];
        });
        DB::table('テーブル名')->insert($urls);
        $url = $crawler->filter('#pnnext')->attr('href');
        $crawler = $browser->visit('https://www.google.com/' . $url)->crawler();
      }
    });
    $check = DB::table('テーブル名')->where('url', 'ドメイン')->first();
    if (empty($check)) {
      echo "残念ながら圏外です。";
    } else{
      echo "あなたの検索順位は" . $check->id . "位で、" . "\n";
      echo "記事タイトルは『" . $check->title . "』です。";
    }
  }
}

上記のカタカナで書かれた部分を、あなたが調べたい内容に合わせて編集してください。

Laravelで検索順位チェックツールを作る準備

それでは、実際の作り方に進んでいきます。まずは、Laravelで検索順位チェックツールを作る手順を簡単にまとめておきます。

なお、開発環境はMacMAMPです。

  1. MAMPでLaravelを使う準備をする
  2. LaravelにSalvagerをインストールする
  3. コマンドを作る

では、順番に見ていきましょう。

MAMPでLaravelを使う準備をする

まずはじめに、MAMPを使ってLaravelの準備をします。ちなみに、Laravelにはサーバーが標準で搭載されていますが、MAMPを使った方が作業が簡単です。

では、MAMPを起動させ、下記の手順で準備を進めてください。

  1. MAMPのhtdocsにLaravelをインストールする
  2. MAMPに合わせて.envファイルを編集する
  3. Laravelとデータベースを接続する
  4. MAMPのドキュメントルートをLaravelのpublicフォルダーに変更する

なお、MAMPの詳しい設定方法については、⬇︎のLaravelでスクレイピングをする方法を解説した記事で確認してください。

➡︎【初心者でもカンタン】Laravelでスクレイピングをしてデータを保存する方法

このとき、データベースに必要なテーブルは【ID・タイトル・URL】の3つです。なお、タイトルは『nullable』に設定しておきます。

$table->string('title')->nullable();

ちなみに、タイトルがなくても検索順位はわかりますが、記事を特定するために取得しています。

データベースのマイグレーションを済ませ、MAMPのドキュメントルートを設定したら、次の作業へ進みます。

LaravelにSalvagerをインストール

続いて、Laravelフォルダーに「Salvager」というスクレイピング用のライブラリをインストールします。Salvagerは、「Laravel Dusk」というテスト用の機能をベースに作られています。

なお、Salvagerについて詳しく知りたい方は、下記のページで確認してください。

  • Salvager:Laravel Duskベースのスクレイピングライブラリ
  • GitHub:kawax/salvager(ソースコード)

では、ターミナルを開いてLaravelフォルダーへ移動し、下記のコマンドでSalvagerをインストールします。

composer require revolution/salvager

続けて、config/salvager.php最新バージョンのChromeDriverもインストールします。

php artisan vendor:publish --provider="Revolution\Salvager\Providers\SalvagerServiceProvider"
php artisan dusk:chrome-driver

インストールしたら、一度ターミナルを閉じて再起動すれば準備は完了です。ついでに、ターミナルでコマンドファイルも作っておきましょう。

php artisan make:command ファイル名

これで、App\Console\Commandsの中にコマンドファイルができました。では、スクレイピングをするためのコードを書いていきます。

スクレイピングのコマンドを作る

ここからは、スクレイピングを実行するコマンドを作っていきます。ちなみに、コマンドで動かす理由は作業量を減らすためです。

それでは、まずコマンドを作るときの流れを簡単にまとめておきます。

  1. コマンドを実行する名前を決める
  2. use宣言を書く
  3. スクレイピングするページ数を設定する
  4. データベースに保存する
  5. 結果をターミナルへ出力する

それでは、順番に見ていきましょう。

コマンド名を決めてuse宣言をする

最初に、実行するコマンドの名前を決めます。

class ファイル名 extends Command
  {
    protected $signature = 'command:name';  ←コマンド名に変更する

次に、use宣言で必要なクラスを読み込みます。Salvagerのページで必要なクラスを確認できます。

use Laravel\Dusk\Browser;
use Symfony\Component\DomCrawler\Crawler;
use Revolution\Salvager\Facades\Salvager;
use Illuminate\Support\Facades\DB;  ←データベースと接続するために追加

続いて、スクレイピングをするためのコードを書いていきます。もし、全てのコードをコピペしても動かなかった場合、修正箇所を探すのが大変なので、順番に進めていきましょう。

ブラウザを操作してスクレイピングをしてみる

まずは、Salvagerのページにあるサンプルコードを動かします。App\Console\Commands内にあるコマンドファイルを開き、下記を記述します。

public function handle()
  {
    Salvager::browse(function (Browser $browser) use (&$crawler) {
      $crawler = $browser->visit('https://www.google.com/')
      ->keys('input[name=q]', 'Laravel', '{enter}')
      ->crawler();
    });
    $crawler->filter('.g')->each(function (Crawler $node) {
    dump($node->filter('h3')->text());
    dump($node->filter('a')->attr('href'));
    });
  }

ここでのポイントは2つあります。サンプルコードを下記の通りに変更しています。

  • スクリーンショットは必要ないので削除
  • 指定するセレクターは『.g』(2021年12月現在)

では、実際にコマンドを動かしてみましょう。ターミナルを開いてLaravelフォルダーへ移動し、下記のコマンドで実行してください。

php artisan コマンド名

これまでに問題がなければ、Googleで「Laravel」と検索した結果のタイトルとURLが、交互に10件ずつターミナルに表示されるはずです。

もしエラーが出た場合は、これまでの内容を順番に確認してみてください。

ページ数とURLを調整する

次に、取得するURLの件数文字数を調整します。まずは、変更内容と理由を簡単にまとめておきます。

変更内容理由
必要なページ数を設定し繰り返す取得するURLの件数を増やすため
要素があるかどうかを判定するnullのエラーを回避するため
ディレクトリやファイル名はカットするURLからドメインのみを取得するため

次に、URLの件数と文字数を調整したあとのコードを載せておきます。(URLを50件取得する場合)

Salvager::browse(function (Browser $browser) use (&$crawler) {
  $crawler = $browser->visit('https://www.google.com/')
  ->keys('input[name=q]', 'キーワード', '{enter}')
  ->crawler();

//繰り返し処理
  for ($i=1; $i < 6; $i++) { 
    $crawler->filter('.g')->each(function (Crawler $node) {

//タイトルの有無を判定
      $title = $node->filter('h3')->count() != 0 ? $node->filter('h3')->text() : null;
      dump($title);

//URLを切り取る
      $href = $node->filter('a')->attr('href');
      $href = substr($href, 0, strpos($href, '/', 8) + 1);
      dump($href);
    });

//次のページへ進む
    $url = $crawler->filter('#pnnext')->attr('href');
    $crawler = $browser->visit('https://www.google.com/' . $url)->crawler();
  }
});

では、順番に解説していきます。

取得するURLの件数を設定する

検索順位をチェックするために取得するURLを増やします。検索結果はおよそ1ページ=10件のため、取得したい件数に合わせて繰り返す処理を記述します。

for ($i=1; $i < ページ数; $i++) {}

そのあと、検索結果の「次へ」ボタンのURLを取得し、クローラーへ渡します。

$url = $crawler->filter('次へボタンのセレクター')->attr('href');
$crawler = $browser->visit('https://www.google.com/' . $url)->crawler();

以上が、必要なURL数を調整する処理になります。

スクレイピングのエラーを回避する

スクレイピングを実行したとき、検索結果の間に広告などが表示されると、取得したデータが「null」となりエラーが出ます。

そこで、今回はnullのままデータを保存していきます。

$node->filter('h3')->count() != 0 ? $node->filter('h3')->text() : null;

このとき、データベースのタイトルのカラムが『nullable』でない場合は、保存できずにエラーとなるため、phpMyAdminで設定を確認してください。

URLを短くする

検索順位をチェックする方法として、データベースに保存したURLと「ドメイン名」を照合します。このとき、ドメイン以降のURLは必要ありません。

そこで、取得したURLを『https://〇〇.〇〇/』の形に切り取ります。今回は、3つ目の『/』以降を切り捨てました。

substr(URL, 0, strpos(URL, '/', 数え始める場所) + 1文字)

データベースに保存する

続いて、取得したタイトルとURLを配列にしてから、データベースへ保存します。

return [
  'title' => $title,
  'url' => $href,
];
DB::table('テーブル名')->insert(配列);

ただし、このままでは検索順位を調べる度にデータが増えてしまいます。そこで、検索順位をチェックする前に、テーブルをリセットする処理を加えます。

DB::table('テーブル名')->truncate();

結果をターミナルへ出力する

最後に、検索順位をチェックしてターミナルへ出力します。まずは、検索順位をチェックする流れをまとめておきます。

  1. 検索したいドメインを指定する
  2. 取得したURLから一致するドメインを検索する
  3. ターミナルへ出力する

実際のコードは下記の通りです。

//ドメインが一致したらデータを取得する
$check = DB::table('テーブル名')->where('url', 'ドメイン')->first();

//一致するドメインがない場合
if (empty($match)) {
  echo "残念ながら圏外です。";

//ドメインが一致したらIDを順位に置き換え、タイトルを表示する
} else{
  echo "あなたの検索順位は" . $check->id . "位です。" . "\n";
  echo "記事タイトルは『" . $check->title . "』です。";
}

以上で、検索順位チェックツールの出来上がりです。

ブラウザを操作してスクレイピングしてみよう

LaravelとGoutteを使えば、簡単にスクレイピングができます。しかし、Goutteではセレクターを指定できない場合があります。

そんなときは、Salvagerを使ってブラウザを操作してみてください。しかも、Laravelならデータベースと簡単に接続できるため、キーワードの種類URLの件数も自由に変更可能です。

今回はコマンドで動かすだけのシンプルな内容ですが、ビューコントローラーを作れば、より使いやすくカスタマイズできると思います。

なお、Laravel Duskテストをするための機能です。セキュリティに問題が発生するため、本番環境では使わないよう公式サイトに記載されています。

他にも、Laravelを使ってさまざまなアプリを作ることができるので、興味のある方は⬇︎の記事で学習方法を確認してください。

基本的に、YouTube動画を見ながら独学する方法をご紹介しています。初心者でも始めやすい簡単な内容ですので、ぜひ参考にしてください。

タイトルとURLをコピーしました