Skip to content

bright-jp/laravel-web-scraping

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 

Repository files navigation

LaravelでのWebスクレイピング

Promo

このガイドでは、Laravelを使用してWebスクレイピングを実行する方法を解説します。

LaravelでWebスクレイピングは可能ですか?

Laravel は、エレガントな構文を備えた強力なPHPフレームワークであり、Webスクレイピング用のAPIを構築するのに最適です。さまざまなスクレイピングライブラリをサポートしており、データ抽出を簡素化できます。

Laravelのスケーラビリティ、容易な統合、強力なMVCアーキテクチャにより、スクレイピングロジックを整理された状態に保てるため、複雑または大規模なプロジェクトに適しています。詳細は、PHPでのWebスクレイピングのガイドをご覧ください。

Laravel向けWebスクレイピングライブラリのベスト

LaravelでWebスクレイピングを行うための代表的なライブラリをいくつかご紹介します。

  • BrowserKit – 静的HTMLドキュメントとやり取りするためにWebブラウザAPIをシミュレートするSymfonyコンポーネントです。効率的なナビゲーションとスクレイピングのために DomCrawler と連携します。
  • HttpClient – リクエスト送信のために BrowserKit とシームレスに統合できるSymfonyのHTTPクライアントです。
  • Guzzle – Webリクエストの送信とレスポンス処理に使える強力なHTTPクライアントです。HTMLドキュメントの取得に便利です。Guzzleでプロキシを設定する方法もご覧ください。
  • Panther – JavaScriptのレンダリングや操作が必要な動的サイトをスクレイピングするためのヘッドレスブラウザです。

Prerequisites

このLaravelでのWebスクレイピングチュートリアルに従うには、以下の前提条件を満たす必要があります。

PHPでコーディングできるIDEの利用も推奨します。

How to Build a Web Scraping API in Laravel

このセクションでは、Quotes scraping sandbox site を使用してLaravelのWebスクレイピングAPIを作成する手順を説明します。スクレイピング用エンドポイントは次を行います。

  1. ページから引用(quote)のHTML要素を選択する
  2. それらからデータを抽出する
  3. スクレイピングしたデータをJSON形式で返す

ターゲットサイトは次のように表示されます。

Quotes to scrape page

Step 1: Set up a Laravel project

ターミナルを開き、Composerの create-command コマンドを次のように実行して、LaravelのWebスクレイピングアプリケーションを初期化します。

composer create-project laravel/laravel laravel-scraper

これで lavaral-scraper フォルダに空のLaravelプロジェクトが作成されます。お好みのPHP IDEで読み込んでください。

現在のバックエンドのファイル構成は次のとおりです。

file structure in the backend

Step 2: Initialize Your Scraping API

プロジェクトディレクトリで次の Artisan command を実行して、新しいLaravelコントローラーを追加します。

php artisan make:controller HelloWorldController

これにより、/app/Http/Controllers ディレクトリに次の ScrapingController.php ファイルが作成されます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ScrapingController extends Controller

{

//

}

ScrapingController ファイルに、次の scrapeQuotes() メソッドを追加します。

public function scrapeQuotes(): JsonResponse

{

// scraping logic...

return response()->json('Hello, World!');

}

現時点では、このメソッドはプレースホルダーとして 'Hello, World!' のJSONメッセージを返します。

次のimportを追加します。

use Illuminate\Http\JsonResponse;

routes/api.php に次の行を追加して、scrapeQuotes() メソッドを専用エンドポイントに関連付けます。

use App\Http\Controllers\ScrapingController;

Route::get('/v1/scraping/scrape-quotes', [ScrapingController::class, 'scrapeQuotes']);

LaravelスクレイピングAPIが期待どおりに動作することを確認しましょう。LaravelのAPIは /api パス配下で利用できるため、完全なAPIエンドポイントは /api/v1/scraping/scrape-quotes です。

Laravelアプリケーションを起動します。

php artisan serve

これでサーバーはローカルのポート 8000 で待ち受けるはずです。

