今天对lsblog做了一些改进,主要体现在以下几个方面:
1 借助Hpricot库进行XHTML的解析
Hpricot是一个容错性比较好的Ruby XML解析库,支持HTML和XHTML,而且速度比REXML快。
因此要运行本文列出的Ruby脚本,首先要安装Hpricot,使用gem即可:gem install hpricot
2 使用iconv处理Unicode编码问题。百度空间的默认编码是GBK,而Ruby内部使用utf-8编码。
这次一取得网页就把感兴趣的字符串转换成utf-8,保存的xml文件也采用utf-8编码,舒服多了。
3 采用open-uri抓取网页,这个uri库采用文件式接口(有点像Python的urllib库),使用起来更方便。
4 不但保存了文章地址和标题,同时保存了发表时间,并且增加了简单的统计功能。
代码如下:
### lsblog2.rb
### 获取百度空间的文章列表并储存在本地XML文件中
### 用法:lsblog <Baidu_ID1> [Baidu_ID2 ...]
### 平台:Ruby 1.8.6
### 作者:龙第九子(cxc200026@163.com)
### 时间:2009年3月8日
require 'iconv'
require 'hpricot'
require 'open-uri'
require 'net/http'
require 'rexml/document'
require 'rexml/element'
require 'rexml/formatters/pretty'
CON = Iconv.new("utf-8", "gbk")
def retrieve_url(uri_str)
# 抓取uri_str所指的网页,以String形式返回页面源代码
uri = URI.parse(uri_str)
Net::HTTP.get_response(uri).body
end
def blog_exist?(baidu_id)
# 简单判断一个Baidu空间是否存在
pattern = '空间不存在或者已经删除|该空间已被限制访问或删除'
home = retrieve_url("http://hi.baidu.com/#{baidu_id}")
home =~ /#{pattern}/ ? false : true
end
def get_blog_page_count(baidu_id)
# 获取一个百度空间的博客页面总页数,baidu_id是此用户的百度ID
page0_uri = 'http://hi.baidu.com/' + baidu_id + '/blog/index/0'
page0 = open(page0_uri) {|f| Hpricot(f)} # 抓取第一个“博客”页面
hrefs = page0/'//div[@id="m_blog"]/div[@id="page"]/a[@href]:last'
return 1 if hrefs.nil? || hrefs[0].nil?
hrefs[0]['href'] =~ /([0-9]+)$/ # 只有一页的话href数组为空
return $1.to_i + 1 # 总页数等于尾页标号加1;href为空则返回1
end
def get_list_on_page(baidu_id, page_index)
# 如果一个百度空间的文章数量很多,那么它的“博客”页面就会分成很多页显示
# 这个函数获取标号为page_index的那张页面,然后以XML node形式返回文章列表
page_url = "http://hi.baidu.com/#{baidu_id}/blog/index/#{page_index}"
page = open(page_url) {|f| Hpricot(f)}
hrefs = page/'//div[@id="m_blog"]/div[@class="tit"]/a[@href]'
dates = page/'//div[@id="m_blog"]/div[@class="date"]/*'
tits = page/'//div[@id="m_blog"]/div[@class="tit"]/a[@href]/*'
elem_page = REXML::Element.new('page')
elem_page.add_attributes({'index' => "#{page_index}",
'blogcnt' => "#{hrefs.size}"})
hrefs.each_index do |i|
elem_item = REXML::Element.new('item')
href = "http://hi.baidu.com" + hrefs[i]["href"]
elem_item.add_attributes({'href'=>href})
date = REXML::Element.new('date')
date.add_text(dates[i].to_s)
elem_item << date
title = REXML::Element.new('title')
title.add_text(CON.iconv(tits[i].to_s))
elem_item << title
elem_page << elem_item
end
return elem_page
end
def get_blog_list(baidu_id)
# 获取一个百度空间的全部文章list,保存在XML中并返回根节点
page_count = get_blog_page_count(baidu_id)
bloglist = REXML::Element.new('baidu_space')
total = 0
0.upto(page_count-1) do |i|
elem_page = get_list_on_page(baidu_id, i)
bloglist << elem_page
total = total + elem_page.attributes['blogcnt'].to_i
end
bloglist.add_attributes({'id' => "#{baidu_id}",
'pagecnt' => "#{page_count}", 'total' => "#{total}"})
doc = REXML::Document.new
doc << bloglist
doc << REXML::XMLDecl.new("1.0", "utf-8")
return doc
end
def save_blog_list(baidu_id)
# 将get_blog_list得到的文章列表写入以baidu_id.xml命名的文件
puts "Exploring #{baidu_id}..."
if blog_exist?(baidu_id)
xml = get_blog_list(baidu_id)
f = File.open("#{baidu_id}.xml", 'w')
pretty = REXML::Formatters::Pretty.new
pretty.write(xml, f)
puts " OK. Blog list has been saved to #{baidu_id}.xml"
else
puts " Error! Blog doesn't exist or can't be accessed!"
end
end
###################### Entry Point ######################
if ARGV == []
puts "Usage: lsblog <Baidu_ID1> [Baidu_ID2 ...]"
else
ARGV.each {|id| save_blog_list(id)}
end
有了博客文章列表,就可以每次随机抽取一个进行访问了,代码如下:
require 'iconv'
require 'hpricot'
require 'open-uri'
if ARGV.size < 1
puts "Usage: cak baidu_id [inteval] [limit]"
exit
elsif ARGV.size == 1
baidu_id, inteval, limit = ARGV[0], 60, 999
elsif ARGV.size == 2
baidu_id, inteval, limit = ARGV[0], ARGV[1], 999
else
baidu_id, inteval, limit = ARGV
end
file = File.new("#{baidu_id}.xml")
if file.nil?
puts "Faild to open #{baidu_id}.xml"
exit
end
xml = Hpricot(file)
xarray, xhash = [], {}
items = xml.search("//item")
CON = Iconv.new('gbk', 'utf-8')
items.each do |item|
href = item.attributes['href']
title = CON.iconv( item.search("title/*").to_s.strip )
xhash.store(href, title)
xarray.push(href)
end
counter = 0
while counter < limit
pick = rand(xarray.size)
uri = xarray[pick]
tit = xhash[uri]
open(uri) { |s| s.read }
puts "#{counter}: #{tit}"
counter = counter + 1
sleep rand(inteval*2)
end
参考资料:
1
lsblog:获取百度空间文章列表 2
Hpricot Home Site [龙第九子 2009/03/08]
评论