python小练习:网络视频下载
互联网上有很多视频网站,提供大量视频。可是大多都要求你使用它提供的专有软件才能下载,或者根本没提供下载的地方。在linux下怎么办?总是有办法的。浏览器扩展,you-get,直接从硕鼠解析出地址自己下载……
这不是重点,重点是:自己动手玩一玩。
- 顺便学习下几个python标准库:
urllib
、urllib2
、re
。 - 初步学习http报头知识
Extra bonus: - flv文件结构
都是随便看看。
下载视频
简单起见,直接从硕鼠抓取地址。
首先我们随便找一个视频地址,比如来自sina的憨豆特工。我们把地址用硕鼠解析出来看看:
哇哦,一个电影被分成15个文件了。
我们接下来要做的就是抓取这十五个视频的地址并把他们下载下来。
也许,用正则是个不错的办法。查看该页面源码,可以找到这样的内容:
<input type="hidden" name="inf" value="<R>憨豆特工
<T>0
<F>http://video.sina.com.cn/v/b/56925622-2257301331.html
<QX>normal
<$>
<N>憨豆特工-0001
<P>新浪网
<U>http://edge.v.iask.com/56926940.hlv?KID=sina,viask&Expires=1354550400&ssig=0G8Acouy32
<X>0001
<C>aHR0cDovL3YuaWFzay5jb20vdl9wbGF5LnBocD92aWQ9NTY5MjU2MjItMjI1NzMwMTMzMSZyPXZpZGVvLnNpbmEuY29tLmNu
<EXPLODEID>1
<&>
<$>
<N>憨豆特工-0002
<P>新浪网
<U>http://edge.v.iask.com/56921791.hlv?KID=sina,viask&Expires=1354550400&ssig=aDBPWf%2B2YH
<X>0001
<C>aHR0cDovL3YuaWFzay5jb20vdl9wbGF5LnBocD92aWQ9NTY5MjU2MjItMjI1NzMwMTMzMSZyPXZpZGVvLnNpbmEuY29tLmNu
<EXPLODEID>2
<&>
<$>
<N>憨豆特工-0003
<P>新浪网
......
显然,<N>
后面是片名而<U>
后面是地址。
另外,我们观察一下硕鼠当前页面的url地址。
http://www.flvcd.com/parse.php?kw=http%3A%2F%2Fvideo.sina.com.cn%2Fv%2Fb%2F56925622-2257301331.html
显然,kw参数后面是之前sina视频页面地址,只不过已经经过转码处理。
至此,足够我们用python来完成这一切了。
打开ipython:
In [1]: import urllib
In [2]: import urllib2
In [3]: videourl = 'http://video.sina.com.cn/v/b/56925622-2257301331.html'
In [4]: url = 'http://www.flvcd.com/parse.php?kw=' + urllib.quote(videourl)
In [5]: req = urllib2.Request(url);
In [6]: req.add_header('host', 'www.flvcd.com');
In [7]: res = urllib2.urlopen(req)
In [8]: html = res.read()
In [9]: print unicode(html,'gbk') # 注意硕鼠的页面编码是charset=GB2312
至此,我们完成了从硕鼠读取整个网页的操作。并把读取的内容保存在html中。
接下来开始抓地址,根据之前的观察,很容易通过正则表达式完成:
In [13]: import re
In [14]: pattern = re.compile('<input\s+type="hidden"\s+name="inf"\s+value="([^"]+)')
In [15]: match = pattern.search(html)
In [16]: urls = match.group(1)
In [17]: urls = unicode(urls, 'gbk')
In [18]: urlpattern = re.compile('<[NU]>(.+)')
In [19]: result = urlpattern.findall(urls)
至此,<N>
和<U>
后面的文件名和地址都被以列表的形式保存在result中了。我们可以遍历它来完成下载:
先简单处理下,以文件名-地址成对保存:
In [28]: data = [result[i:i+2] for i in range(0, len(result), 2)]
然后遍历下载:
In [32]: for k, v in enumerate(data):
print ' >downloading Block %.2d ...' % (k+1,)
urllib.urlretrieve(v[1], v[0] + '.flv')
print ' downloaded Block.%.2d completely<' % (k+1,)
然后?等着……目前的下载器相当简陋,木有进度条,木有断点……
之后就是合并flv的问题了。
合并flv文件
简单起见,直接用这里join_flv.py来完成。
python2 join_flv.py -o out.flv flv1.flv flv2.flv ...
如果你想深入了解flv文件结构,参考further reading部分和flv文件规范。
Practice
抓取这里的视频。并按名称保存他们:
- https://class.coursera.org/ml/lecture/preview
- http://v.163.com/special/opencourse/machinelearning.html
作为正则和urllib、urllib2的练习。