精华 request 请求到的数据为乱码,求解决
发布于 9 年前 作者 shanelau 46011 次浏览 最后一次编辑是 8 年前 来自 问答

这个链接请求的数据结果乱码,求解决

http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746

在浏览器中打开是正确的,自己使用 request 模块,请求到的数据就是乱码, 不知道用的什么编码格式编码的 , 跪求指导怎么解码?

var request = require('request');
request('http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746', function (req,res,body) {
    console.log(body);
});
35 回复

设置gzip为true

var request = require('request');
request({url:'http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746',gzip:true}, function (err,response,body) {
        console.log(body);
});

还是我来回答把,楼上的我用了是不行的! 以后回答,请先自己测试

下面测试过可用:只是我换成了superagent

var request = require('superagent');
request
.get('http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746')
.end(function(res){
    console.log(res.body);
});

你可以把http的header打印出来看看返回的数据有没有经过gzip压缩,如果有压缩的话我得先解压缩。然后查看一下返回数据的编码, 在浏览器里直接访问返回数据好像是unicode编码,所以在接收到数据后最好使用birnary来接收,使用iconv转成utf8编码

@yaochun 一楼方法是可以的,你可能把unicode当成乱码了。

@ruanyl 我想LZ要的是和浏览器访问一样的正常的数据结构,而不是你说的【unicode】,这个有什么用?你能解码吗?

我也碰到过这种情况,取出来的内容是乱码。乱码的原因的话编码问题造成的,有的网页是utf-8,有的是gb2312。 我处理这个问题思路是这样的:把希望取出来的内容通过buffer = new Buffer(content)存进去,了解网页的编码模式, 然后用iconv-lite进行decode转码 可以试一下~~

@yessirpopesama 他这不是爬虫爬取,是直接api获取

@yaochun 如果你想看汉字,输出的那一句敲成:console.log(JSON.parse(body)); 不就好了?楼主问的是浏览器能看,但是用request看到的是乱码,这是因为用浏览器请求该url,因为Headers带有“Content-Encoding:gzip”,所以浏览器会decompress。你用浏览器能看到正常文本可能是因为你装了JSON Formatter一类的插件,不然你看到还是unicode。

但是楼主究竟问的是gzip的问题还是楼主想看正常文字,只有他自己知道了。你认为是楼主想看文字, 而@airyland 理解的是gzip。但你不能说人家的方法不行嘛,还怀疑人回答问题的态度。况且楼主的代码第一感觉是没有对gzip进行处理导致看到乱码的嘛。所以嘛,大家都是搬砖的,互相理解,互相学习嘛,我明显不能凭大脑强行解码Unicode的嘛。。

@ruanyl 我花点时间来回答一下你,混社区这么久没进前十也是一个十一,作为一个node一线老兵,遇到一个不容易

console.log(JSON.parse(body)); 

请问你实践过嘛?

我把代码给你:

var request = require('request');
request({url:'http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746',gzip:true}, function (err,response,body) {
        console.log(JSON.parse(body)); 
});

你难道看不到错误吗?

我们现在讨论的是在node下面来访问zhihu的这个接口,LZ希望直接看到我给出的答案的这个方式,直接是没有任何编码的正常的JSON,{json太大,有兴趣的CNoder可以使用以下我的方案看看}

var request = require('superagent');
request
.get('http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746')
.end(function(res){
    console.log(res.body);
});

而不是编码后的,如果你用request的gzip,那输出的body,我按照你的方式加了JSON.parse这样的,有用吗?

至于你说的:

你用浏览器能看到正常文本可能是因为你装了JSON Formatter一类的插件,不然你看到还是unicode。

这个和我的回答没有任何关系啊,亲,看看我们的场景~

你应该想的是当你在node下

var request = require('request');
request({url:'http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746',gzip:true}, function (err,response,body) {
       //这个body的转码问题?如何转?
});

当然你可能觉得我提供的方案并不是最佳的,因为很简单,我就是换了一个工具包-superagent,哈哈

我的观点是:希望回答至少是实践过的,并不是针对任何人,我也鼓励大伙踊跃帮助提问的人

找到原因之后。通过 urlencode2iconv-lite 肯定能解决乱码问题。

@ruanyl @yaochun 你们的解决方案其实是一回事。 楼主之所以看到了乱码,是因为没有 ungzip。request 需要手工指定,superagent 自动 ungzip 了。 至于 JSON.parse 的问题,来看一下代码

var request = require('request');
request({url:'http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746',gzip:true}, function (err,response,body) {
  console.log(typeof body); // => string
});

var request = require('superagent');
request
.get('http://zhuanlan.zhihu.com/api/columns/bigertech/posts/19885746')
.end(function(res){
  console.log(typeof res.body); // => object
});

在 request 库里面,body 是字符串,对应 superagent 的 res.text,superagent 里面的 body 其实是 JSON.parse(res.text)。body 只是方便调用者,省去调用 JSON.parse 而已。

@ruanyl @yaochun 在我这里,浏览器楼主的地址后,给出的源码长这样: untitled1.png

