LoginSignup
8
1

More than 3 years have passed since last update.

LaravelでスクレイピングしたデータをSeederに逆生成してみた話

Last updated at Posted at 2019-12-23

やりたい事

  • 某サイトからスクレイピングしてきたデータをDBに保存。
    ※某サイトからは許可を得ている。
  • ローカルの開発環境でもある程度、テストデータとして、Seederは用意しておきたい。
  • PHPUnitを実行する時にテストデータを作っておきたい。

導入方法

スクリーンショット 2019-12-24 0.19.32.png

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が存在せず、自分でデータを取得しなければいけない案件には向いてそう!

参考記事

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1