linuxのシェルコマンドでWebページのタイトルを取得する
あるWebサイトのURLがずらずらと書かれたcsvファイルがあって、それにページタイトルの列を付けたいという案件がありました。 100行ちょっとあって面倒くさかったので、シェルでぱぱっと解決することに。
少し考えた結果、以下のようなコマンドでタイトルを取得するようにしてみました。
$ curl -s "${URL}" | grep -oP '(?<=<title>).*(?=</title>)'
各行について処理したかったので、forコマンドと組み合わせて以下のようにして使いました。
for URL in `cat ./url-list`; do
curl -s "${URL}" | grep -oP '(?<=<title>).*(?=</title>)' >> title-list
done
curlもgrepもだいたいのディストリビューションに標準で入っているので、手軽で良い感じ。
中身の解説
curl -s
curlに渡している-s
オプションは--silent
オプションの短縮です。
これを使うことで、ダウンロードの進捗なんかが表示されなくなります。
渡さなくても問題無いのだけれど、沢山出てくるとウザいので付けてあります。
grep -o
grepの-o
オプションは、「マッチした部分だけを表示する」という意味のオプションです。
シェル芸ではよく使う便利オプションです。
今回は、ダウンロードしてきたHTMLからtitleタグの中身だけを抜き出すために使っています。
grep -P
grepにもう一つ渡している-P
オプションは、Perlの正規表現を使うために付けているオプションです。
これを付けておくと、何も付けていない状態のgrepよりも高度な正規表現の機能を使えるようになります。
(?<=<title>).*(?=</title>)
単純にタイトルタグを抜き出す正規表現を考えると <title>.*</title>
のようになるのですが、これだけだと <title>ここにページタイトル</title>
という形で余計なタグが付いた結果しか得られません。
このタグをマッチ結果に含めないようにするために、先ほどの-P
オプションで有効にしたPerlの機能を使っていきます。
まず、開きタグ(<title>
の方)を除去するために、肯定後読みという機能を使います。
書き方は(?<=<title>)
みたいな感じ。(?<=
と)
で囲ってあげます。
これをすると、「<title>
の後に続く文字列しかマッチしない(ただし<title>
自体はマッチに含めない)」ということが出来ます。
まさに今欲しい機能。
次は閉じタグ(</title>
の方)。こちらは肯定先読みを使用します。
書き方は(?=<title>)
という感じ。(?=
と)
ですね。
機能はご想像の通り。
後読みと同じ感じで、「</title>
の前にある文字列にしかマッチしない(ただし</title>
はマッチに含めない)」となります。
そんなわけで、欲しかったタイトルの部分だけを抜き出すことが出来ます。
まとめ
正規表現はいいぞ。