我在Ruby(1.9)中编写了一个爬虫程序,它从很多随机站点中消耗了大量的HTML
在尝试提取链接时,我决定只使用.scan(/href="(.*?)"/i)
而不是nokogiri / hpricot(主要加速)。问题是我现在收到很多“invalid byte sequence in UTF-8
”错误
根据我的理解,net/http
库没有任何特定于编码的选项,并且进入的内容基本上没有正确标记。
实际使用传入数据的最佳方法是什么?我尝试使用替换和无效选项设置.encode
,但到目前为止没有成功......
答案 0 :(得分:170)
在Ruby 1.9.3中,可以使用String.encode来“忽略”无效的UTF-8序列。这是一个可在1.8(iconv)和1.9(String#encode)中使用的代码段:
require 'iconv' unless String.method_defined?(:encode)
if String.method_defined?(:encode)
file_contents.encode!('UTF-8', 'UTF-8', :invalid => :replace)
else
ic = Iconv.new('UTF-8', 'UTF-8//IGNORE')
file_contents = ic.iconv(file_contents)
end
或者如果您输入真的很麻烦,可以从UTF-8到UTF-16再转换为UTF-8进行双重转换:
require 'iconv' unless String.method_defined?(:encode)
if String.method_defined?(:encode)
file_contents.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '')
file_contents.encode!('UTF-8', 'UTF-16')
else
ic = Iconv.new('UTF-8', 'UTF-8//IGNORE')
file_contents = ic.iconv(file_contents)
end
答案 1 :(得分:78)
接受的答案或其他答案对我有用。我找到了建议的this post
string.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
这解决了我的问题。
答案 2 :(得分:23)
我目前的解决方案是运行:
my_string.unpack("C*").pack("U*")
这至少可以摆脱我的主要问题
答案 3 :(得分:8)
试试这个:
def to_utf8(str)
str = str.force_encoding('UTF-8')
return str if str.valid_encoding?
str.encode("UTF-8", 'binary', invalid: :replace, undef: :replace, replace: '')
end
答案 4 :(得分:4)
我建议您使用HTML解析器。找到最快的一个。
解析HTML并不像看起来那么容易。
浏览器在UTF-8 HTML文档中解析无效的UTF-8序列,只需添加“ ”符号。因此,一旦HTML中的无效UTF-8序列被解析,结果文本就是一个有效的字符串。
即使在属性值内,您也必须解码HTML实体,如放大器
这是一个很好的问题,总结了为什么你不能用正则表达式可靠地解析HTML: RegEx match open tags except XHTML self-contained tags
答案 5 :(得分:3)
这似乎有效:
def sanitize_utf8(string)
return nil if string.nil?
return string if string.valid_encoding?
string.chars.select { |c| c.valid_encoding? }.join
end
答案 6 :(得分:3)
attachment = file.read
begin
# Try it as UTF-8 directly
cleaned = attachment.dup.force_encoding('UTF-8')
unless cleaned.valid_encoding?
# Some of it might be old Windows code page
cleaned = attachment.encode( 'UTF-8', 'Windows-1252' )
end
attachment = cleaned
rescue EncodingError
# Force it to UTF-8, throwing out invalid bits
attachment = attachment.force_encoding("ISO-8859-1").encode("utf-8", replace: nil)
end
答案 7 :(得分:2)
我遇到过字符串,它混合了英语,俄语和其他一些字母,导致异常。我只需要俄语和英语,这对我来说很有用:
ec1 = Encoding::Converter.new "UTF-8","Windows-1251",:invalid=>:replace,:undef=>:replace,:replace=>""
ec2 = Encoding::Converter.new "Windows-1251","UTF-8",:invalid=>:replace,:undef=>:replace,:replace=>""
t = ec2.convert ec1.convert t
答案 8 :(得分:1)
虽然Nakilon的解决方案有效,至少就错过了错误,在我的情况下,我有一个奇怪的f-ed up字符源自Microsoft Excel转换为CSV,在ruby中注册为(得到这个)西里尔字母在红宝石中的K是一个粗体K.为了解决这个问题,我用'iso-8859-1'即可。 CSV.parse(f, :encoding => "iso-8859-1")
,这使我的怪异的dehy西里尔文K变成了一个更易于管理的/\xCA/
,然后我可以使用string.gsub!(/\xCA/, '')
删除
答案 9 :(得分:0)
在使用scan
之前,请确保所请求页面的Content-Type
标题为text/html
,因为可能存在指向未以UTF-8编码的图像等内容的链接。如果您在href
元素之类的内容中选择<link>
,该页面也可能是非HTML格式的。如何检查这取决于您使用的HTTP库。然后,确保结果只是ascii String#ascii_only?
(不是UTF-8,因为HTML只应该使用ascii,否则可以使用实体)。如果这两个测试都通过,则使用scan
是安全的。
答案 10 :(得分:-1)
如果您不“关心”数据,您可以执行以下操作:
search_params = params[:search].valid_encoding? ? params[:search].gsub(/\W+/, '') : "nothing"
我刚用valid_encoding?
来传递它。我是一个搜索领域,所以我一遍又一遍地发现同样的怪异所以我使用了类似的东西:只是为了让系统不破坏。由于我在发送此信息之前不会将用户体验控制为autovalidate(如自动反馈说“虚拟!”),我可以将其取出,将其删除并返回空白结果。