如何保存一些网络广播

近来一直有在网上听一些动画的广播以及网络广播。而因为广播每周都有放送,如果错过了这周,下一周就没得再听了(有些可以付费重新听,相当于不可能再听了)。那么本周的广播其实可以先保存下来,等到有时间的时候再听。经过了一段时间的摸索,的确摸到了一些门路,于是总结一下整个流程的技术。这些广播实质上就是一些网络媒体,和平常在音乐网站听音乐等其实是一样的,因此这些获取方法应该也基本适用。

  1. 边用边分析——響篇
  2. 提取媒体位置——響篇
  3. 使用特定的工具
  4. 另一个例子——音泉篇
  5. 使用插件或工具下载
  6. 编写脚本
  7. 福利

边用边分析——響篇

下面以我经常去的 響 - HiBiKi Radio Station - 为例子。

打开网站。

网站状况

大概浏览一下整个页面,可以看到分成几个区域,新闻区、播放器区、节目列表区、广告区。

分区

新闻区会更新广播的信息,一般是得知新广播推出的来源。

播放器区,这个是重点。一般看播放器就大概知道获取广播的难度。

节目列表区,这种涉及和网站交互的区域是搞懂网站架构的好地方。

广告区,并非没用,有时会出现一些新广播或者新广播站的消息。

随便点一个广播,就这个吧,妹ちょ。らじお。

按 F12 打开 chrome 的开发者工具。什么?你不是在用 chrome?那你自己看着办。

开发者工具

来看看控制台输出了什么?(红色的是资源获取失败,是我的网络原因,可以忽略)

看起来是一些调试信息。这应该不是 javascript 输出的信息,一般 js 代码输出的信息在右边会有代码行数提示。

看到两行比较感兴趣的输出:

  1. connectiong Stream->rtmpe://cp209391.edgefcs.net/ondemand/
  2. DetailsLoad->urlhttp://image.hibiki-radio.jp/uploads/data/channel/imocyo/description.xml

第一个有单词 stream,而且后面的网址使用 rtmpe 协议。(什么协议,我没看过……)

第二个看到一个 xml 文件位置,url 中有 imocyo,是广播题目妹ちょ的罗马拼写,看来就是跟广播有关的东西,点进去看看。

可以看到这么一些 xml 文件内容。

1
2
3
4
5
6
7
8
9
10
11
<data>
<title > 妹ちょ。らじお</title>
<cast>
<name > 橋本ちなみ</name>
<name > 金元寿子</name>
</cast>
<outline>
絶賛放送中の TV アニメ『最近、妹のようすがちょっとおかしいんだが。』のラジオ番組! 神前美月役の橋本ちなみさんと桐谷雪那役の金元寿子さんが番組を担当。 第 5 回より「妹ちょ。らじお」は毎週土曜日の更新へ変更となります。 ラジオ大阪 OBC [1314kHz]では毎週金曜日 24 時 30 分~25 時にて放送!
</outline>
<link>http://hibiki-radio.jp/description/imocyo</link>
</data>

看起来就是一些配置信息。

回头再来看首页的播放器,右边的是不是就是 xml 文件里面的内容啊?看来这个 xml 就是播放器请求的了。

顺手右击一下播放器,看看弹出的菜单。嗯,看来是 flash 了,可能就比较麻烦了。

播放器信息

为什么说是 flash 就比较麻烦呢?因为 flash 作为组件,内部是对浏览器屏蔽的,也就是说它搞了什么,浏览器基本是不清楚的,包括它向哪里请求了什么。通常情况下,flash 请求的是流媒体,很多是没有缓存的。

比较幸运的是这个 flash 自己输出了一些调试信息,也算有迹可寻。

如果连控制台输出都没有,那怎么办呢?其中一种方法是可以用硕思闪客精灵反汇编这个 flash 的 swf 文件,在文件内部找 url。这个方法可能涉及到版权或法律问题,就不在这叙述。另外一种方法操作上比较难,就是监听网卡。这个算是终极手段,因为所有的网络进出信息都可以捕捉到,但是技术要求也是最高的(我自己尝试过,收获不多就另辟蹊径了)。

ok,现在保持控制台打开的状况,点击播放。

听到了橋本ちなみ和金元寿子的声音。

再看控制台,哦真给力,呕吐一样输出一堆东西。

播放时输出

