前段时间Dreamforce终于闲的无聊,发现Douban.fm还真的不错,总觉得它精选的歌曲还可以。所以Dreamforce就准备开始打造了一个简单的豆瓣客户端。

网上虽然有.net,C#,各种平台的,同时还有一些做的相当精致的客户端,如果只是为了使用,这篇文章将不再适合您阅读下去,本篇文章适合为想了解构造简单的豆瓣客户端的人群阅读,纯技术帖。

1.无API?

确实,douban.fm没有公开相关API,也没有文档可以参考。但是这些不能阻拦我们探索的脚本,打开Firefox,打开FireBug开始分析数据包吧,或许很多人没有尝试过HTTP数据包的分析,但是当你迈出第一步的时候,你将会发现,其实很简单。

数据分析前提: 首先要明白,我们是要抓什么样的包? 我们要何种数据

显然Douban.fm是用FlashPlayer来播放音乐的,而这点我们可以马上想到他的数据来源是JSON数据,后台一定会给他传一个播放列表,里面有每首歌的信息,URL等等,或者这个JSON叫做,songList,playList,musiclist等等。通过这个前期分析后,开始对关键字查找,你能很快的定位结果,Dreamforce用了几分钟的时间发现了,数据的所在:

dataAnalize
dataAnalize

我们现在已经发现了JSON请求的地址,接下来的事情很好看办了,我们可以试图去请求一下这个地址,看看Response的数据是什么样的

{"r":0,"song":[{"picture":"http:\/\/img1.douban.com\/mpic\/s4623241.jpg","albumtitle":"Femme Fatale","company":"","rating_avg":4.06523,"public_time":"2011","ssid":"cb94","album":"\/subject\/5962329\/","like":0,"artist":"Britney Spears","url":"http:\/\/mr3.douban.com\/201207061300\/6b69329cec5375639e9e98a223f01025\/view\/song\/small\/p1638685.mp3","title":"Trip To Your Heart","subtype":"","length":214,"sid":"1638685","aid":"5962329"},{"picture":"http:\/\/img1.douban.com\/mpic\/s3855454.jpg","albumtitle":"Thriller","company":"","rating_avg":4.73667,"public_time":"2001","ssid":"9939","album":"\/subject\/1422148\/","like":0,"artist":"Michael Jackson","url":"http:\/\/mr5.douban.com\/201207061300\/bc03be07074faf95afd7c48c92ec17fa\/view\/song\/small\/p676071.mp3","title":"Beat It","subtype":"","length":258,"sid":"676071","aid":"1422148"},{"picture":"http:\/\/img3.douban.com\/mpic\/s1400647.jpg","albumtitle":"Lennon Legend: Th...","company":"","rating_avg":4.63824,"public_time":"1998","ssid":"dfbc","album":"\/subject\/1395275\/","like":0,"artist":"John Lennon","url":"http:\/\/mr3.douban.com\/201207061300\/bb88939b7509cf5d5e64384161a72667\/view\/song\/small\/p1403048.mp3","title":"Instant Karma!","subtype":"","length":201,"sid":"1403048","aid":"1395275"},{"picture":"http:\/\/img3.douban.com\/mpic\/s4716636.jpg","albumtitle":"It's Not Me, It's...","company":"","rating_avg":4.03394,"public_time":"2009","ssid":"10e0","album":"\/subject\/3313731\/","like":0,"artist":"Lily Allen","url":"http:\/\/mr3.douban.com\/201207061300\/bbd664422211b8a22517fe5a654d4ace\/view\/song\/small\/p1381366.mp3","title":"Back To The Start","subtype":"","length":251,"sid":"1381366","aid":"3313731"},{"picture":"http:\/\/img5.douban.com\/mpic\/s3765819.jpg","albumtitle":"Holy Wood (In The...","company":"","rating_avg":4.36569,"public_time":"2000","ssid":"95ab","album":"\/subject\/1417966\/","like":0,"artist":"Marilyn Manson","url":"http:\/\/mr3.douban.com\/201207061300\/78f745355bfc6f13db0f8c89e851ecb7\/view\/song\/small\/p501145.mp3","title":"In The Shadow Of The Valley Of","subtype":"","length":249,"sid":"501145","aid":"1417966"},{"picture":"http:\/\/img1.douban.com\/mpic\/s7033620.jpg","albumtitle":"Nimrod","company":"","rating_avg":4.0268,"public_time":"1997","ssid":"572d","album":"\/subject\/1424291\/","like":0,"artist":"Green Day","url":"http:\/\/mr3.douban.com\/201207061300\/7f632f10edc0a45bda1e10c3435c219b\/view\/song\/small\/p1033919.mp3","title":"Walking Alone","subtype":"","length":165,"sid":"1033919","aid":"1424291"},{"picture":"http:\/\/img3.douban.com\/mpic\/s1400298.jpg","albumtitle":"Escape","company":"","rating_avg":4.19888,"public_time":"2001","ssid":"f309","album":"\/subject\/1394999\/","like":0,"artist":"Enrique Iglesias","url":"http:\/\/mr3.douban.com\/201207061300\/c948f73ffb38c92f771a730d8b44000f\/view\/song\/small\/p1385198.mp3","title":"Heroe","subtype":"","length":263,"sid":"1385198","aid":"1394999"},{"picture":"http:\/\/img1.douban.com\/mpic\/s3860021.jpg","albumtitle":"Bury the Hatchet","company":"","rating_avg":4.44362,"public_time":"1999","ssid":"2dfe","album":"\/subject\/1462020\/","like":0,"artist":"The Cranberries","url":"http:\/\/mr3.douban.com\/201207061300\/25ccfae5f111c3b50c1fde8a9775a9ed\/view\/song\/small\/p333016.mp3","title":"Animal Instinct","subtype":"","length":211,"sid":"333016","aid":"1462020"},{"picture":"http:\/\/img1.douban.com\/mpic\/s3762451.jpg","albumtitle":"Queen","company":"","rating_avg":4.25209,"public_time":"1973","ssid":"d1d6","album":"\/subject\/1467981\/","like":0,"artist":"Queen","url":"http:\/\/mr4.douban.com\/201207061300\/cce549b63f73df5e6a1a401b1ce53900\/view\/song\/small\/p1046354.mp3","title":"Liar","subtype":"","length":224,"sid":"1046354","aid":"1467981"}]}

