这个问题困扰了两三天,目前一步一步分析出来应该是解压的问题。请问此文件到底是什么解压方式?该如何通过工具解压?
文件示例: https://api.bilibili.com/x/v1/dm/list.so?oid=71163662
部分 Header:
Content-Encoding: deflate
Content-Type: text/xml
Transfer-Encoding: chunked
Accept-Encoding: gzip, deflate, br
最初:采用 Aria2 下载时,已添加 --http-accept-gzip,但依旧报错,incorrect header check
Exception: [AbstractCommand.cc:350] errorCode=1 URI=https://api.bilibili.com/x/v1/dm/list.so?oid=71163662 -> [GZipDecodingStreamFilter.cc:110] errorCode=1 libz::inflate() failed. cause:incorrect header check
已尝试的方法:
① curl -O url --compressed,成功解压,文件正常显示!唯一成功的途径。
② bandzip 为文件损坏,gzip 为 not in gzip format
③ fs.readFile('1.gz', function(err, data){ console.log(data) })
Buffer 94 bd 5b 73 5c 49 72 26 f8 57 30 78 18 d3 8c 38 47 e1 11 ee 1e 11 36 25 68 6a ba 5b 9a b5 51 4b 6d dd db 3b ad 7d 59 4b 24 12 dd 1c 75 b1 ca ea 22 55 ...
④ node.js:Gunzip/Inflate, Error: incorrect header check
const fs = require('fs'), zlib = require('zlib') fs.createReadStream('./1.gz').pipe(zlib.createGunzip()).pipe(fs.createWriteStream('1.xml')) console.log("文件解压完成。")
希望大家可以帮忙看看,感激不尽!
一打岔忘记备注了。问题已解决。
这个问题的原因有两点:
① B站返回的 deflate 不是标准的!而是 raw deflate,它没有被 zlib 包装,这是错误的。
② Aria2 软件问题。它不支持对于 raw deflate 的解压。
此问题出自我写 bilibili_video_download 时,下载视频同时下载弹幕,以及之后可更新弹幕的目标。
最终的解决方案:用 node.js 写了一个小型服务器,zlib.createInflateRaw(),同时完成了更新弹幕是累加(不删除旧弹幕)的目标。
更多内容请查看项目内的 CHANGELOG_Zh_CN.md 文件(7月20号附近)的记录,以及相关提交代码时的描述。相关文章:HTTP 协议中的 Content-Encoding,deflate——过时的网页压缩格式,最好禁用[转]
谢谢大家的帮助。
1
ztcaoll222 2019-07-15 08:24:25 +08:00
这不是个 xml 文件吗, 不能直接解析吗
|
2
mystrylw 2019-07-15 08:28:37 +08:00
+1 浏览器直接打开识别为 xml 了
|
3
evenIfAlsoGo OP @ztcaoll222 主要是想根据 URL 把文件下载下来用
|
4
evenIfAlsoGo OP @mystrylw 不通过浏览器,比如使用 aria2 进行下载
|
5
ztcaoll222 2019-07-15 08:35:58 +08:00
@evenIfAlsoGo #3 你下载下来的文件不能当 xml 解析吗
|
6
evenIfAlsoGo OP @ztcaoll222 直接 ctrl+s 是 xml,但是使用下载工具通过 URL 下载就不可以。忘记说明了:只通过 URL 下载下来的文件是 46K 左右,解压后可正常查看的文件是 114KB。
|
7
littlewing 2019-07-15 08:47:29 +08:00 via iPhone
header 不全
|
8
des 2019-07-15 08:50:20 +08:00 via Android 1
第一,curl 和浏览器能正常下载和打开,说明你的下载方式有问题
第二,not in gzip format 以及各种解压报错说明这个文件根本不是 gzip 文件,我不知道为啥你坚信这是个 gz 文件,不信你自己用 file 命令看看 第三,你也不熟悉 http,因为根本就不是压缩文件,那个压缩只是传输过程中的压缩,是透明的,不需要你处理。个人猜测是你把 Accept-Encoding: gzip, deflate, br 这个 header 复制进去了,然后 aria2 还不支持 |
9
littlewing 2019-07-15 08:51:29 +08:00 via iPhone
Accept-Encoding 头去掉
|
10
darlinghsu 2019-07-15 08:52:56 +08:00 1
油猴上 有关于 哔哩哔哩的脚本?/哔哩哔哩助手扩展程序 可以下载 xml 字幕 和 ass 字幕 可以看看
|
11
ztcaoll222 2019-07-15 08:52:59 +08:00 1
@evenIfAlsoGo #6
伪造个 ua 就可以了 |
12
des 2019-07-15 09:02:17 +08:00
@evenIfAlsoGo 抱歉,事先没有测试就妄下结论了,希望不要介意
|
13
expy 2019-07-15 09:03:22 +08:00 1
|
14
dingyx99 2019-07-15 09:14:47 +08:00
B 站弹幕不是 xml 嘛。。而且获取弹幕不是直接通过 comment.bilibili.com/aid.xml 就能直接拖下来的吗?
|
15
zsdroid 2019-07-15 09:20:06 +08:00 1
php 是世界上最好的语言
``` $url = 'https://api.bilibili.com/x/v1/dm/list.so?oid=71163662'; $data = file_get_contents($url); $data = gzinflate($data); var_dump($data); ``` |
16
lzvezr 2019-07-15 09:20:55 +08:00 via iPhone
用 nodejs 了为什么不直接用 request 模块呢
|
17
evenIfAlsoGo OP @littlewing 去掉也是的,采用 IDM 下载是相同的文件。可能是下载工具的原因,刚用其他工具下载,没有问题。可能是里面有 transfer-encoding: chunked,部分工具不支持。
|
18
evenIfAlsoGo OP @des 你说的基本没错,我的方向有错误,问题不是解压方式而是下载工具,这个过程应该不需要我 /用户的参与。不过我没有坚信它是 gzip,要不也不会问是什么方式。此处我的思路出现了矛盾,它本身是 chunked+gzip,我还问怎么解压干啥...一直看 gzip 迷了,而且觉得应该我来处理(当然多学一些也不错)。此外又刚才测试了其他工具,成功下载。
不过目前我对 HTTP 的理解确实不够扎实,谢谢你的回复。 |
19
evenIfAlsoGo OP @expy 对的,IDM 和 Aria2 可能不支持这种方式,所以导致这个问题的出现。并且我标题应该问如何用工具解析,而不是如何解压。
|
20
evenIfAlsoGo OP @dingyx99 需要通过下载工具和 URL 来下载,不采用浏览器的方式。获取弹幕这两个 API 都可以,目前网站采用的是 list.so?oid=cid 这个。
|
21
evenIfAlsoGo OP @zsdroid 哈哈,其实用 JS 的 XMLHttpRequest 也可以直接获取到内容(手动滑稽)
|
22
evenIfAlsoGo OP @lzvezr 因为我是导出所有下载链接的 URL,然后采用工具批量创建对应文件夹、重命名和下载的。具体你可以看看这个: https://github.com/evgo2017/bilibili_video_download
|
23
evenIfAlsoGo OP |
24
lzvezr 2019-07-15 10:57:12 +08:00 via iPhone
@evenIfAlsoGo 但是你说的这些 nodejs 都能做到啊
|
25
evenIfAlsoGo OP @lzvezr 是的,只是大部分用户应该不会直接使用 node.js ,所以需要选择适合的方案和下载工具(后续添加浏览器直接下载),考虑到用户体验就需要做的更多一些。
|
26
jinliming2 2019-07-15 12:05:04 +08:00 via iPhone
curl -I -XGET https://api.bilibili.com/x/v1/dm/li st.so?oid=71163662
HTTP/1.1 200 OK Date: Mon, 15 Jul 2019 04:01:06 GMT Content-Type: text/xml Transfer-Encoding: chunked Connection: keep-alive Bili-Trace-Id: 3c3183c3895d2bfa:3c3183c3895d2bfa:0:0 Content-Encoding: deflate Last-Modified: Mon, 15 Jul 2019 12:02:12 GMT X-Cache-Webcdn: BYPASS from cds-uswest-webcdn-v6-01 由此可知,他们不是用 gzip 压缩的,而是 deflate,你用 gunzip 解压当然失败! |
27
jinliming2 2019-07-15 12:11:53 +08:00 via iPhone 1
curl -I -XGET [ V 站禁止外链???] -H "Accept-Encoding: gzip"
HTTP/1.1 200 OK Date: Mon, 15 Jul 2019 04:06:30 GMT Content-Type: text/xml Transfer-Encoding: chunked Connection: keep-alive Bili-Trace-Id: d9c73fea75d2bfc:d9c73fea75d2bfc:0:0 Content-Encoding: deflate Last-Modified: Mon, 15 Jul 2019 12:07:36 GMT X-Cache-Webcdn: BYPASS from cds-uswest-webcdn-v6-01 由此可知,他们会忽略你给的 Accept-Encoding 头,固执的继续使用 deflate 压缩。 |
28
shansing 2019-07-15 12:34:21 +08:00
@jinliming2 我也注意到 Content-Encoding 是 deflate 了。但是这个能说是服务端忽略了 Accept-Encoding 头吗?因为 Accept-Encoding 中也包含了 deflate,所以也是没问题的吧。倒是优先级,不知道有没有问题,但肯定不是在前面的优先级高,因为 br 更高级,服务端实现一般会优先返回 brotli 压缩的内容,而它却是写在 Accept-Encoding 最后的。
|
29
Paladinfeng 2019-07-15 12:47:13 +08:00 1
你可以去 Github 搜一个项目叫 bilibili-api
/** * 弹幕文件解析器. * 弹幕文件(list.so)有三个部分 * 第一个部分为一个 Int, 表示第二部分的长度 * 第二部分为一个 Json, 标识各个弹幕的等级(用于屏蔽设置) * 第三部分为一个 gzip 压缩过的 xml * * Web 端的弹幕是一个明文 xml, 与 APP 的接口是不一样的. * * json 部分形如 {"dmflags":[{"dmid":12551893546958848,"flag":10}],"rec_flag":1,"rec_text":"开启后,全站视频将按等级等优化弹幕","rec_switch":1} * xml 部分形如 <d p="12509048833835076,0,117373,5,25,16777215,1551001292,0,d2c5fc5">硬核劈柴</d> * * @see com.hiczp.bilibili.api.danmaku.DanmakuAPI.list */ |
30
evenIfAlsoGo OP |
31
evenIfAlsoGo OP @Paladinfeng 好的,谢谢!
|
32
shansing 2019-07-15 13:20:51 +08:00 1
@evenIfAlsoGo 我尝试请求 Accept-Encoding 不包含 deflate 甚至要求不压缩都不成功,可能服务端放弃这些向下兼容的东西了。
|
33
evenIfAlsoGo OP @shansing 谢谢!
|
34
jinliming2 2019-07-16 01:21:28 +08:00 via iPhone 1
@shansing #28 看我的第二个回复,里面我指定了 Accept-Encoding 为 gzip 了,不包含 deflate,但服务器依旧以 deflate 进行回复,可见服务端是忽略这个头的……
|