把Mechanize的html_parser改回到Hpricot

阅读更多
记得我最初开始用 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, [">= 0.8.2"])
# s.add_runtime_dependency(%q, [">= 1.2.1"])
# ...
s.add_dependency(%q, [">= 0.8.2"])
# s.add_dependency(%q, [">= 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

你可能感兴趣的:(HTML,Ruby,rubygems,jruby,C#)