最後に今回やったことをまとめておきましょう。
-
reqwest
クレートを使って、HTTPサーバにGETリクエストを送信してウェブページを取得しました。レスポンスからボディ、ステータスコードやリダイレクト後のURLを取り出しました。 -
select
クレートを使って、HTML文書から<a>
要素を抜き出し、そのhref
属性の値を取り出しました。 -
url
クレートを使ってURLをパースしました。パースしたURLが相対URLだった場合にはリダイレクト後のURLをベースにして絶対URLに変換しました。 -
log
クレートを使って、ログを記録するようにしました。ログの表示にはenv_logger
クレートを使いました。 -
thiserror
クレートを使って独自のエラー構造体を実装しました。呼び出し側でのエラー処理にはeyre
を使いました。 - 幅優先探索をイテレータとして実装しました。
-
structopt
クレートを使ってコマンドライン引数のパース機能を作りました。
以上のステップを踏んで、最低限の機能をもったウェブクローラを作ることができました。この冊子で知ったことを読者のみなさんが作るプログラムに役に立つことを願います。また、mini-carwler
にさらに機能を付け加えてみたい人は、どうぞご自由に改造してみてください。完成版のソースコードは https://github.com/ShotaroTsuji/mini-crawler にMIT Licenseで公開しています。
使用したクレートに関する補足
コマンドラインプログラムを作成するために使用するクレートについて少し補足をしておきます。
手続きマクロを使ってコマンドライン引数を処理するクレートは現在のところstructopt
を使うのがベストだと思いますが、将来的にはclap
に同等の機能が実装されるようです[1]。
ロギングに関しては、シングルスレッドのプログラムを実装するのであればlog
クレートで十分なように思います。しかし、マルチスレッドや非同期のプログラムに対しては不十分でしょう[2]。より高機能なクレートとしてslog
がありますが、筆者は使ったことがないのでこれに対してコメントはできません。
この冊子で作ったプログラムを実際に動かした方の中には、env_logger
が色付けして文字を表示していることが気になった方もいるでしょう。ターミナルにエスケープシーケンスを使って文字を色付けするためのクレートとして、ansi_term
があります。また、出力がターミナルか否かを判別するにはatty
を使います。
エラー処理に関しては、ライブラリではthiserror
を使い、アプリケーションではanyhow
を使うのが標準的なようです。ただし、今回はanyhow
の代わりにそのフォークであるeyre
を使いました。これは筆者が普段、エラー表示のためにcolor-eyre
を使っていて、eyre
の方に慣れているからです。
参考文献
-
Rust Cookbook - Extract all links from a webpage HTML
リンクの抽出はRust Cookbookに掲載されているサンプルを参考にコードを書きました。
-
幅優先探索は、杉原厚吉「データ構造とアルゴリズム」(共立出版、2001年)を参考に記述しました。
-
https://qiita.com/watawuwu/items/a6cbcd92dfb5336b9a01#引数処理c ↩︎
-
log
クレートにおいて排他処理は行われています。ただしlog::debug!
などのマクロを呼ぶたびにenv_logger
などのクレートが登録したロガー(Log
トレイトを実装したオブジェクト)が呼び出されます。env_logger
のロガーは呼び出されるとそのスレッドで印字処理が行われるようなので、おそらくログを記録するたびにブロックしてしまいます。また、非同期プログラミングにおいては、どのタスクを実行している時のログなのかも記録しないと、後から解析するのが困難になります。 ↩︎