curlでスクレイピングするときの基本書式

2018年6月22日

あくまで個人的な話。これで正しいかはよくわからないけれど、今のところシェルスクリプトでのスクレイピングはこのスタイルに落ち着きつつあります。

HTTPステータスを確認しよう

curlは受信データを標準出力に出力します。そのままパイプで受けて処理してもいいし、一旦ファイルに保存して処理してもいい。…けど。

エラー処理したほうがよくね?

STATUS=`curl -sS $URL \
              -o $FILE \
              -w "%{http_code}"`
if test $STATUS -eq 200;then
  ~(処理)~
fi

ということでサブプロセスでcurlを動かすことにします。ポイントは-wオプション。

-wオプションは受信データの代わりに、後に続くフォーマット指定に従った結果を標準出力に出力します。ちょうどシェル変数の$マークの代わりに%マークを使って、その変数の値を出力してるみたい。こうしてHTTPステータスを確認すれば、正常終了時とそれ以外とで処理を振り分けることができます。

サブプロセスの結果をシェル変数$STATUSで受けてやればifなどで処理を適切に分岐することができます。

ファイル出力オプション-o

-wオプションを設定してしまったので受信データを標準出力できなくなってしまいましたが、これは-oオプションで解決できます。

-oに続けてファイル名を指定すると、出力先がそちらに切り替わります。

ちなみにやったことはないですが、-oオプションを使えば複数の接続先ごとに出力ファイルを切り替えることもできます。

curl first.url second.url -o first.file -o second.file

名前を合わせる必要はなくて、単純に順番に沿って出力されます。

出力メッセージを抑制する

定期的にクロールする場合など、cronでスクリプトを実行すると進捗メッセージがmailに残ります。

# curl https://prim.mariinsky.ru/en/playbill/playbill > mariinsky.txt
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 38126    0 38126    0     0   4891      0 --:--:--  0:00:07 --:--:--  9206

あえて記録したいとか、他にも出力メッセージがあるからいいとか、そういうことでない限り上記のようなメッセージだけのメールが残ります。1時間おきとかに実行したら1日24通のメールが溜まっちゃう。

というわけで-sオプション(小文字のs)でメッセージは抑制してしまいましょう。-wオプションで実行結果は捉えているし、そもそもcronの実行なんかリアルタイムで見てないし。

ただしこのオプションはエラーメッセージも含めて出力しないオプションです。HTTPステータスはわかるけれど、それ以外の実行時エラーは一切わからなくなります。

対策としては-sSと大文字のSオプションも同時に指定することで、エラーが発生した時だけメッセージを出力するようになります。だからエラーが出たときだけメールにログが残る。

curlのスクレイピングスタイルはこんな感じに落ち着いています。