コンピュータ/ソフトウェア関連Tips

被リンクの無い(宙に浮いた)ファイルを検出するアイデア

作成日: Jun 11, 2013
カテゴリー: misc タグ: misc

Webサイト内の、被リンクの無い(宙に浮いた)ファイルを検出するアイデアです。 www1.example.comからwww2.example.comのページを参照しているが、www2.example.com内にはindex.htmlが無い…といういささか特殊な状況。時間が限られていたため、力技(ネットワーク負荷無視、効率無視)で、以下のようなことを考えてみました。

Webサイトのオリジナルファイル(オリジナルファイルが手元に無い場合は、FTPとかrsyncで取得)をファイル群Aとし、Webサイトをクローリングして得たファイルをファイル群Bとする。被リンクの無い(宙に浮いた)ファイルがあるのは当然ファイル群Aだ。イメージとしては以下のような感じ。

ファイル群A

index.html
somepage1.html
somepage2.html
somepage3.html
img/someimage1.jpg
img/someimage2.jpg
img/someimage3.jpg

ファイル群B

index.html
somepage1.html
somepage2.html
img/someimage1.jpg
img/someimage2.jpg

この例では、somepage3.htmlと、img/someimage3.jpgは、被リンクの無い(宙に浮いた)ファイルである。単純に、ファイル群Aの個々のファイルに対応するファイルがファイル群Bに存在するかどうかをチェックし、ファイル群Aにしか存在しないファイルは、被リンクの無い(宙に浮いた)ファイルである可能性が高いと判断する。

自分にとっては珍しく、CGIにしてみた。ソースコードは以下。

http://www.exmaple.com/cgi-bin/lonefile.cgi?l=/data/local&c=/data/crawled&h=http://www.example.com/

といった形で呼び出す。1つめ目の引数でファイル群Aのディレクトリを、2つ目の引数でファイル群Bのディレクトリを、3つ目の引数で対応するWebページのルートURLを指定する。

この方法は、いかにうまくサイトをクローリングできるかが肝。wgetではスタイルシート中のファイルを取得してくれないのは経験的に知っていたので、httrackを初めて使った。

HTTrack WEBSITE COPIER http://www.httrack.com/

Linuxマシンにインストールして、コマンドラインにて使用した。オプション設定に難儀したが、www1.example.com/index.htmlを起点として、www1.example.comとwww2.example.com内のコンテンツをクローリング出来た。

まぁ、それらしく動作している。冒頭に書いたとおり、色々度外視しているので、適用出来るケースは少ないと思う。

#!/usr/local/bin/ruby
# The magic comment is unneeded after Ruby 2.0.
# Copyright (C) 2013 Someone in the TERRA
# This is a private work at home.

require 'cgi'
require 'rubygems'
require 'mechanize'
require 'uri'

def get_page_title(url)
  agent = Mechanize.new
  page = agent.get(url)
  begin
    page.title
  rescue
    '*** Could not retrieve the title ***'
  end
end

def write_header
  print <<EOT
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">
<head>
<meta http-equiv="content-style-type" content="text/css">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="description" content="Lone file check results" />
<title>Lone file check result</title>
<style type="text/css">
<!--
  body { background-color: #fff7e5;}
  td.center { text-align: center; }
  td.url { background-color: #dcd5cf; }
  td.warning { background-color: navajowhite; }
  td.ok { background-color: palegreen; }
  td.error { background-color: lightpink; }
  table { border-collapse: collapse; ext-alingn: left;}
  tr { vertical-align: top;}
  th { padding: 2px; border: 1px solid black; background-color: NavajoWhite;}
  td { padding: 2px; border: 1px solid black; background-color: white;
       font-family: Arial,sans-serif; }
  p { font-family: Arial,sans-serif; }
  .indent { margin-left: 50px; }
  h1 { text-align: center;}
-->
</style>
</head>
<body>
<h1>Lone file check result</h1>
EOT
end

def append_footer
  print <<EOT
</body>
</html>
EOT
end

cgi=CGI.new
local_dir=cgi['l']
crawled_dir=cgi['c']
http_base=cgi['h']

print "Content-type: text/html\n\n"

write_header

print "<p>Local directory: #{local_dir}<br>Crawled directory: #{crawled_dir}<br>HTTP-base: #{http_base}</p>\n"
if (local_dir=='')||(crawled_dir=='')||(http_base=='')
  print "<p>One of parameter above is empty.</p>"
end

count=0
unless File.exist?(local_dir)
  print "<p>Error: #{local_dir} is not existed.</p>\n"
  count=count+1
end
unless File.exist?(crawled_dir)
  print "<p>Error: #{crawled_dir} is not existed.</p>\n"
  count=count+1
end
if count>0
  append_footer
  exit(1)
end

print "<p>There is a suspicion that the following files are not linked from any file.  Delete the file if unneeded.</p>\n"

http_base=http_base.sub(/\/$/, '')
Dir.glob("#{local_dir}/**/*") do |f|
  next unless File::ftype(f) == "file"
  relative_path=f.sub(/^#{local_dir}\//, '')
  unless File.exist?("#{crawled_dir}/#{relative_path}")
    uri="#{http_base}/#{relative_path}"
    ext=File.extname(relative_path)
    print %(<p><a href="#{uri}">#{uri}</a>)
    if /\.(gif|png|jpg)$/i =~ ext
      print %(<br><img class="indent" src="#{uri}">)
    elsif /\.(html?)$/i =~ ext
      page_title=get_page_title("file://#{f}")
      print "<br>#{page_title}"
    end
    print "</p>\n"
  end
end

append_footer

exit(0)