cURLを使って /api/v1/scraping/scrape-quotes エンドポイントへ GET リクエストを送信します。

curl -X GET 'http://localhost:8000/api/v1/scraping/scrape-quotes'

次のレスポンスが返ってくるはずです。

"Hello, World!"

Step 3: Install the scraping libraries

パッケージをインストールする前に、要件に合うLaravelのWebスクレイピングライブラリを判断してください。ターゲットサイトを開き、Developer Toolsで調査して Network → Fetch/XHR セクションを確認します。

Accessing the 'Fetch XHR' section

このサイトは AJAX requests を行っていないため、データがHTMLに埋め込まれた静的ページです。headless browser は不要であり、使用するとオーバーヘッドが増えてしまいます。

効率的にスクレイピングするために、Symfonyの BrowserKitHttpClient を使用します。次でインストールしてください。

composer require symfony/browser-kit symfony/http-client

Step 4: Download the target page

ScrapingControllerBrowserKitHttpClient をimportします。

use Symfony\Component\BrowserKit\HttpBrowser;

use Symfony\Component\HttpClient\HttpClient;

scrapeQuotes() 内で、新しい HttpBrowser オブジェクトを初期化します。

$browser = new HttpBrowser(HttpClient::create());

HttpBrowser を使用すると、Cookieやセッション処理を含むブラウザの挙動を模倣しながらHTTPリクエストを送信できます。ただし、実ブラウザ内でリクエストを実行するわけではありません。

request() メソッドを使用して、ターゲットURLにHTTP GETリクエストを実行します。

$crawler = $browser->request('GET', 'https://quotes.toscrape.com/');

結果は Crawler オブジェクトとなり、サーバーから返されたHTMLドキュメントを自動的に解析します。このクラスは、ノード選択とデータ抽出の機能も提供します。

上記のロジックが動作していることは、crawlerからページのHTMLを抽出して確認できます。

$html = $crawler->outerHtml();

テストとして、APIがこのデータを返すようにしてください。

これで scrapeQuotes() 関数は次のようになります。

public function scrapeQuotes(): JsonResponse

{

// initialize a browser-like HTTP client

$browser = new HttpBrowser(HttpClient::create());

// download and parse the HTML of the target page

$crawler = $browser->request('GET', 'https://quotes.toscrape.com/');

// get the page outer HTML and return it

$html = $crawler->outerHtml();

return response()->json($html);

}

APIは次を返すようになります。

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Quotes to Scrape</title>

<link rel="stylesheet" href="/static/bootstrap.min.css">

<link rel="stylesheet" href="/static/main.css">

</head>

<!-- omitted for brevity ... -->

Step 5: Inspect the page content

抽出ロジックを定義するために、ターゲットページのHTML構造を調査します。

  1. Quotes To Scrape を開きます。
  2. 引用要素を右クリックし、DevToolsで Inspect を選択します。
  3. HTMLを展開して構造を確認します。

Inspecting the quote elements

.quote 要素には次が含まれます。

  • 引用文のテキスト用の .text ノード
  • 著者名用の .author ノード
  • 関連タグ用の複数の .tag ノード

これらの CSS selectors を使って、Laravelで必要なデータを抽出できるようになりました。

Step 6: Get ready to perform web scraping

スクレイピングしたデータを保存するデータ構造を作成します。ここでは配列を使用します。

quotes = []

次に、Crawler クラスの filter() メソッドを使って、すべての引用要素を選択します。

$quote_html_elements = $crawler->filter('.quote');

これは、指定した .quote CSSセレクタに一致するページ上のすべてのDOMノードを返します。

続いて、それらを反復処理し、各要素にデータ抽出ロジックを適用する準備をします。

foreach ($quote_html_elements as $quote_html_element) {

// create a new quote crawler

$quote_crawler = new Crawler($quote_html_element);

// scraping logic...

}

filter() が返す DOMNode オブジェクトにはノード選択メソッドがありません。これを回避するために、特定のHTML引用要素にスコープしたローカル Crawler インスタンスを作成します。