显然最有用的就是那一行。

1
stream->mp4:140614_imocyo_140614_imocyo.mp4?di=910&si=609&pi=2806&gi=6498&gc=6&bi=57971&bc=imocyo&ei=717045&ec=140614_imocyo&vi=4102269&vc=140614_imocyo&msi=516&mc=&ni=1625?1405751016018

一看到 mp4,感觉已经摸到了这个资源了,而且名字很明显是 140614_imocyo_140614_imocyo.mp4,后面的形似? xx=xxx&xx=xxx 的东西是一些请求的参数。

这名字,一看就知道格式是:日期_名字_日期_名字_.mp4,也就是说 14 年 6 月 14 日的妹ちょ广播。这些信息说不定有用,先记录下来。

尝试和前面的网址结合起来得到 cp209391.edgefcs.net/ondemand/140614_imocyo_140614_imocyo.mp4,放到地址栏访问一下,啥都没有。嗯,预料之内,有可能是协议问题,也有可能是路径不对。

上网搜索一下 rtmpe 协议,发现叫实时消息传送协议协议,是 Adobe 公司的(好吧又是你)。搜索出来的结果基本都是有关怎么下载这些协议的流媒体的。基本就是介绍什么软件什么软件的,个人比较讨厌这些使用乱七八糟软件的方法,而且基本也是不凑效的。

将关键字改为 download rtmpe 一搜,发现一个 rtmpdump 的命令行工具,声称通杀这类协议。但是一看文档,嗯,暂时不想深究。看看有没有其他方法吧。

留意到播放器里面有个“详细”,点击一下跳转到一个网页 http://hibiki-radio.jp/description/imocyo

节目页

看来就是个节目的详细介绍页面,估计网址格式是:hibiki-radio.jp/description / 节目名字

拉到最下面,终于发现突破口!

WMP

提取媒体位置——響篇

页面中内嵌了一个 WMP(Windows Media Player)组件,虽然这个也是跟 flash 一样的组件,但是并没有 flash 那样让人讨厌。根据我的经验,WMP 播放的媒体是可以手动提取的。现在就来试试。

打开开发者工具,审查这个插件元素,可以看到是一个 <embed> 标签,属性 src 就是一个网址 http://www2.uliza.jp/IF/WMVDisplay.aspx?clientid=910&playerid=2869&episodeid=140614_imocyo&videoid=140614_imocyo-wm&vid=4102271&memberid=&membersiteid=516&nickname=&sex=&birthday=&local=&mode=1

嵌入

点击访问发现下载了一个文件 140614_imocyo-wm.asx

用记事本打开,内容如下:

1
<ASX version = "3.0"><entry><title>[毎]140614_妹ちょ。らじお #23</title><Ref href ="mms://wms.uliza.jp/uliza/910/140614_imocyo_140614_imocyo-wm.wma"/></entry></ASX>

出来了!看到那个 mms://wms.uliza.jp/uliza/910/140614_imocyo_140614_imocyo-wm.wma 了吗?wma 就是一个音乐文件。mms 协议的文件是能够使用迅雷来下载的。Mission completed.

使用特定的工具

在分析的时候不是发现了一个叫 rtmpdump 的命令行工具吗?现在来看看怎么使用。

尝试以各种关键字组合起来搜索,比如 download rtmpe mp4how to downlaod rtmpe with rtmpdump……

最后得到一个可用的命令:rtmpdump -r "rtmpe://cp209391.edgefcs.net/ondemand/" -y "mp4:140614_imocyo_140614_imocyo" -o test.flv

可以看到,其实就是组合了一直分析下来的网址。下图就是正在下载的窗口。

rtmp 下载

Boom! 这可比乱七八糟的软件好用多了。

另一个例子——音泉篇

现在再来看另外一个例子,另一个广播比较多的网站,音泉

先看一下网站,嗯比 hibiki 好看多了。

音泉整站

网站的区域分布也跟 hibiki 大同小异。播放器也是 flash。

音泉播放

播放之后看不到什么输出,只是看到一个请求:http://www.onsen.ag/data/api/getMovieInfo/aldnoah?callback=callback&_=1405758148110

可以看得出格式是:www.onsen.ag/data/api/getMovieInfo / 节目名字。后面的参数是代码回调和当前的时间。

直接访问这个网址,得到:

