​ ​

超省エネ(他力)でクローラーを作ってみました

こんにちは
さくらいです

最近、何回か連続して

「クローラーを使って、デッドリンクを調べるぞ」

というプロジェクトがあったので、先人の知恵を拝借して、クローラーを作ることにしました

ポイントは以下の通り

  • 極力ソースは書かない
  • サイト内のデッドリンクを把握したい
  • HTMLファイルだけではなく、画像ファイルなども対象にしたい
  • 結果をみんなで共有したい

では、早速本題に入りましょう

【その1】クローラーのメインの処理はwgetにやってもらう

クローラーを最初から作ると大変ですね
ということで、優秀なwgetコマンドに手伝ってもらいます
今回はデッドリンクを把握したいだけなので、コンテンツをダウンロードしないようにオプションを付けます

wget -r -l inf -w 待ち時間 --no-parent -nv --spider クロール先のURL  2>&1 | tee wgetの出力ファイル 

オプションはこんな感じです

-r → 再帰的に
-l inf → 行けるところまで(infを数字に変えれば、その階層までという意味になります)
-w → サーバに負荷をかけないために待ち時間を
--no-parent → 親には遡らずに
-nv → 余計な出力をなくす
--spider → ファイルのダウンロードをしない

なんか行けそうですね!

【その2】クロールの結果をsedで簡単にparseする

wgetは非常に便利ですが、今回はデッドリンクを見つけるのが目的なので、不要な表示は削除しちゃいます。

ここもプログラムを書くのではなく、コマンドラインで処理しましょう

先ほどのwgetの結果はこんな感じです

2015-04-24 19:50:51 URL:http://クロール対象のURL/index.php [64852] -> "クロール対象のURL/index.php" [1]
2015-04-24 19:50:53 URL:http://クロール対象のURL/robots.txt [90/90] -> "クロール対象のURL/robots.txt" [1]
2015-04-24 19:50:54 URL: http://クロール対象のURL/favicon.ico 200 OK
unlink: No such file or directory
2015-04-24 19:50:55 URL: http://クロール対象のURL/css/style.css 200 OK
unlink: No such file or directory
2015-04-24 19:50:56 URL: http://クロール対象のURL/common/css/basic.css 200 OK
unlink: No such file or directory

ここで必要な情報は『どこにアクセスしたか?』『その結果がどうだったか?』です

抽出するsedコマンドは以下のようになります

sed -e 's/.*\(http:\/\/[^ ]*\)\( [^ ]*\).*/\1,\2/g' 

先ほどwgetで取得したファイルを対象に実行してみます

cat wgetの出力ファイル | sed -e 's/.*\(http:\/\/[^ ]*\)\( [^ ]*\).*/\1,\2/g' 

実行結果は、このようになります

http://クロール対象のURL/index.php, [64852]
http://クロール対象のURL/robots.txt, [90/90]
http://クロール対象のURL/favicon.ico 200
http://クロール対象のURL/css/style.css 200
http://クロール対象のURL/common/css/basic.css 200

1行目と2行目の結果とその他の行の結果が異なっています。

1列目:アクセスしたURL、2列目:クロールしたページのサイズもしくはHTTPステータス
  ↓ ↓ ↓
1列目:アクセスしたURL、2列目:HTTPステータス、3列目:クロールしたページのサイズ

この方が後々使いやすそうですね。
ということで、コマンドを少し書き換えます

cat wgetの出力ファイル | sed -e 's/.*\(http:\/\/[^ ]*\)\( [^ ]*\).*/\1,\2/g' | sed -e 's/\(.*\)\[\(.*\)].*/\1OK, \2/g' > CSVファイル

http://クロール対象のURL/index.php, OK, 64852
http://クロール対象のURL/robots.txt, OK, 90/90
http://クロール対象のURL/favicon.ico 200
http://クロール対象のURL/css/style.css 200
http://クロール対象のURL/common/css/basic.css 200

何となく、いい感じにフォーマットされました。
次はGoogleドライブにアップしてみます

【その3】CSVファイルをGoogleドライブにアップする

これは簡単ですね。
developersnoteでも紹介しています!
詳細はこちらの記事を御覧ください

北村さんのおかげで、簡単にアップするプログラムが作れました

require "google_drive"

client = Google::APIClient.new
auth = client.authorization
auth.client_id = "クライアントID」の文字列"
auth.client_secret = "クライアントシークレット」の文字列"
auth.refresh_token = "************"
auth.fetch_access_token!

filename = ARGV[0]
dir = Dir::pwd
session = GoogleDrive.login_with_oauth(client)
session.upload_from_file(dir + File::SEPARATOR + filename, filename)
p "done!"

これで引数にアップロードしたいCSVファイルを指定すると、Googleドライブにアップしてくれます

【その4】シェルで全部の処理をつなげる

ほとんどコードを書かずに、既存の仕組みを利用してクローラーもどきができました。
最後にシェルで処理するようにしてみましょう

#!/bin/sh

depth=1
sleep_time=1
date_no=`date +"%Y%m%d%H%M%S"`
target_url="クロール先URL"
crawl_file="result_$date_no.txt"
crawl_csv="result_$date_no.csv"

echo " CRAWL START ..."
wget -r -l $depth -w $sleep_time --no-parent -nv --spider $target_url 2>&1 | tee $crawl_file
echo " CRAWL END"

cat $crawl_file | grep -e 'URL' | sed -e 's/.*\(http:\/\/[^ ]*\)\( [^ ]*\).*/\1,\2/g' | sed -e 's/\(.*\)\[\(.*\)].*/\1OK, \2/g' > $crawl_csv

ruby upload.rb $crawl_csv

upload.rbは先ほどのrubyのファイルです

ほとんど数行でクロールした結果が、Googleドライブへ反映される仕組みが出来ました。このファイルのdiffを取れば、サイトが正しく更新されているかを確認できますね

このエントリーをはてなブックマークに追加