このコードが正しく動作するように、次のimportを追加します。

use Symfony\Component\DomCrawler\Crawler;

Step 7: Implement data scraping

foreach ループの中で次を行います。

  1. .text.author.tag 要素から必要なデータを抽出する
  2. それらで新しい $quote オブジェクトを作成する
  3. 新しい $quote オブジェクトを $quotes に追加する

まず、HTML引用要素内の .text 要素を選択します。次に、text() メソッドで内部テキストを抽出します。

$text_html_element = $quote_crawler->filter('.text');

$raw_text = $text_html_element->text();

各引用は \u201c\u201d の特殊文字で囲まれています。これらは次のようにPHPの str_replace() 関数で削除できます。

$text = str_replace(["\u{201c}", "\u{201d}"], '', $raw_text);

同様に、著者情報は次のコードでスクレイピングします。

$author_html_element = $quote_crawler->filter('.author');

$author = $author_html_element->text();

タグのスクレイピングは難しい場合があります。1つの引用に複数のタグが付く可能性があるため、配列を定義して各タグを個別にスクレイピングする必要があります。

$tag_html_elements = $quote_crawler->filter('.tag');

$tags = [];

foreach ($tag_html_elements as $tag_html_element) {

$tag = $tag_html_element->textContent;

$tags[] = $tag;

}

filter() が返す DOMNode 要素は text() メソッドを公開していない点に注意してください。代わりに textContent 属性を提供します。

以下がLaravelのデータスクレイピングロジック全体です。

// create a new quote crawler

$quote_crawler = new Crawler($quote_html_element);

// perform the data extraction logic

$text_html_element = $quote_crawler->filter('.text');

$raw_text = $text_html_element->text();

// remove special characters from the raw text information

$text = str_replace(["\u{201c}", "\u{201d}"], '', $raw_text);

$author_html_element = $quote_crawler->filter('.author');

$author = $author_html_element->text();

$tag_html_elements = $quote_crawler->filter('.tag');

$tags = [];

foreach ($tag_html_elements as $tag_html_element) {

$tag = $tag_html_element->textContent;

$tags[] = $tag;

}

Step 8: Return the scraped data

スクレイピングしたデータで $quote オブジェクトを作成し、$quotes に追加します。

$quote = [

'text' => $text,

'author' => $author,

'tags' => $tags

];

$quotes[] = $quote;

次に、APIレスポンスのデータを $quotes リストに更新します。

return response()->json(['quotes' => $quotes]);

スクレイピングループの終了時点で、$quotes には次が含まれます。

array(10) {

[0]=>

array(3) {

["text"]=>

string(113) "The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking."

["author"]=>

string(15) "Albert Einstein"

["tags"]=>

array(4) {

[0]=>

string(6) "change"

[1]=>

string(13) "deep-thoughts"

[2]=>

string(8) "thinking"

[3]=>

string(5) "world"

}

}

// omitted for brevity...

[9]=>

array(3) {

["text"]=>

string(48) "A day without sunshine is like, you know, night."

["author"]=>

string(12) "Steve Martin"

["tags"]=>

array(3) {

[0]=>

string(5) "humor"

[1]=>

string(7) "obvious"

[2]=>

string(6) "simile"

}

}

}

このデータはその後JSONにシリアライズされ、LaravelスクレイピングAPIから返されます。

Step 9: Put it all together

以下がLaravelにおける ScrapingController ファイルの最終コードです。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Illuminate\Http\JsonResponse;

use Symfony\Component\BrowserKit\HttpBrowser;

use Symfony\Component\HttpClient\HttpClient;

use Symfony\Component\DomCrawler\Crawler;

class ScrapingController extends Controller