之所以里面有那些 \u 的东西,是因为知乎用 Python 开发,Python 对于内部字符串的存储形式就是 \uxxxx。因为 Python 2.x 默认不是支持 unicode 的,而 Python 3k 几乎没人用,所以存成那样保险。 我认为嘛,把楼主的问题解决到 \uxxxx 的形式就已经足够了,至于这个 \uxxxx 他怎么处理,他应该也懂得 JSON.parse 一下的。

@yaochun 别质疑我没测试过。LZ问题是乱码,我的代码我运行过已经正常了。 请问你觉运行我的代码不行是什么不行?

第一,我自己翻了下文档,写了代码,还测试过了。因此不要随便指责别人态度不对。 第二,解决到正常String已经算解决问题了,会JS的不会JSON.parse ?! 第三,你明明就是针对人,还在争辩中说不要针对人。哪来的道德高度?

看这里争论的这么开心,最后楼主跑出来说,其实我想问的是学习挖掘技术哪家强?:D

@airyland @yaochun @jinphen @jinphen @ruanyl @yessirpopesama 谢谢你们,问题已经解决了,确实是gzip压缩和解压的问题 。 不过你们好热闹,大家都是追求真理的人呐

我的chrome 确实安装了 json 自动转换工具, 所以在浏览器中 就能看到正确的 json格式

看了诸位道友的回答受益颇多,自己也动手尝试并总结了下: 1 request中如果不手动设置gzip的话显示的的确是乱码,加gzip参数后显示的便是unicode,想要看中文的话还是需要用json去parse下的。 2 superagent自带parseJson方法,内部做过处理。 3 我装的chrome是原版无插件的,浏览器看出来的就是unicode代码。诚如楼主所说能看到中文是装过json自动转换工具的。 4 我是路过度劫的~~

乱码解决 主要是为了这个 模块的, zhihu_module

@airyland , 太感谢你了,解决了我的大问题!

@itlodge 你是怎么解决乱码的问题的

@yaochun 爬虫取到的页面乱码这个怎么解决

@alsotang 问个问题,如果用request请求某个页面,它的content=“text/html; charset=gb2312” ,这边显示乱码,这种情况就不能正常爬取了,能解决吗

@ChrisFuck 先请求下来 Buffer, 也就是 request 的时候指定 encoding: null ,得到 Buffer, 用ASCII解码前一千个字符,用正则,匹配出 ; charset=(\w+)",得到正确的 charset, 再用 iconv-lite 解码出全部的 buff

@ChrisFuck 用 iconv-lite 转转码试试

@klesh 读 header 也靠谱的。

@alsotang header不一定有的,特别是静态资源

来自酷炫的 CNodeMD

@klesh 静态资源在没有 charset 的情况下,反而只能读 header。猜字符编码虽然也靠谱,但感觉不是正道。

@alsotang 我的意见正好跟你相反,meta 标签指定的 charset 是在制作时确定。而服务器只能是在运行时动态去检测,那么问题来了,作为服务器怎么检测html的charset,好像也只能检测 meta 了吧?但是事实上,它根本不检测,因为浪费服务器资源,还不如让客户端去做这种事情,所以是没有header头声明charset的。cnodejs.org 本身也是有用 nginx 的,你看下静态资源的 header,是没有指定 charset 的。 看下各种语言,从 js 文件,css文件到 asp/php 到 python 等等,都有相应的声明编码的标签,就是文件编码无法动态正确地检测只能通过声明的方式去解决。这几天好像在哪里看到有一篇讲BOM头的就有相关的论述……

header中指定charset据我观测只有动态资源才会这么做。

@klesh 确实,不过就一个网站来说,一般 charset 都是统一的。这个地方写死编码也挺好的,你觉得呢?

@alsotang 理想状态下是可以,可惜现实是残酷的。别的不说吧,某宁的 api ,正常情况下包括正确和错误是返回 utf-8 编码的 json 格式,有时候异常了。。。返回的是一个 gb2312 的 html 页面……

一个纯文本必须是有编码的,基于交换需要,其使用的编码必须由它自己声明才是合理的,抛开WINDOWS奇异的BOM头不讲(这玩意也就只能区分是不是utf8编码而已),*nix 是不提倡使用隐藏字节进行声明。因此各种格式的纯文本都有自己特定的声明编码的方式,而 html 的方式就是通过 meta 声明,所以我觉得通过 meta 中的 charset 进行判别才是正规的做法。

早期的IE(好久没用,新版本的情况不清楚),也是判定 META 的,所以若在 utf-8 meta 标签之前有出现中文,整个页面都会乱码掉,猜测它是流式向后查找,再加综合判定的方式进行处理编码的。

@ChrisFuck , 设置gzip为true

这个问题其实是因为使用了accept-encoding请求头 requset header: accept-encoding: gzip, deflate, br,浏览器告诉服务器支持的编码方式有gzip, deflate, br这三种 response header: content-encoding: br,服务器告诉浏览器用了 br 这种方式编码 然而request配置中加上gzip: true 只能解析gzip编码的,遇到谷歌首页优先使用br编码一样会乱码 所以最好的解决办法是在请求头中把 accept-encoding 去掉,这样返回内容就不会经过编码。

回到顶部