1
callback({"type":"sound","thumbnailPath":"\/program\/aldnoah\/image\/128_pgi01_m.jpg","moviePath":{"pc":"http:\/\/onsen.b-ch.com\/radio\/aldnoah140712Zf8j.mp3","iPhone":"http:\/\/onsen.b-ch.com\/radio\/aldnoah140712Zf8j.mp3","Android":"http:\/\/onsen.b-ch.com\/radio\/aldnoah140712Zf8j.mp3"},"title":"\u30a2\u30eb\u30c9\u30ce\u30a2\u30fb\u30e9\u30b8\u30aa","personality":"\u96e8\u5bae\u5929\uff08\u30a2\u30bb\u30a4\u30e9\u30e0\u30fb\u30f4\u30a1\u30fc\u30b9\u30fb\u30a2\u30ea\u30e5\u30fc\u30b7\u30a2 \u5f79\uff09 \/ \u6c34\u702c\u3044\u306e\u308a\uff08\u30a8\u30c7\u30eb\u30ea\u30c3\u30be \u5f79\uff09","guest":"","update":"2014.7.12","count":"03","schedule":"\u6bce\u9031\u571f\u66dc\u65e524:30\uff5e\u66f4\u65b0","optionText":"\u30a2\u30cb\u30d7\u30ec\u30c3\u30af\u30b9","mail":"[email protected]","copyright":"\u00a9Olympus Knights\uff0fAniplex\u30fbProject AZ","url":"aldnoah","link":[],"recommendGoods":[],"recommendMovie":[{"imagePath":"\/program\/gochiusa\/image\/34_pgi01_b.jpg","url":"\/program\/gochiusa\/"}],"cm":[],"allowExpand":"false"});

就是个 json 而已,上 jsnice 整理一下得:

1
2
3
4
5
6
7
8
9
10
11
12
callback({
"type" : "sound",
"thumbnailPath" : "/program/aldnoah/image/128_pgi01_m.jpg",
"moviePath" : {
"pc" : "http://onsen.b-ch.com/radio/aldnoah140712Zf8j.mp3",
"iPhone" : "http://onsen.b-ch.com/radio/aldnoah140712Zf8j.mp3",
"Android" : "http://onsen.b-ch.com/radio/aldnoah140712Zf8j.mp3"
},
"title" : "\u30a2\u30eb\u30c9\u30ce\u30a2\u30fb\u30e9\u30b8\u30aa",
"personality" : "\u96e8\u5bae\u5929\uff08\u30a2\u30bb\u30a4\u30e9\u30e0\u30fb\u30f4\u30a1\u30fc\u30b9\u30fb\u30a2\u30ea\u30e5\u30fc\u30b7\u30a2 \u5f79\uff09 / \u6c34\u702c\u3044\u306e\u308a\uff08\u30a8\u30c7\u30eb\u30ea\u30c3\u30be \u5f79\uff09",
"guest" : "","update":"2014.7.12","count":"03","schedule":"\u6bce\u9031\u571f\u66dc\u65e524:30\uff5e\u66f4\u65b0","optionText":"\u30a2\u30cb\u30d7\u30ec\u30c3\u30af\u30b9","mail":"[email protected]","copyright":"\u00a9Olympus Knights\uff0fAniplex\u30fbProject AZ","url":"aldnoah","link": [],"recommendGoods": [],"recommendMovie": [{"imagePath":"/program/gochiusa/image/34_pgi01_b.jpg","url":"/program/gochiusa/"}],"cm": [],"allowExpand":"false"
});

看到第四行 "moviePath" 下的 http://onsen.b-ch.com/radio/aldnoah140712Zf8j.mp3 了吗?熟悉的 mp3 格式。

文件位置格式是:onsen.b-ch.com/radio/ + 节目名字 + 6 位日期 + 4 位随机字符 + .mp3

于是广播也 get だぜ~

举了两个详细的例子,一些更简单的就不再详述了。只要你活用开发者工具,很容易就找到地址的。有的广播比如 Aniplex 旗下的动画,会做一个官网,查看网页的源代码就直接能找到音频的地址。

使用插件或工具下载

