使用R包在使用特殊字符的页面上编码错误

时间:2014-08-05 00:14:15

标签: r web-scraping

我一直在使用httr抓取网页,并将结果存储在data.frame中,df e.g

library(httr)
urlPage <-"http://www.theguardian.com/commentisfree/cartoon/2014/aug/04/ben-jennings-cartoon-first-world-war-centenary"
pagehtml <- content(GET(urlPage),"parsed")
title <- xpathSApply(pagehtml, "//*/div[@id='main-article-info']/h1", xmlValue)

此示例导致df$title变量中的值 “本·詹宁斯在第一次世界大战一百周年之际—卡通“

我现在意识到我可以通过不同的方法来避免使用特殊字符的这个问题

library(XML)
pagehtml <- htmlParse(urlPage, isURL = TRUE,encoding='UTF-8')
title <- xpathSApply(pagehtml, "//*/div[@id='main-article-info']/h1", xmlValue)

导致“本·詹宁斯在第一次世界大战一百周年 - 卡通”的理想结果

所以我知道从现在开始该做什么,但希望纠正我已收集的数据。我试过了

Encoding(title) <-"UTF-8"

但没有效果

任何帮助非常感谢

响应请求使用bad_title和good_title进行编辑。在我的Windows机器上

charToRaw(good_title)
 [1] 42 65 6e 20 4a 65 6e 6e 69 6e 67 73 20 6f 6e 20 74 68 65 20 63 65 6e 74 65 6e 61     72 79 20 6f 66
[33] 20 74 68 65 20 66 69 72 73 74 20 77 6f 72 6c 64 20 77 61 72 20 e2 80 93 c2 a0 63 61 72 74 6f 6f
[65] 6e

charToRaw(bad_title)
 [1] 42 65 6e 20 4a 65 6e 6e 69 6e 67 73 20 6f 6e 20 74 68 65 20 63 65 6e 74 65 6e 61 72 79 20 6f 66
[33] 20 74 68 65 20 66 69 72 73 74 20 77 6f 72 6c 64 20 77 61 72 20 c3 a2 c2 80 c2 93 c3 82 c2 a0 63
[65] 61 72 74 6f 6f 6e

1 个答案:

答案 0 :(得分:0)

这似乎是一个非常混乱的问题。所以,为了确保我们查看完全相同的字节,这些是我对数据的表示

title_good <- enc2utf8(rawToChar(as.raw(c(0x42, 0x65, 0x6e, 0x20, 0x4a, 0x65, 
0x6e, 0x6e, 0x69, 
0x6e, 0x67, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 
0x63, 0x65, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x6f, 
0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 
0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x77, 0x61, 0x72, 0x20, 
0xe2, 0x80, 0x93, 0xc2, 0xa0, 0x63, 0x61, 0x72, 0x74, 0x6f, 0x6f, 
0x6e))))

title_bad <- enc2utf8(rawToChar(as.raw(c(0x42, 0x65, 0x6e, 0x20, 0x4a, 0x65, 
0x6e, 0x6e, 0x69, 
0x6e, 0x67, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 
0x63, 0x65, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x6f, 
0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 
0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x77, 0x61, 0x72, 0x20, 
0xc3, 0xa2, 0xc2, 0x80, 0xc2, 0x93, 0xc3, 0x82, 0xc2, 0xa0, 0x63, 
0x61, 0x72, 0x74, 0x6f, 0x6f, 0x6e))))

所以问题是数据实际编码为UTF-8但是解析器假设它是ISO-8859-1然后它被翻译成UTF-8。您可以使用

从良好版本重新创建错误版本
iconv(title_good, "ISO-8859-1", "UTF-8")
# [1] "Ben Jennings on the centenary of the first world war â\u0080\u0093 cartoon"

所以问题是在转换过程中,新的字节是通过编码操作似乎不可逆的方式创建的。我找不到iconv正在使用的确切代码,但是从您提供的测试数据中,似乎将较大的字符代码&gt; = 128分成多字节代码,这些代码无法正确转换为UTF代码。如果我们查看二进制表示中的数据位,基本上它似乎通过

进行转换
AABB BBBB  ->  1100 00AA  10BB BBBB

其中AA和BBBBBB是1和0的序列

这是一个似乎扭转过程的函数

revenc<-function(x) {
    cc <- as.numeric(charToRaw(x))
    w<-matrix(which(cc>=128), byrow=T, ncol=2)
    nc<-apply(w, 1, function(x) {bitwShiftL(bitwAnd(cc[x[1]], 3), 6) +
        bitwAnd(cc[x[2]], 63)})
    pp<-rawToChar(as.raw(c(cc[-w], nc)[order(c(seq_along(cc)[-w], w[,1]))]))
    Encoding(pp)<-"UTF-8"
    pp
}

revenc(title_bad)
# [1] "Ben Jennings on the centenary of the first world war – cartoon"