我正在尝试从url获取这样的文件列表:
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.extract返回空字符串,即使我没有在其上调用select方法。有什么建议吗?
答案 0 :(得分: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 "Ü"
相等的编码。要么知道它,要么写一些Ruby:
Encoding.list.select { |e| "Ü" == "\xDC".encode!(Encoding::UTF_8, e) rescue next }.map(&:name)
当然,让程序进行猜测也是一种选择。有libguess库。 Web浏览器也可以这样做。但是你需要下载文件,除非服务器可能告诉浏览器它是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解析器才能获得最佳可靠性(可能还有一个gem)。这是一个应该做你想做的事的例子:
html.scan(/href="(.*?PL.*?)"/).flatten # => ["SI_PL_ACTIV_bicompact.pdf", ...]