ruby hogehoge.rb
http://foobar.com/ と実行したらそのサイトをクロールしてサイト内リンク(テキストのみ)をすべてリストアップするスクリプトを書いてみました。
幾つかのサイトを食わせてみて正常動作してます。このままでもかなり実用に堪えることができると思います。
再帰で実装したら落ちたので再帰を使わないでクロールを行なってます。結構大変ですねぇ。。<クロール
require 'rubygems'
require 'hpricot'
require 'open-uri'
require 'kconv'
require 'uri'
def catanate(p1="/",p2 = "")
return p2 if p2 =~ /^\//
p1 = p1.sub(/\/([^\/]+)$/,"/");
return p1 + p2
end
def crawler(start)
offset = ""
s_uri = URI.parse(start).normalize
if @bad_urls[s_uri.to_s] != nil then
p "bad url skipped #{s_uri.to_s}"
return
end
queue = []
begin
host = s_uri.host
f = open(s_uri.to_s);
base_uri = f.base_uri
return unless f.content_type =~/text/
if base_uri.host != s_uri.host then
@bad_urls[s_uri.to_s] = "DUMMY"
return
end
doc = Hpricot(f)
rescue => ex
@bad_urls[s_uri.to_s] = "DUMMY"
p "#{s_uri.to_s} ==> #{ex}"
else
(doc/'a').each { |e|
s = e.inner_html.toutf8.gsub(/<.*?>/,'')
next if s == nil || s == ''
begin
next unless e.attributes['href']
uri = URI.parse( e.attributes['href']).normalize
scheme = (uri.scheme == nil ? s_uri.scheme : uri.scheme)
next unless scheme =~/http/
host = (uri.host == nil ? s_uri.host : uri.host)
next unless host == s_uri.host
port = (uri.port == nil ? s_uri.port : uri.port)
if port != nil then
port = (port.to_i == 80 ? "" : ":#{port}" )
end
path = catanate(s_uri.path,uri.path)
qs = ( uri.query == nil ? "" : "?#{uri.query}" )
s = scheme + "://" + host + port + path + qs
next unless @urls[s] == nil
@urls[s]="dummy";
queue.push(s);
rescue => ex2
p "#{e.attributes['href']} => #{ex2}"
end
}
end
return queue;
end
@urls = {}
@bad_urls = {};
q = []
q.push(ARGV[0])
q.each{ |u|
p u
sleep 0.1
wk = crawler(u)
q.concat(wk) if wk != nil
}
@urls.sort.each { |key,val|
p key
}