
「スクレイピングって裏ではどういう仕組みで動いてるの?」
「社内のエンジニアにスクレイピングについて相談したいけど上手く伝えられない…」
そんなお悩みを解決する助けとなりたいという想いから、この記事は生まれました。
本記事ではPigDataスクレイピング担当の技術者がWebサイトをスクレイピングしていく手順を、PigDataブログのサイトを実際にスクレイピングしながら解説していきます。
目次
スクレイピングの仕組み
Scrapyとは
スクレイピングを実装するにはいくつかの方法がありますが、今回は「Scrapy(スクレイピー)」というフレームワークを用いてスクレイピングの仕組みを解説していきます。
Scrapyとは、PythonでのWebスクレイピング用に設計されたフレームワークであり、特に設定不要で全体で行うべき処理がある程度組み込まれています。
そのためScrapyを用いると、スクレイピングのための多くのことをフレームワーク自体が行ってくれるので、ユーザーはどのサイトからどのデータを取得するかなどの必要最低限のコーディングだけ行えばよくなります。これにより効率的にスクレイピングを実装することが可能になります。またScrapyはオープンソースであるため、コマンドpip install scrapyでインストールを行うだけで、誰でも簡単に使用することができます。
Scrapyを用いたスクレイピングのデータフロー
それでは、このScrapyを用いたスクレイピングのデータフローを簡単にご紹介します。
Scrapyを用いたスクレイピングのデータフロー概観図

各機能
Spider:ユーザーにより記述されるクラスであり、スクレイピング方法を定義する
Engine:システム全体のデータフローを制御する
Schedulrer:受信したリクエストを格納し、リクエストに応じてそれを返す
Downloader:インターネットよりWebページの情報を取得(ダウンロード)する
Item Pipelines:取得した情報(アイテム)の保存や処理を行う
Middleware:送受信されるリクエストについて任意の処理を加える
まず全体の流れを可視化すると上図のようになります。EngineはPCでいう所のCPUのような存在であり、全体を制御しています。その制御は以下の流れで行われます。
「開発」タブの表示方法は以下の流れです。
- EngineがSpiderからリクエストを受け取る
- EngineがSchedulerにリクエストを送り、リクエストをスケジューリングする
- Schedulrerが次のリクエストをEngineに返す
- EngineはMiddlewareを通してDownloaderにリクエストを送る
- DownloaderがInternetから情報(レスポンス)を取得し、Engineにレスポンスを送る
- EngineがSpiderにレスポンスを送る
- Spiderがレスポンスを処理してアイテムとして格納し、Engineに返す
- EngineはアイテムをItem Pipelinesに送る
全体像を把握していただいたところで、実際にスクレイピングするために必要な設定について次の項目から述べていきます。
スクレイピングをはじめる前の設定
各機能を持つファイルの設定
先述のようにスクレイピングを行うためには多くの機能が必要となるため、その各機能に相当するファイルを設定する必要があります。
ファイル構造
|– scrapy.cfg
|–PigData_blog_pj
|– __init__.py
|– middlewares.py
|– items.py
|– pipelines.py
|– settings.py
|– spiders
|– __init__.py
|– PigData_blog.py
スクレイピングに必要なファイル
上図で示した各ファイルの概要をご説明します。
middlewares.py
送受信されるリクエストに加える処理の内容を記述するファイル。任意の条件を満たすリクエストについて自動で廃棄や変更を行えます。
items.py
取得したデータを格納して、それらが出力される際のデータ形式を定義するファイル。形式を指定することで、意図していないデータが混入することを防ぎます。また、取得したデータをアイテムとして宣言して使用します。
pipelines.py
スクレイピングされたデータ(アイテム)を受け取り、何らかの処理を行うファイル。このファイルの中で、items.pyで宣言したアイテムの出力を記述します。
上図で示した各ファイルの概要をご説明します。
setting.py
pipelines.pyやspider自体を含むすべてのScrapy機能の動作を設定するファイル。このファイルでスクレイピングの環境や条件をカスタマイズします。例えばサーバーへの負荷を考慮した、以下の設定を行うことができます。
スクレイピング間隔設定(DOWNLOAD_DELAY)
Scrapyが次のページをダウンロードするまで待機する時間の設定。長くすると短時間でのアクセス数を減らし、サーバーへの負担を減らせます。
(デフォルト:0 )
同時リクエスト数設定(CONCURRENT_REQUESTS)
Scrapyが実行する数(リクエスト数)の設定。少なくすると一度に実行されるサーバーへのリクエストを減らし、サーバーへの負担を減らせます。(デフォルト:16)
PigData_blog.py
spiderフォルダの中に存在する、スクレイピングの内容を定義するファイル。取得先のサイトは何か、サイト内のどの情報を取得するか、取得した情報をどのような形式で出力するかなどを指定します。次のスクレイピング実行のパートからは、このPigData_blog.pyに書き込むことでコーディングを行っていきます。
スクレイピング実行
スクレイピングをはじめる前の設定ができたら、実際どのようにスクレイピングを行うかをご説明します。
今回はPigDataのブログページ(下図)から各記事の詳細ページに移動し、記事のタイトル・日付・内容についてスクレイピングを行ってみます。

