Nasuta<http://www.nasuta.jp/>

2008年04月10日

ruby でサイト内のリンクを抽出

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
}

posted by ふんじ at 23:39| Comment(0) | TrackBack(0) | Misc | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバック
×

この広告は90日以上新しい記事の投稿がないブログに表示されております。