Ruby Mechanize web scraper库返回文件而不是页面

Ruby Mechanize web scraper库返回文件而不是页面,ruby,object,mechanize,scraper,Ruby,Object,Mechanize,Scraper,我最近一直在使用ruby中的Mechanize gem来编写一个scraper。不幸的是,我试图刮取的URL在GET请求时返回的是Mechanize::File对象,而不是Mechanize::Page对象 我不明白为什么。我尝试的其他每个URL都返回了一个Mechanize::Page对象 是否有某种方法可以强制Mechanize返回页面对象?使用curl(curl yoururl-i)查看HTTP头中特定url的内容类型。在代码中,您可能希望在获取url之前检查内容类型: require '

我最近一直在使用ruby中的Mechanize gem来编写一个scraper。不幸的是,我试图刮取的URL在
GET
请求时返回的是
Mechanize::File
对象,而不是
Mechanize::Page
对象

我不明白为什么。我尝试的其他每个URL都返回了一个
Mechanize::Page
对象


是否有某种方法可以强制Mechanize返回
页面
对象?

使用curl(curl yoururl-i)查看HTTP头中特定url的内容类型。在代码中,您可能希望在获取url之前检查内容类型:

require 'net/http'
url = URI.parse('http://www.gesetze-im-internet.de/bundesrecht/bgb/gesamt.pdf')
res = Net::HTTP.start(url.host, url.port) {|http| http.head(url.path)}
puts res['content-type']

#=> application/pdf
或者,您可以检查Mechanize对象是否属于类
Mechanize::Page

agent = Mechanize.new
unknown_body = agent.get(url)
if unknown_body.class == Mechanize::Page
  self.body = unknown_body
else
  puts "Discarded binary content!"
end

请注意,这种方法会慢得多,因为它会“下载”请求的资源。但是,如果您想存储文件供以后使用,它可能会很有用。

当网站没有将内容类型作为响应的一部分返回时,您可以在连接后挂钩中自行设置内容类型:

agent = Mechanize.new { |a|
  a.post_connect_hooks << lambda { |_,_,response,_|
    if response.content_type.nil? || response.content_type.empty?
      response.content_type = 'text/html'
    end
  }
}
agent=Mechanize.new{a|

a、 post_connect_hooks发生了什么

当你下载一个“普通”网页时,它的标题会有一个类似于
内容类型text/html
的字段。当Mechanize看到这一点时,它知道将网页内容解释为html,并将其解析为一个Mechanize::page对象,包括链接和表单等等

但是如果你点击过一个链接,上面写着“下载CSV数据”或“下载PDF”或者,简而言之,任何非HTML的内容,您收到的页面没有
文本/HTML
内容类型
。由于Mechanize无法将非HTML解析为Mechanize::page对象,因此它会将内容打包为Mechanize::File对象

如何处理Mechanize::File对象取决于您试图完成的任务。例如,如果您知道您访问的页面是CSV数据而不是HTML,则可以按如下方式提取CSV数据:

page = web_agent.get(some_url_that_references_csv_data)
parsed_csv = CSV.parse(page.body)
如果你想成为一名花花公子,你可以编写自己的解析器,允许Mechanize处理非HTML格式。看看你是否想这样做。但是你可以通过直接使用Mechanize::File对象来完成大量工作

回复@user741072评论的附录 另一方面,如果页面是HTML,而有人忽略了将
内容类型设置为HTML,则可以编写一个方法,将HTML解析器中的值替换为默认解析器,其长度刚好足以解析页面。这将强制解析为HTML:

def with_html_parser(agent, &body)
  original_parser = agent.pluggable_parser.default
  agent.pluggable_parser.default = agent.pluggable_parser['text/html']
  begin
    yield
  ensure
    agent.pluggable_parser.default = original_parser
  end
end

让我知道这是否奏效。

给出两个给出不同结果的页面示例这可能是目标服务器基于用户代理或类似的东西正在做的事情。这正是我所需要的。小修改:
response.content\u type
可能为零,因此您需要对此进行测试,例如使用
blank?
。谢谢。顺便说一句“.blank?是rails的一部分而不是ruby。什么?你可以在没有rails的情况下运行ruby???)是的,奇怪的是,一个库比它所用的语言更流行。Mechanize支持请求。你可以从Mechanize::File检索内容类型,你可以如上所述安装可插入的解析器。不需要做额外的工作,Mechanize可以安装哦,这一切对你来说完全公平,我的回答并不是说@zhon和gogogopenny还没有说的任何东西——我只是用更简单的术语说出来。这是一个html页面。问题是写它的白痴没有在标题中声明。我能强迫Mechanize将其解释为html文件吗?