2011-07-02 13 views
2

私はNokogiriを使用して、各国のWikipediaのページを開き、インターウィキのリンク(外国語のウィキペディアへのリンク)から他の言語でこれらの国の名前を抽出しています。しかし、the page for Franceを開こうとすると、Nokogiriはフルページをダウンロードしません。たぶんそれは大きすぎますが、とにかく私が必要とするインターウィキのリンクが含まれていません。どうすればそれを強制的にダウンロードすることができますか?なぜノコギリはフルページを読み込まないのですか?

は、ここに私のコードです:

url = "http://en.wikipedia.org/wiki/" + country_name 
page = nil 
begin 
    page = Nokogiri::HTML(open(url)) 
rescue OpenURI::HTTPError=>e 
    puts "No article found for " + country_name 
end 

language_part = page.css('div#p-lang') 

テスト:

with country_name = "France" 
=> [] 

with country_name = "Thailand" 
=> really long array that I don't want to quote here, 
    but containing all the right data 

たぶんこの問題は鋸山を超えてOpenURIに入る - とにかく私は、解決策を見つける必要があります。問題を傷つけヘッドのかなり後

+0

open()はNokogiriではありませんか? –

答えて

9

鋸山は、ページを取得しません、それはオープンStringIOオブジェクトに内部readでそれを行うためにOpenURIを頼む:: URIを返します。

require 'open-uri' 
require 'zlib' 

stream = open('http://en.wikipedia.org/wiki/France') 
if (stream.content_encoding.empty?) 
    body = stream.read 
else 
    body = Zlib::GzipReader.new(stream).read 
end 

p body 

ここであなたがOFFキーことができるものだ。それは[]、AKA "text/htmlの" ですこの場合には

>> require 'open-uri' #=> true 
>> open('http://en.wikipedia.org/wiki/France').content_encoding #=> ["gzip"] 
>> open('http://en.wikipedia.org/wiki/Thailand').content_encoding #=> [] 

、それが読み込まれます。それが["gzip"]なら、それはデコードします。再び軌道にあなたを取得する必要があります

require 'nokogiri' 
page = Nokogiri::HTML(body) 
language_part = page.css('div#p-lang') 

:上記のすべてのものをやってそれを投げ

。あなたは二つの異なる結果を見た理由について

p language_part.text.gsub("\t", '') 

参照キャスパーの回答とコメント:

は、視覚的にあなたが使用可能なものを取得している確認するために上記のすべての後にこれを行います。もともと、Open-URIは返されたデータの処理が一貫していなかったようだが、Casperが言ったことと、curlを使って見たものに基づいて、Wikipediaは大きな文書の "Accept-Encoding"ヘッダを守り、gzipを返す。これは今日のブラウザではかなり安全ですが、エンコードを自動的に検出しないOpen-URIのようなクライアントには問題があります。上記のコードは修正するのに役立ちます。

+0

ありがとうございます。私はこれを実装し、今私はデータを取得しています。唯一の問題は、Unicodeの国名が正しく表示されないことです。 g。私はフランスのヒンディー語の名前としてα1½α╝αÑìαñ°αñαααααιαを得ています。これは、gzipでエンコードされた名前の問題に過ぎず、他は自動的に正しいものです。何か案が? – Sprachprofi

+0

気にしないで、わかりました。ちょうどpage = Nokogiri :: HTML(body、nil、 'UTF-8')を代わりに使ってください。 – Sprachprofi

+0

"UTF-8"と仮定するのではなく、レスポンスの 'external_encoding'メソッドを使いたいかもしれません。一貫して1つのサイトを持つUTF-8がかなり安全だと仮定しますが、複数のサイトを見ていると、互換性のないエンコードを取得する可能性があります。ちょうど考慮すべき何か。 –

0

はここにある:

> wget -S 'http://en.wikipedia.org/wiki/France' 
Resolving en.wikipedia.org... 91.198.174.232 
Connecting to en.wikipedia.org|91.198.174.232|:80... connected. 
HTTP request sent, awaiting response... 
    HTTP/1.0 200 OK 
    Content-Language: en 
    Last-Modified: Fri, 01 Jul 2011 23:31:36 GMT 
    Content-Encoding: gzip <<<<------ BINGO! 
    ... 

あなたはオープン-URIが自動的に行いませんgzip圧縮されたデータを、解凍する必要があります。
ソリューション:

def http_get(uri) 
    url = URI.parse uri 

    res = Net::HTTP.start(url.host, url.port) { |h| 
    h.get(url.path) 
    } 

    headers = res.to_hash 
    gzipped = headers['content-encoding'] && headers['content-encoding'][0] == "gzip" 
    content = gzipped ? Zlib::GzipReader.new(StringIO.new(res.body)).read : res.body 

    content 
end 

そして:

page = Nokogiri::HTML(http_get("http://en.wikipedia.org/wiki/France")) 
+0

実際、Open :: URIはgzipをデコードしますが、特定のサイズのページではそうです。 Wikipediaのすべての結果はgzippedですが、フランスのページはデコードされません。より小さなタイのページがデコードされます。 –

+0

私のマシンではありません。タイは私がそれを要求するときgzipされていません。あなたの場所や、あなたがヒットしたウィキペディアサーバーに依存しているようです。 wget -Sではタイは私のためにgzipされていません。また、open-uriのコードを見ると、パックされたページを解凍する場所を見つけることができませんでした。 – Casper

+0

上記の私の答えを参照してください。 –

0
require 'open-uri' 
require 'zlib' 

open('Accept-Encoding' => 'gzip, deflate') do |response| 
    if response.content_encoding.include?('gzip') 
    response = Zlib::GzipReader.new(response) 
    response.define_singleton_method(:method_missing) do |name| 
     to_io.public_send(name) 
    end 
    end 

    yield response if block_given? 

    response 
end 
関連する問題