Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

exoticknight's blog


年寿有时而尽,荣乐止乎其身,二者必至之常期,未若文章之无穷。

如何保存一些网络广播

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

  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文件内容。

<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,现在保持控制台打开的状况,点击播放。

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

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

播放时输出

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

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

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

<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/节目名字。后面的参数是代码回调和当前的时间。

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

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整理一下得:

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的,请自备梯子。

编写脚本

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

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

装逼

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

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

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

#!/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协议地址。

使用的时候可以这样用:

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

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

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

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

#!/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


About the author

exoticknight


Discussions

comments powered by Disqus