我知道有很多文档和争论,但仍然是:
这是我在Rails上测试各种网站抓取数据的最佳尝试。奇怪的是,如果我手动复制粘贴URL的来源,一切都会正常进行。
我能做什么?
# encoding: utf-8
require 'rubygems'
require 'iconv'
require 'nokogiri'
require 'open-uri'
require 'uri'
url = 'http://www.website.com/url/test'
sio = open(url)
@cur_encoding = sio.charset
doc = Nokogiri::HTML(sio, nil, @cur_encoding)
txtdoc = doc.to_s
# 1) String manipulation test
p doc.search('h1')[0].text # "Nove36 "
p doc.search('h1')[0].text.strip! # nil <- ERROR
# 2) Regex test
# txtdoc = "test test 44.00 € test test" # <- THIS WORKS
regex = "[0-9.]+ €"
p /#{regex}/i =~ txtdoc # integer expected
我意识到,也许我的操作系统Ubuntu加上我的文本编辑器正在进行一些很好的编码转换,而不是一些损坏的编码:这很好,但我如何在实时运行的同时在我的应用程序上解决这个问题?
@cur_encoding=doc.encoding#ISO-8859-15
ISO-8859-15不是引用页面的正确编码;它应该是UTF-8。将其图标化为UTF-8,就好像它是8859-15一样,这只会加剧问题。
此编码来自文档中有故障的<meta>
标记。浏览器将忽略该标记,并使用Content-Type: text/html;charset=utf-8
HTTP响应标头中的重写编码。
然而,Nokogiri似乎无法从open()
ed流中读取此标头。需要注意的是,我对Ruby一无所知,从源代码来看,问题似乎是它使用了字符串或IO中的属性encoding
,而不是open-uri
所写的charset
。
你可以传入自己的覆盖编码,所以我想试试:
sio= open(url)
doc= Nokogiri::HTML.parse(doc, nil, sio.charset) # should be UTF-8?
您遇到的问题是由页面中的非中断空格字符(Unicode U+00A0)引起的。
在你的第一个问题中,字符串:
"Nove36 "
实际上以U+00A0结尾,String#strip!
不认为这个字符是要删除的空白:
1.9.3-p125 :001 > s = "Foo u00a0"
=> "Foo "
1.9.3-p125 :002 > s.strip
=> "Foo " #unchanged
在第二个问题中,价格和欧元符号之间的空间再次是一个不间断的空间,因此正则表达式根本不匹配,因为它正在寻找一个正常的空间:
# s as before
1.9.3-p125 :003 > s =~ /Foo / #2 spaces, no match
=> nil
1.9.3-p125 :004 > s =~ /Foo / #1 space, match
=> 0
1.9.3-p125 :005 > s =~ /Foo u00a0/ #space and non breaking space, match
=> 0
当您复制和粘贴源时,浏览器可能会对非打断空间进行规范化,因此您只复制正常的空间字符,这就是它以这种方式工作的原因。
最简单的修复方法是在开始处理之前对空间进行u00a0
的全局替换:
sio = open(url)
@cur_encoding = sio.charset
txt = sio.read #read the whole file
txt.gsub! "u00a0", " " #global replace
doc = Nokogiri::HTML(txt, nil, @cur_encoding) #use this new string instead...