浏览器能帮我们做到很多事情。因为从网络上来的东西,最后都是交给浏览器来解析的(flash 这类内嵌的组件除外)。也就是说,浏览器是知道我们想保存的下来的资源的位置和内容的,只要告诉浏览器给我们就行了,这也就是比较早期的时候,一些教程教授的从缓存文件夹中复制出文件的技术基础。不过现代浏览器有插件,就不用那么复杂了。安装上了插件,会自动给你提取出网页中可能存在的多媒体文件(音乐 / 视频 / 图片 /…)。

比如音泉

随便点击一个节目,在播放的同时,能够捕捉多媒体的插件就抓到资源了。

抓到播放资源

直接点击下载就 ok 了,容易吧。这些插件在 chrome 商店一搜一大堆,其他现代浏览器比如 FireFox 和 Opera 也是有这类插件。IE…… 我就不太清楚了。

BTW,这个网站访问是没问题的,但是媒体资源例如 mp3 和 mp4 等是限定日本 IP 的,请自备梯子。

编写脚本

以下是比较高阶的使用,电脑小白可以跳过了。

为什么在已经能够下载媒体的情况下,还要写脚本?

~~ 装逼~~

~~ 懒~~

咳咳,不是啦,其实是使用脚本能够快速和自动化啦(诶偷懒好像说对了……

鉴于访问外国网站的不稳定性(为了能截到博文中的漂亮的大图,我整个下午在不断地刷新……),这些广播网站经常是比较卡的。使用脚本能够只请求最小的资源就能提取出媒体的位置,比起每次打开网页快多了。当然你听一个两个广播还好,我要听十来个广播我是受不了的。如果能做到高度自动化,鼠标点两下,资源就自动躺在你面前了岂不妙哉?

废话不多说,直接上代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python
# _*_ coding: utf-8 _*_

from bs4 import BeautifulSoup
import urllib2
import sys

def mms_extract(url):
soup = BeautifulSoup(urllib2.urlopen(url))
return soup.select("ref")[0]["href"]

name_list = sys.argv[1].split(",")

for name in name_list:
soup = BeautifulSoup(urllib2.urlopen(u"http://hibiki-radio.jp/description/{name}".format(name=name), timeout=30))
mms = soup.select("div.hbkDescriptonContents embed")[0]["src"]
print mms_extract(mms)

这个是提取广播站響的广播音频地址,简单易懂吧?

先通过请求地址 http://hibiki-radio.jp/description / 节目名字 来获得节目详细页面。还记得这里的地址吗?是在分析的过程得知的。

注意这里获得到的网页文件只是一些代码和文字, 没有图片或者这个页面再请求的其他资源

接着是用 BeautifulSoup 在这个页面中提取出 <embed> 标签中的 src 属性值,再请求一次那个 asx 文件,在 asx 文件中取到最终要得到的 mms 协议地址。

使用的时候可以这样用:

1
python hibiki.py 节目名字[, 节目名字]

而如果你想使用 rtmpdump 来下载,也不是不可能,但是思维就完全不一样。先来看看 rtmpdump 的使用:

1
rtmpdump -r "rtmpe://cp209391.edgefcs.net/ondemand/" -y "mp4:140614_imocyo_140614_imocyo" -o test.flv

重点是要得到 -y 参数里面的名字,这就需要你清楚节目更新的日期和节目名字的代号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python
# _*_ coding: utf-8 _*_

from datetime import date

def get_date(delta=0):
"""
:return:
formatted date, i.e. 140505
"""format ="%y%m%d"
day = date.today()
if delta != 0 and isinstance(delta, int):
day = day + timedelta(days=delta)

return day.strftime(format)

def get_download_command(bangumi, output_name):
return "rtmpdump -r \"rtmpe://cp209391.edgefcs.net/ondemand/\"-y \"mp4:{date}_{bangumi}_{date}_{bangumi}\"-o {output}.flv".format(bangumi=bangumi, date=get_date(), output=output_name)

福利:一些广播网站地址

インターネットラジオ ·TV の番組表

響 - HiBiKi Radio Station -

インターネットラジオステーション<音泉>

Lantis web radio

超!A&G | AM1134kHz 文化放送 JOQR

exoticknight wechat
扫描关注公众号
Or buy me a coffee ☕ ?
  • 本文作者: exoticknight
  • 本文链接: https://blog.e10t.net/how-to-save-internet-radio/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。图片以及多媒体资料,均属原作者或本人所有。禁止任何形式的转载!
  • 授权转载务必保留以上声明和二维码。