2

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

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

有什么方法可以强制 Mechanize 返回一个Page对象吗?

4

3 回答 3

6

这是正在发生的事情。

当您下载“普通”网页时,其标题将包含一个类似Content-Type text/html. 当 Mechanize 看到这一点时,它知道将页面内容解释为 HTML 并将其解析为 Mechanize::Page 对象,并包含链接和表单等。

但是,如果您曾经点击过“下载 CSV 数据”或“下载 PDF”的链接,或者简而言之,任何不是 HTML 的链接,您将收到一个没有Content-Type. text/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 格式。如果你想走这条路,请参阅PluggableParser 上的 Mechanize 文档。但是您可以通过直接使用 Mechanize::File 对象来完成很多工作。

针对@user741072 评论的附录

另一方面,如果页面HTML 并且有人忽略了将其设置content-type为 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

让我知道这是否有用。

于 2012-04-10T19:44:01.563 回答
3

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

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
  }
}
于 2011-09-19T21:29:28.997 回答
-1

使用 curl (curl yoururl -i) 查看 HTTP-Headers 中特定 url 的 Content-Type。在您的代码中,您可能希望在获取 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

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

于 2011-08-05T09:32:36.190 回答