从这里我们可以看出这是一个简单的JSON数据结构,同时没有任何加密,心情大为高兴,剩下的事情就是分为三个点:1,解析数据;2,播放曲目;3.Build APP

应用开发篇

本应用将是使用Python(2.7)语言进行开发,同时Dreamforce最近相当喜欢这门语言

1.解析数据

定义基本属性

#This properties defined in the nameV.py files
songList = None
current  = 0
mp3 = None
threads=[]
aurl = 'http://douban.fm/j/mine/playlist?type=n&'
murl='channel=1'
burl = '&from=mainsite'
#This method defined in the client.py files
def getPlayList():
    print("------------Welcome to Douban Client------------")
    #拼装请求URL,通过Channel进行切换,Channel值是可选的,后面的代码会有示例
    url = str(nameV.aurl)+str(nameV.murl)+str(nameV.burl)
    print(url)
    print('Current Channel is : ' + str(nameV.murl))
    nameV.current = 0
    page_source = None
    try:
        #使用urllib请求
        page_source = urllib.urlopen(url)  
    except Exception,data:
        print Exception,":",data
    print("------------Reading PlayList , please waiting------------")
    #抓取页面数据
    pageData = page_source.read()
    #使用JsonLIB将数据解析为Json,这个LIB让我们省了很多事
    jsonData =json.loads(pageData)
    #将Song里面集合存入songList,这里统一将请求得的数据放到nameV里进行缓存
    nameV.songList = jsonData['song']
    #将列表打印出来
    printPlayList()

2.播放

播放MP3,我们这里不会让你从底层进行解码器开发,Dreamforce也不会解码器的开发,但是我可以使用相关的解码器Lib进行播放,我们这里使用WM解码器内核作为我们MP3的播放内核。
推荐使用mp3play这个LIB包进行开发。非常轻量级的,如果你想做一个UI质感的,功能强劲的播放器的话,可以选择PygameLIB包。
简单的播放:

def play:
    #支持远程流播放
    mp3.load(fileName)
    mp3.play()
    #播放整首歌曲,1秒的间隔结束
    time.sleep(mp3.seconds()+1)
    mp3.stop()

这里是很简单的播放示例,可是真正的做起来,不止这么简单,你要考虑到很多功能点,比如暂停,播放,下一首,切换频道,刷新列表等等。 Dreamforce就不将全部代码贴出来了。
这里友情提示一下,客户端的功能是通过按键监听来实现,那么Python自带的Input功能是完全不能满足的(必须要回车,通过会阻断行为),那么可以引入下面这块代码来实现:

from msvcrt import getch

#监听用户按键行为

getch().upper()

对于歌曲中文编码问题,Dreamforce也友情提示一下:

import codecs
codecs.register(lambda name: name == 'cp65001' and codecs.lookup('utf-8') or None)

上面这块代码可以解决英文操作系统CMD不支持中文的问题,必须要强行进行utf-8的映射
同时使用

encode('gbk')

可以很好的将JSON里面的中文数据转换为可阅读的中文

 

3. Build APP

当开发完成,就可以进行APP封装,一般情况下是封装为EXE,同时你如果使用的MP3PlayLIB,那这个客户端也只能在Windows上使用,除非你将WM解码器一起打包分发,但这样会将整个APP变的相当臃肿。
使用CX_Freezer进行编译,这里不用详细介绍了,非常简单。

 

后记:

整个APP的开发相当简单,没有太多的技术难度,但可以让读者了解一下客户端的构建过程。

18 thoughts on “纯手工打造Python豆瓣电台客户端(Geek命令行风格)”
  1. 你好,DreamForce,很喜欢你的个性签名,喜欢用自动化工作,同样我也是很懒,最近刚开始学习Python,从《dive into Python》开始,DreamForce有没有什么建议呢?

    1. 感谢到访, 其实Pyton是很轻量的脚本语言, 如果你有其它语言的编程基础,上手是相当快速,可能1-3天就能上手。 但如果想深入研究的话需要花上一定的时间。 推荐边看边做, 学习Python最好的方式是你带着目的去学,你想用python去实现你的业务,而不是学完了python再来思考它能做什么。。。 这是我速成的经验。 希望对你有所帮助。 如果说的有错也请谅解,毕竟我也是拿python做为业余爱好进行开发

  2. Heya i am just at last here. I discovered this particular panel i find It genuinely helpful & this allowed me to out considerably. I hope to offer some thing and also aid other individuals just like you helped me.

  3. Howdy would you mind letting me know which web host you’re using? I’ve loaded your blog in 3
    different browsers and I must say this blog loads a lot quicker then most.

    Can you suggest a good web hosting provider at a honest price?
    Cheers, I appreciate it!

  4. I have been surfing online greater than 3 hours nowadays, but I by no means found any attention-grabbing article like yours.
    It is lovely value enough for me. In my view, if all webmasters and bloggers made just right content material as
    you probably did, the internet can be much more helpful than ever before.

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注