`
RednaxelaFX
  • 浏览: 3015205 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

把Mechanize的html_parser改回到Hpricot

    博客分类:
  • Ruby
阅读更多
记得我最初开始用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
分享到:
评论
7 楼 zhengb66 2011-03-04  
不错,还是Hpricot好用,速度又快,但最好用0.84版,0.83段溢出太严重。
6 楼 RednaxelaFX 2009-12-29  
yuan 写道
0.8.2到最新的0.9.1不知道是有bug还是把api改了,调用像这样的方法page.links.text('linkxx')会报告 undefined method text in array!%$!@#$
我卸了装0.8.1就没问题了,而且parser默认是hpricot了。

0.8.2到0.9.1是指Hpricot?那我先不要升级……
parser默认是Hpricot是指什么?新版Mechanize么?这个月都没升级过gems没留意动态 T T
5 楼 yuan 2009-12-29  
0.8.2到最新的0.9.1不知道是有bug还是把api改了,调用像这样的方法page.links.text('linkxx')会报告 undefined method text in array!%$!@#$
我卸了装0.8.1就没问题了,而且parser默认是hpricot了。
4 楼 yuan 2009-12-29  
哇靠,改完连编码都自动变了……原来的乱码是Nokogiri搞的啊。
3 楼 yuan 2009-12-29  
正好需要,试一下。
另外,FX有没其它ruby的抓网页工具组合推荐?
不知道mechanize能不能执行javascript……如果不能的话,导航就悲剧了。
2 楼 RednaxelaFX 2009-11-08  
night_stalker 写道
现在的 Mechanize 是 tenderlove (nokogiri 作者) 在维护…… 她比较阴险……

嗯我知道……话说这么改造了之后我要试试以前写的几个用Nokogiri出问题的脚本会不会就没事了
1 楼 night_stalker 2009-11-08  
现在的 Mechanize 是 tenderlove (nokogiri 作者) 在维护…… 她比较阴险……

相关推荐

Global site tag (gtag.js) - Google Analytics