2015-07-28 56 views
0

我想要得到的文件列表從URL像這樣無效的字節序列:紅寶石URI.extract返回空數組或引發ArgumentError:在UTF-8

require 'uri' 
    require 'open-uri' 

    url = 'http://www.wmprof.com/media/niti/download' 
    html = open(url).read 
    puts URI.extract(html).select{ |link| link[/(PL)/]} 

此代碼返回引發ArgumentError:無效字節序列在UTF-8符合URI.extract(即使html.encoding返回UTF-8)

我已經找到了一些解決方案,以編碼的問題,但是當我改變代碼

html.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?') 

URI.ext即使我沒有調用select方法,ract也會返回空字符串。有什麼建議麼?

+0

@cremno感謝,但它不工作,迫使ISO-8859-1編碼,然後轉碼爲UTF-8提取仍返回空數組後。另外爲了將來的參考 - 你從哪裏得到的信息,該網站的編碼是ISO-8859-1?它不在文檔頭部,正如上面提到的'html.encoding'返回utf-8。 –

回答

0

該網站的字符編碼可能是ISO-8859-1或相關的一個。我們無法確定,因爲只有兩次出現相同的非US-ASCII字符,反正也無關緊要。

html.each_char.reject(&:ascii_only?) # => ["\xDC", "\xDC"] 

尋找實際的編碼是通過猜測完成的。 HTML 3.2的年齡或使用的語言可能是一個線索。在這種情況下,特別是PDF文件的內容是有幫助的(它包含SPRÜH-EX和該文件的名稱爲TI_DE_SPR%dcH_EX.pdf)。那麼我們只需要找到"\xDC" and "Ü"相等的編碼。要麼知道它或寫一些紅寶石:

Encoding.list.select { |e| "Ü" == "\xDC".encode!(Encoding::UTF_8, e) rescue next }.map(&:name) 

當然,讓程序做猜測也是一個選項。有libguess圖書館。網絡瀏覽器也可以做到這一點。但是,您需要下載文件,除非服務器可能會告訴瀏覽器它是UTF-8,即使它不是(例如在這種情況下)。任何體面的文本編輯器也會嘗試檢測文件編碼:例如ST3認爲它是Windows 1252,它是ISO-8859-1的超集(如UTF-8是US-ASCII)。

可能的解決方案是本字符串編碼手動設置爲ISO-8859-1:

html.force_encoding(Encoding::ISO_8859_1) 

或者(優選地)從代碼轉換ISO-8859-1爲UTF-8串:

html.encode!(Encoding::UTF_8, Encoding::ISO_8859_1) 

要回答其他問題:URI.extract不是您正在查找的方法。顯然它已經過時了,更重要的是它不提取相關的URI。

一個簡單的選擇是使用正則表達式與String#scan。它適用於這個網站,但它可能不與其他網站。您必須使用HTML解析器才能獲得最佳可靠性(這可能也是一種寶石)。下面是應該做你想做的一個例子:

html.scan(/href="(.*?PL.*?)"/).flatten # => ["SI_PL_ACTIV_bicompact.pdf", ...] 
+0

謝謝,使用'字符串#掃描'和修改後的正則表達式而不是'URI.extract'可以正常工作,因爲我現在需要的只是PL文件的名稱。 –