记得我最初开始用
Nokogiri就是因为
Mechanize用的HTML/XML解析器从
Hpricot转到了Nokogiri。不过Nokogiri用起来问题多多,内存泄漏的问题貌似一直没解决,之前在1.9上想用的时候也是segfault,然后对格式不良好的HTML的解析也有问题。虽说_why离开了人们的视野,但在
whymirror上还能找到why留在github的代码,包括当前版本的
Hpricot;通过RubyGems也还能安装到Hpricot。
最近在写某脚本的时候又被Nokogiri绊倒了,一怒,决定把机上的Mechanize的html_parser换回到Hpricot去。之前
NS老兄已经这么做过一次,向他咨询了经验后,这改造工程顺利完成。下面把步骤记下来。
这次测试的机器上,我安装的是
RubyInstaller Technology Preview2的1.8.6-p383,安装到C:\Ruby。这个新的RubyInstaller装的Ruby上要安装Hpricot得先把devkit也装上才行,为了构建Hpricot用。下载
devkit-3.4.5r3-20090411.7z,解压到Ruby的安装目录,然后从devkit目录里的MSys来完成后面需要命令行的步骤。通过
gem install mechanize
可以安装到Mechanize 0.9.3,然后同样
gem install hpricot
可以安装到Hpricot 0.8.2。
如果是用老的官方版RubyInstaller装的Ruby 1.8.6则不需要devkit,直接用RubyGems就能装上Hpricot。如果你用的是自己构建出来的Ruby的话想必这些gem要怎么构建也该了解。下面描述的步骤也对应非Windows用户,因为只涉及纯Ruby代码的修改。
都装好之后,把下面提到的几个地方改过来:(注释里的是原本的代码,上面是新改的代码)
C:\Ruby\lib\ruby\gems\1.8\specifications\mechanize-0.9.3.gemspec
C:\Ruby\lib\ruby\gems\1.8\gems\mechanize-0.9.3\mechanize.gemspec
s.add_runtime_dependency(%q<hpricot>, [">= 0.8.2"])
# s.add_runtime_dependency(%q<nokogiri>, [">= 1.2.1"])
# ...
s.add_dependency(%q<hpricot>, [">= 0.8.2"])
# s.add_dependency(%q<nokogiri>, [">= 1.2.1"])
(这两个文件里有多处相同的代码要改,不放心的话在文件里搜一下吧)
C:\Ruby\lib\ruby\gems\1.8\gems\mechanize-0.9.3\lib\www\mechanize.rb
require 'hpricot'
# require 'nokogiri'
@html_parser = Hpricot
# @html_parser = Nokogiri::HTML
C:\Ruby\lib\ruby\gems\1.8\gems\mechanize-0.9.3\lib\www\mechanize\page.rb
def parser
return @parser if @parser
if body && response
#if mech.html_parser == Nokogiri::HTML
# @parser = mech.html_parser.parse(html_body, nil, @encoding)
#else
@parser = mech.html_parser.parse(html_body)
#end
end
@parser
end
C:\Ruby\lib\ruby\gems\1.8\gems\mechanize-0.9.3\lib\www\mechanize\util.rb
def to_native_charset(s, code=nil)
#if Mechanize.html_parser == Nokogiri::HTML
# return unless s
# code ||= detect_charset(s)
# Iconv.iconv("UTF-8", code, s).join("")
#else
s
#end
end
def from_native_charset(s, code)
#if Mechanize.html_parser == Nokogiri::HTML
# return unless s
# Iconv.iconv(code, "UTF-8", s).join("")
#else
s
#end
end
Mechanize的设计原本就考虑到了html_parser的切换,所以改起来并不费力。只是page.rb和util.rb里显式写了Nokogiri::HTML这点让人郁闷,要是去掉了require 'nokogiri'这些代码就会抱怨Nokogiri常量未定义。
幸好改造前先问了NS,不然我大概不知道要去改gemspec里的配置。以前一直没了解过RubyGems是怎么工作的orz
091109更新:刚试了在JRuby 1.4.0上用同样方式改造Mechanize让它用Hpricot 0.8.2-java来做html_parser,暂时没遇到什么问题。终于又可以在JRuby上用Mechanize了,泪目 TvT