2

私は最近、Ruby で Mechanize gem を使用してスクレイパーを作成しています。残念ながら、私がスクレイピングしようとしている URL は、リクエストに対してMechanize::Fileオブジェクトではなくオブジェクトを返します。Mechanize::PageGET

理由がわかりません。私が試した他のすべての URL は、Mechanize::Pageオブジェクトを返しました。

PageMechanize にオブジェクトを返させる方法はありますか?

4

3 に答える 3

6

これが何が起こっているかです。

「通常の」Web ページをダウンロードすると、そのヘッダーには次のようなフィールドが含まれますContent-Type text/html。Mechanize はこれを確認すると、ページ コンテンツを HTML として解釈し、リンクやフォームなどを備えた Mechanize::Page オブジェクトに解析します。

しかし、「CSV データをダウンロードする」または「PDF をダウンロードする」というリンク、つまり HTML 以外のリンクをクリックしたことがある場合はContent-Typetext/html. Mechanize は非 html を Mechanize::Page オブジェクトに解析できないため、コンテンツを Mechanize::File オブジェクトにパッケージ化します。

Mechanize::File オブジェクトで何をするかは、何を達成しようとしているかによって異なります。たとえば、アクセスしたページが HTML ではなく CSV データであることがわかっている場合、次のように CSV データを抽出できます。

page = web_agent.get(some_url_that_references_csv_data)
parsed_csv = CSV.parse(page.body)

工夫を凝らしたい場合は、Mechanize が非 HTML 形式を処理できるようにする独自のパーサーを作成できます。そのルートに行きたい場合は、PlugableParser の Mechanize ドキュメントを参照してください。しかし、Mechanize::File オブジェクトを直接操作することで、多くのことを達成できます。

@ user741072 さんのコメントに対する補遺

一方、ページHTML であり、誰かが HTML に設定content-typeするのを怠った場合、ページを解析するのに十分な時間だけ、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

Web サイトが応答の一部としてコンテンツ タイプを返さない場合は、ポスト接続フックでコンテンツ タイプを自分で設定できます。

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ヘッダーの特定の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 に答える