なお、PCの実行環境は以下の通りです。
- Ubuntu 22.04 LTS
- python 3.9.2、scrapy 2.6.1
スクレイピングの手順
①取得するサイトURLを指定
ベースとなるトップURL(https://pig-data.jp/)の後ろに、付加情報を持つ文字列を加えて指定を行います。今回はPigDataサイト内のブログ情報(:「/blog_news/」)の情報を取りたいので、URLは「https://pig-data.jp/blog_news/」となります。
②HTMLを用いた取得項目の設定
WebページからのスクレイピングにはHTMLを利用します。HTMLとはページの情報を構造化することを目的としている言語であり、タグや属性と呼ばれる要素を用いて文字や画像情報のレイアウトを整理して、ホームページ内の情報を管理しています。この要素を指定することで、ページ上の情報を特定して欲しい情報のみを取得できます。要素を指定するには「lxml」や「Xpath」、「CSSセレクター」など書き方が複数ありますが、今回は比較的簡潔に記述できるCSSセレクターを用いています。
例えば記事を検索するための「スクレイピング」というタグのアイコンを表すHTMLから、同様に情報を取るにしても、
<href>で指定 →アイコンのリンク情報(= “http://…”)
<text>で指定 →画像の文字情報(= “スクレイピング”)
がそれぞれ取得できます。
また、こうしたページ上の各情報は、class属性やid属性によってグループ分けされています。そのため属性を正しく指定すれば、一つの情報だけを指定したり、同じclass(同じ属性)の情報をまとめて指定したりも可能です。

(例えば各記事の情報は、class = “blog-thumb”でまとめられている(10件))
また、記事は複数のページにまたがって存在しているので、ページを移動するコードを記述する必要があります。今回はそのページ内の情報を取った後、「次へ」ボタンがあればそのリンクを取得→次ページに移動、という操作を行っています。これを繰り返すことで、「次へ」ボタンが無い最終ページまでの、全ページのデータを取得できます。
③データの出力設定
最後に、データを整形して出力します。まずitems.pyにデータを一度格納し、pipelines.pyにて格納データを指定した形式で出力しました。今回はデータを種類ごとに各列(「タイトル:title」,「日付:data」,「記事の内容:description」)に分け、csvファイルにて出力を行っています。csvファイルであれば、ほとんどのソフトウェアやツール(Excelやテキストファイル)に対応しているので、その後のデータ利活用が容易となります。
また出力時の注意点として、文字コードをPC側とサイト側で一致させる必要があります。文字コードとは、文字をコンピュータ上で扱うために行う処理の形式です。この文字コードの設定によっては、正しくデータが出力されない可能性があります。現在、世界的に多くのソフトウェアやサイトでは”UTF-8”という文字コードが使用されています。しかし、中には”SHIFT-JIS”や”EUC”など別の文字コードを設定している場合もあり、PC側とサイト側で文字コードが違うと、データを移動した際に文字化けやデータの欠損が発生してしまいます。この場合はpipelines.pyで出力時の文字コードを指定してあげましょう。
なお今回は、サイト側の文字コードは<meta charset=”UTF-8”>となっており、PC側と一致していたため変更の必要はありませんでした。

スクレイピングコード公開
ここまでの内容をコード化したものを以下にご紹介します。
import scrapy from ..items import PigItem class PigTestSpider(scrapy.Spider): name = 'pig' start_url = ['https://pig-data.jp/blog_news/'] def parse(self, response): for link in response.css('ul.blog-list div.blog-thumb a::attr(href)').getall(): yield scrapy.Request(url=link, callback=self.parse_blog) next_page = response.css('div.page-nav a.next::attr(href)').get() if next_page: yield scrapy.Request(url=next_page, callback=self.parse) def parse_blog(self, response): content = response.css('div#news-columns div.content-L') if len(content) > 0: item = PigItem() item["title"] = content[0].css('h1::text').get() item["date"] = content[0].css('div.content time::text').get() item["description"] = content[0].css('p::text').getall() yield item
その他必要なファイル(Items.pyやpipelines.py)にもコードを記述すると、以下のようにデータが出力されます。

法律面での注意点
スクレイピングを行う前に、その方法や目的によっては法律的に問題となるケースもあることを知っておかなければなりません。スクレイピングは短時間でサイトへのアクセスを繰り返す行為ですので、サーバーへの負担を考慮する必要があります。
サーバーへの負担軽減には、setting.pyでスクレイピング間隔設定(DOWNLOAD_DELAY)を長くしたり、同時リクエスト数設定(CONCURRENT_REQUESTS)を少なくしたりするなどの方法があります。ただ耐久性はサイト側のサーバーに依存しているため、「この数値以下なら大丈夫」という明確な基準は無く、十分な注意が必要です。過去にはスクレイピング間隔を1秒に設定したもののサーバーがダウンしてしまい、スクレイピングを行った個人が罪に問われた事案も存在します。
まとめ
今回はスクレイピングの仕組みから、実際にScrapyを用いたスクレイピング方法をご紹介してきました。全体像を理解すると、スクレイピングでどんなことが可能なのかがイメージしやすくなるはずです。
よりさらにスクレイピングの概要や活用方法について詳しく知りたい方は、こちらの記事も併せてご覧ください。
弊社ではスクレイピング代行はもちろん、スクレイピングを活用したWebサイトのモニタリングや競合サイトの監視などのサービスも展開しています。そのほか「こんなデータが欲しい」などのご希望があれば、お気軽に弊社までご相談ください。