アドベントカレンダーの1日目が空いていたので、飛び込みで記事書きます。
はじめに
WEBサイトをスクレイピングするときに、しばしば面倒なことにぶつかります。
- スクレイピング対象から、想定どおりに文字が取り出せない
- スクレイピングしたいけど、クローラーをつくるの面倒
- あとからスクレイピングしたい箇所に気が付いた
- スクレピング先に大きな負荷かけたくない
それ、コンテンツを取得するダウンローダ「Wget」で解決しましょう。
Wgetとは
すでにご存知の人は読み飛ばしてください。
コンテンツを取得するダウンローダ「Wget」、その歴史は1996年まで遡ります。それからの歴史の詳しいことはWikipedia - Wgetを見ていただくとして、いろいろバージョンアップを重ねて、urlを入力してブラウザで表示するレベルなら十分すぎるほどの便利なダウンロードできるツールとして活躍しています。
Linux OSと呼ばれるたいていの環境には、インストール済みであることが多く、素の状態のLinuxからソフトウェアパッケージや証明書のダウンロードなどで使ってたりします。
とても簡単に使えるWget、いろいろなオプションを使いこなすとクローラー+スクレイピングの手助けをしてくれるツールとして便利に使えます!
Wgetの使い方
とりあえず実行してみる
$ wget https://qiita.com/
シェルを開いてWget
コマンドのあとにURLを入力して、実行してみてください。
するとQiitaのトップページをダウンロードすることができます。
ね、簡単でしょ?
ダウンロードしたらhtmlファイルだけで画像がないんだけど?
最初のWget
コマンドはhttps://qiita.com/のindex.htmlをダウンロードして
という内容でした。「index.htmlをダウンロード」を実行した結果が、愚直にhtmlファイルだけダウンロードされました。
もう少し融通をきかせて欲しい感じもしますが、画像を収集したいときに困ります。
そんなときは、-r
と-l 1
オプションを使います。
$ wget -r -l 1 https://qiita.com/
これでindex.htmlファイルと関連しているファイル(画像など)がダウンロードできました。ちなみにオプションの-r
は再帰的にダウンロード
します。……htmlファイルのなかのリンクを解析しながら、そのリンクをダウンロードします。言葉にするとややこしいですが、ブラウザでリンクを片っ端から開くようなイメージです。
また、-l 1
はリンクの深さを指定します。Wgetの実行時に指定したurlをゼロの起点として、リンクをたどったときに深さがカウントアップします。つまり、https://qiita.com/
ページにあるリンク先は深さ:1
と考えられます。深さを1まで制限することで、指定したurlに係わるコンテンツをダウンロードできるわけです。
サイトをまるっとダウンロードしたい
さきほどのオプション-r
と、-l 1
をちょっと変えて-l 0
を指定します。深さ:0
指定すると延々と深いリンク先もたどってくれます。
$ wget -r -l 0 https://qiita.com/
上記コマンドを実行すると……こんなにファイルいらないよ!ってくらいダウンロードしてるかと思います。途中でやめたいときはCntl+C
で強制終了できます。
ちなみに、Qiitaのようなコンテンツがたくさん掲載されているサイトでは、このコマンドの実行はお勧めしません。動的に生成されているコンテンツの場合、動的に生成されたリンクをたどった先が動的に生成されたリンク集だったりしてWgetが延々とループにはまった状態になることがあるからです。
サイトの一部をダウンロードするには?
ようやくここでスクレイピングの話が出てきます。
スクレイピングする対象が、静的コンテンツの場合はサイトをまるっとダウンロードしてダウンロードしたhtmlファイルをスクレイピング/解析すればいいのですが、動的に生成されるコンテンツの場合、人の目ではループが完結するように見えてもWget上で無限に思えるhtmlページがあるように見えてしまうことがあります。
そこで、Wgetの巡回機能を使わずに、人の手でリンク集を作り そこからWgetでダウンロードをさせる方法をとります。シェル芸を駆使して「とりあえず実行してみる」のようにURLをパラメータとして渡して処理させる方法もあるのですが、せっかくWgetに便利なオプション-i
(対象urlをファイルから読み込む)があるので使ってみます。
$ wget -i url.txt -l 1
url.txt
は、urlが羅列されているテキストです。複数のurlを記述するには改行して書いていきます。
https://qiita.com/advent-calendar/2017/increments
https://qiita.com/advent-calendar/2017/crawler
よくあるテキストファイルです。プログラムでクロールさせるのもアリだとは思いますが、
開発途中で何度もスクレイピング対象のサイトをクロールすると待ち時間(ダウンロード時間)がかかってしまいます。
そこでWgetを使って、1度ダウンロードさせることで、プログラム側はローカルファイルを読み取ってスクレイピングすればよくなります。また、スクレイピング対象のスナップショットとして保存できるため便利です。
記載しなければならないURLが多い?
ひとつひとつurlをテキストファイルに記載するのは大変です。
スクレイピングする対象のリストをスクレイピングして抽出してしまいましょう。
つまり……スクレイピングを効率的に進めるには?
- スクレイピング対象を観察する
- スクレイピング対象の一覧を作る(url.txtの生成)
- Wgetでurl.txtを巡回して対象をダウンロードする
- ダウンロードしたhtmlをスクレイピングする
2.
と4.
の部分だけプログラミングすればよくなるので、効率よくコーディングできます。
終わりに
ざっくりとした説明になってしまいましたが「Wgetしてスクレイピングする」いかがだったでしょうか?
おそらく実際に実行したときに、「保存先のディレクトリを変えたい」とか
「生成されるディレクトリの階層を抑えたい」とか「親ディレクトリの巡回は不要」とか
「Basic認証されたページを取得したい」とか「クッキーを保存/読込したい」とか
色々とやりたいことが出てくるかと思います。
それ、Wgetのオプション指定でできます。
ヘルプに書いてあるので見てみるといろいろ面白い発見があると思います。
$ wget --help