创建博客 登录  
 关注
   显示下一条  |  关闭

龙第九子de博客

易无思也,无为也,寂然不动,感而遂通天下之故

 
 
 

日志

 
 

lsblog的改进版本  

2009-03-08 21:52:35|  分类: Tech |  标签: |字号 订阅

今天对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]
  评论这张
转发至微博
转发至微博
0   分享到:        
阅读(243)| 评论(3)| 引用 (0) |举报

历史上的今天

相关文章

最近读者

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--相关文章--> <#--历史上的今天--> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2012