私は最近、Ruby で Mechanize gem を使用してスクレイパーを作成しています。残念ながら、私がスクレイピングしようとしている URL は、リクエストに対してMechanize::File
オブジェクトではなくオブジェクトを返します。Mechanize::Page
GET
理由がわかりません。私が試した他のすべての URL は、Mechanize::Page
オブジェクトを返しました。
Page
Mechanize にオブジェクトを返させる方法はありますか?
これが何が起こっているかです。
「通常の」Web ページをダウンロードすると、そのヘッダーには次のようなフィールドが含まれますContent-Type text/html
。Mechanize はこれを確認すると、ページ コンテンツを HTML として解釈し、リンクやフォームなどを備えた Mechanize::Page オブジェクトに解析します。
しかし、「CSV データをダウンロードする」または「PDF をダウンロードする」というリンク、つまり HTML 以外のリンクをクリックしたことがある場合はContent-Type
、text/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 オブジェクトを直接操作することで、多くのことを達成できます。
一方、ページが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
それがうまくいくかどうか教えてください。
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
}
}
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
このアプローチは、要求されたリソースをとにかく「ダウンロード」するため、はるかに遅くなることに注意してください。ただし、後で使用するためにファイルを保存する場合に役立つことがあります。