{

public function scrapeQuotes(): JsonResponse

{

// initialize a browser-like HTTP client

$browser = new HttpBrowser(HttpClient::create());

// download and parse the HTML of the target page

$crawler = $browser->request('GET', 'https://quotes.toscrape.com/');

// where to store the scraped data

$quotes = [];

// select all quote HTML elements on the page

$quote_html_elements = $crawler->filter('.quote');

// iterate over each quote HTML element and apply

// the scraping logic

foreach ($quote_html_elements as $quote_html_element) {

// create a new quote crawler

$quote_crawler = new Crawler($quote_html_element);

// perform the data extraction logic

$text_html_element = $quote_crawler->filter('.text');

$raw_text = $text_html_element->text();

// remove special characters from the raw text information

$text = str_replace(["\u{201c}", "\u{201d}"], '', $raw_text);

$author_html_element = $quote_crawler->filter('.author');

$author = $author_html_element->text();

$tag_html_elements = $quote_crawler->filter('.tag');

$tags = [];

foreach ($tag_html_elements as $tag_html_element) {

$tag = $tag_html_element->textContent;

$tags[] = $tag;

}

// create a new quote object

// with the scraped data

$quote = [

'text' => $text,

'author' => $author,

'tags' => $tags

];

// add the quote object to the quotes array

$quotes[] = $quote;

}

var_dump($quotes);

return response()->json(['quotes' => $quotes]);

}

}

テストしてみましょう。Laravelサーバーを起動します。

php artisan serve

/api/v1/scraping/scrape-quotes エンドポイントにGETリクエストを送信します。

curl -X GET 'http://localhost:8000/api/v1/scraping/scrape-quotes'

次の結果が得られます。

{

"quotes": [

{

"text": "The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.",

"author": "Albert Einstein",

"tags": [

"change",

"deep-thoughts",

"thinking",

"world"

]

},

// omitted for brevity...

{

"text": "A day without sunshine is like, you know, night.",

"author": "Steve Martin",

"tags": [

"humor",

"obvious",

"simile"

]

}

]

}

Next steps

このAPIは、LaravelのWebスクレイピング機能の基本例です。プロジェクトを改善してスケールさせるには、次の拡張を検討してください。

  • クローリングを実装する – ターゲットサイトは複数ページにまたがります。クローリングを使用して、すべての引用を効率的に取得してください。
  • スクレイピングタスクをスケジュールする – API呼び出しをスケジュールし、データをデータベースに保存し、最新状態を維持することで、データ収集を自動化します。
  • プロキシを統合する – レジデンシャルプロキシを使用してリクエストを分散し、スクレイピング対策を回避することで、IPアドレスのBANを避けます。

Ethical Web Scraping

Webスクレイピングはデータ収集のための強力な手段ですが、倫理的かつ責任を持って行う必要があります。コンプライアンスを確保し、ターゲットサイトに悪影響を与えないために、次のベストプラクティスに従ってください。

  • サイトの利用規約を確認する – スクレイピングを行う前に、データ利用、著作権、知的財産に関するガイドラインを確認してください。
  • robots.txt のルールを尊重する – 倫理的なスクレイピング慣行を維持するために、サイトのクローリング指示に従ってください。
  • 公開データのみをスクレイピングする – 認証が必要な制限コンテンツは避けてください。非公開データのスクレイピングは法的な影響を招く可能性があります。
  • リクエスト頻度を制限する – リクエストの間隔を空け、ランダムな遅延を追加することで、サーバー過負荷やレート制限を防ぎます。
  • 信頼できるスクレイピングツールを使用する – 倫理的なスクレイピングガイドラインに従う、十分に保守されたツールを選択してください。

Conclusion

LaravelでのWebスクレイピングはシンプルで、数行のコードで実現できます。しかし、多くのサイトはアンチボットおよびスクレイピング対策ソリューションでデータを保護しています。これを回避するために、あらゆるスクレイピング対策を回避しつつ任意のページのクリーンなHTMLをシームレスに返せるアンロックAPIである Web Unlocker を利用できます。

今すぐサインアップして無料トライアルを開始してください。

About

PHP、BrowserKit、HttpClient を使用して Laravel で Webスクレイピング API を構築し、データを効率的に抽出して処理します。

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors