やりたい事
- 某サイトからスクレイピングしてきたデータをDBに保存。
※某サイトからは許可を得ている。 - ローカルの開発環境でもある程度、テストデータとして、Seederは用意しておきたい。
- PHPUnitを実行する時にテストデータを作っておきたい。
導入方法
1.fabpot/goutteをインストール
$ composer require fabpot/goutte
2.スクレイピングするバッチを作成
<?php
namespace App\Console\Commands;
use App\Entity\Article;
use Goutte\Client;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
/**
* Class ScrapingCommand
* @package App\Console\Commands
*/
class ScrapingCommand extends Command
{
/**
* スクレイピング先のURL
*/
const SCRAPING_URL = 'http://example.com';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'command:scraping_command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
//インスタンス生成
$client = new Client();
//取得とDOM構築
$crawler = $client->request('GET', self::SCRAPING_URL);
//要素の取得
$tr = $crawler->filter('table tr')->each(function($element){
echo $element->text()."\n";
});
// 以下略
// 取得したデータをArticleエンティティに設定 ※例なので、ざっくり書いてます。
$article = new Article();
// 本当は良い感じに取得したデータをエンティティに詰める
$article->title = $tr;
// 以下略
DB::beginTransaction();
try {
$article->save();
DB::commit();
} catch (\Exception $exception) {
Log::error('記事の更新に失敗しました', [
'exception' => $exception->getMessage(),
'file' => __FILE__,
'method' => __FUNCTION__,
'line' => __LINE__
]);
DB::rollBack();
}
Log::notice('スクレイピングバッチの実行が成功しました。');
}
}
3.orangehill/iseedをインストール
$ composer require --dev "orangehill/iseed"
を実行。
config/app.phpにProviderの設定を追加
'providers' => [
/*
* データベースからLaravelのSeederを逆生成する
*/
Orangehill\Iseed\IseedServiceProvider::class
],
4.下記のコマンドを実行すればテーブルの内容に応じたSeederクラスが生成される。
$ php artisan iseed {table_name}
を実行。
5.Seederクラス生成後のイメージ
<?php
use Illuminate\Database\Seeder;
class ArticlesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
\DB::table('articles')->delete();
\DB::table('articles')->insert([
0 => [
'id' => 1,
'title' => 'タイトル',
'descrition' => '記事の説明文',
'category' => 'Tech',
],
1 => [
'id' => 2,
'title' => 'タイトル',
'descrition' => '記事の説明文',
'category' => 'Tech',
],
2 => [
'id' => 3,
'title' => 'タイトル',
'descrition' => '記事の説明文',
'category' => 'Tech',
]
]
);
}
}
使ってみた感想
- けっこうコマンドの実行時間も短いし、良かった
- データ量が多いとファイルサイズが大きくなってしまうので、上手くfor文とかで重複データはコードで簡潔にまとめてもらえたら尚嬉しい!
- お客さんがマスタデータを提供していない or APIが存在せず、自分でデータを取得しなければいけない案件には向いてそう!