
PyETGO 0.3 更新版下载:http://code.google.com/p/ptcoding/source/browse/trunk/PyETGO
本脚本可跨平台使用,在Win下需要wget for Windows, 把wget.exe放在脚本所在目录即可。
Wget下载:http://www.interlog.com/~tcharron/wgetwin-1_5_3_1-binary.zip
感谢Twitter上的好友mengzehe关于Win下使用的测试和提醒。
感谢Ubuntu论坛上网友的测试。
v0.3
2009.03.16
-对获取的XML列表中存在的非法字符进行过滤(解决曲名含"&"等不规则字符导致无法下载)
v0.2更新
- 2009.03.11
- -为在Win下使用本脚本,全部使用Unicode的字符串来提示(0.1有部分乱码)
- -修改写入Intro.txt文件的方法,使用writelines,会根据操作系统不同写入不同换行符,减少乱码
- -写入文件名前过滤Win下的非法文件名字符/\:<>?|等
大概实现这样的功能:
- 下载http://music.etgo.cn/上的任意专辑的音乐文件
- 专辑的存放目录命名为“歌手名 - 专辑名”
- 多CD的专辑,音乐文件命名为“CD号-轨号_歌手 - 歌名”,单CD则为“轨号_歌手 - 歌名”
- 下载专辑的封面和封底文件cover.jpg、coverback.jpg
- 从页面中抽出的专辑信息和介绍文字写入Intro.txt
- 首次使用需要用-u和-p输入一个ETGO账户以获取Cookie,以后下载只需用-a指定一个专辑的页面
- 下载时可随时使用Ctrl + C中断,重新下载时自动从断点续传。
花了好几天的时间在这个脚本上,基本把Python的特性摸熟了。
ETGO是国内一个娱乐网站,有电影、Mp3等,资源不算新,格式也就192~256K那样,没太大特色,但其有自己的服务器,运营稳定,这几年来我偶尔都从那里Down些专辑,基本上浏览器的嗅探+序号批量下载就可搞定,而且速度不赖。网站的免费试听使用的是Flash的播放器,这个脚本则模拟了播放器读取列表的功能,骗回所有Mp3的原始地址,然后调用wget下载。
稍微记录下开发过程。

首先还是逆向路线,打开Wireshark在嗅探,从浏览器点击一首歌的试听,浏览器弹出窗口开始播放。从嗅探结果看,在本地发出GET MP3文件的那个报文之前,服务器必然已经把真实地址发回给Flash播放器,于是检查前一个请求:GET /mp3player.php。从其相应报文类型HTTP/XML就可以判断出这是一个返回XML信息的请求,打开分析,果然。
但这个mp3player.php根据什么来知道用户的点歌呢?查看专辑页的源码,只见每个“试听”链接具有这样的属性:
onClick="MM_openBrWindow('/player.php?fid=90388','MusicPlayer','width=446,height=340')"
不难猜到fid=54664就是每首歌的“身份ID”,player.php是带Flash控件的那个页面,fid应该是送给Flash的参数,而mp3player.php才是返回列表XML,而mp3player.php没有任何GET参数,说明请求还是藏在报文内。

回到Wireshark查看GET /mp3player.php那个报文,展开其请求,一眼看不出什么猫腻,就见到那个长长的Cookie,Wireshark没有给出完整的分析,直接看下面的原始数据:
![]()
抓到你了!竟然藏在Cookie的结尾。
1.getPlayListXML模块
有了之前写CETQuery的经验,模拟它发个这样的报文很轻松,稍作调试就收到完整的XML歌曲列表。原来ETGO整个网站对用户的验证都是通过这样的Cookie,里面甚至包含了明文的用户名和密码,都算的上是世界上最不安全的网站之一了。都几年了没点技术更新,难怪我骗起来那么容易(嘿嘿)。
一次得一首歌的效率我可是不满意的,页面里面不是有个连播么,一次往列表里面添加所有歌。同上道理嗅探下来,原来只需把藏在Cookie后面那个参数用%7C分隔,连上一串uid即可:
playlist=20274%7C20275%7C20276%7C20277%7C20278......
剩下的是解析XML的工作,这可是Python的强项,我选择了minidom。《Dive in Python》Scripts and Streams一章中示范了直接把urlopen的流对象直接塞给minidom的parse,帅呆了。操作方法和Javascript的DOM很类似,用了一个getElementsByTagName把所有个song元素调出,再组织一下属性值,轻松过关。
2.Download File 方法
如何下载Mp3文件呢?直接下载是不行的,服务器有HTTP头检测。wget --help看了一下,果然不愧是UNIX下的老牌工具,很强大,--header可定义下载时的HTTP头。依旧在Wireshark看其连接Mp3地址时的报文,看不出有什么特别的,也是那个Cookie。
3.getCookie 模块
要获得Cookie,需要在页面登录。页面登录经典的老牌方法,把用户名密码等post到http://member.etgo.cn/member.php,然后读取相应头部里面的'set-cookie'段,然后干脆把Cookie写入文件,以后要下载专辑都不用麻烦连服务器了,直接读取即可。
4.getAlbum 模块
如果仅仅是下载,这时已经完成了,但为了提高自动化程度,还得想办法自动获取每首歌的uid,这需要解释专辑的HTML页面。《Dive in Python》中的例子用的是SGMLParser,但是从文档看到说SGMLParser在2.6版本后就过时了,《Python网络编程基础》里面则用了HTMLParser,两个模块大同小异,选择了后者。
HTMLParser的设计和很多Python模块一样,预置了接口,只需要实现所用的部分即可(似乎就是传说中的抽象工厂模式)。为了下载的时候能够把文件名编得完美点,从网页中解析出完整的歌手、专辑名,用了一堆正则表达式来过滤。
5.模块内聚
以上的几个模块都实现完成后,虽说什么功能都不缺了,但还是耗了不少时间。一是文件名,对于多CD的专辑,在文件名前标上CD号,而单CD的,只标轨号。而CD号和轨号都是要从URL里面析取的,一晚上下来把正则表达式用得相当熟手了。其次是如何组织目录,检查文件,os模块内的几种系统调用,还有要响应强行终止的任务,处理命令行参数……

我想问下,这个东西该怎么用呢?直接双击?
在脚本的解压目录下执行./ETGO.py -a http://... -u user -p pass即可,分别是专辑的地址,和用户密码。参看里面的Readme吧!
赞一个。好东西