FLYING

/* TODO: 気の利いた説明を書く */

XMLサイトマップファイルを生成

gen_sitemap.rb

#!/usr/local/bin/ruby
# -*- encoding: utf-8 -*-

require 'uri'
require 'open-uri'

def get_depth(uri)
	uri.to_s.scan(/\//).size
end

def uri_normalize(uri)
	# include dynamic pages
	uri.sub(/#.*$/, "").sub(/index\.\w+$/, "").gsub(/&/, "&")
	# not include dynamic pages
	# uri.sub(/#.*$/, "").sub(/\?.*$/, "").sub(/index\.\w+$/, "").gsub(/&/, "&")
end

def find(array, uri, begin_uri)
	buf = nil
	begin
		# append a pair
		uri_array = array.map{|a| a.first.to_s}
		depth = get_depth(uri) - get_depth(begin_uri)
		return if uri_array.include?(uri.to_s)
		return if uri.to_s.index(begin_uri.to_s) != 0
		array << [ uri.to_s, 0.8 ** depth ]
		puts "#{uri.to_s}"
		# download source
		open(uri.to_s) {|f|
			buf = f.read
		}
		# find links recursively
		matches = buf.scan(/<a\s*?href=\"([^\"]+?)\"[^>]*?>/)
		matches.each{|m|
			href = uri_normalize(m.first)
			next_uri = uri.merge(href)
			find(array, next_uri, begin_uri)
		}
	rescue Exception
		return
	end
end

def gen_sitemap(uri)
	array = []
	uri = URI.parse(uri)
	find(array, uri, uri)
	
	result = ""
	result << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
	result << "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n"
	array.each {|a|
		result << "<url>\n"
		result << "  <loc>#{a.shift}</loc>\n"
		result << "  <lastmod>#{Time.now.strftime("%Y-%m-%d")}</lastmod>\n"
		result << "  <changefreq>daily</changefreq>\n"
		result << "  <priority>#{a.shift.to_s}</priority>\n"
		result << "</url>\n"
	}
	result << "</urlset>\n"
	
	File.open("sitemap.xml", "w") {|f|
		f.write(result)
	}
end

gen_sitemap(ARGV.shift)
puts "successfully completed."

使い方

$ ruby gen_sitemap.rb http://d.hatena.ne.jp/tondol/

出力

動的ページを含まないようにして*1上記のコマンドを実行した結果,生成されたXMLサイトマップファイルのサンプルです。

sitemap.xml

雑感

HTMLパーサを使わずに正規表現で適当にやってるので誤認識はもちろんあり得ます。また,律儀に1ページずつ全文取得しているので異様に遅いです。添付ライブラリのみでローカルにファイルがなくても生成できるのがメリットと言えばメリットかなあ。

*1:“# include dynamic pages”の部分をコメントアウトして,“# not include dynamic pages”の部分をコメントイン