python小练习:网络视频下载

Published on 12月 02, 2012

python小练习:网络视频下载

互联网上有很多视频网站,提供大量视频。可是大多都要求你使用它提供的专有软件才能下载,或者根本没提供下载的地方。在linux下怎么办?总是有办法的。浏览器扩展,you-get,直接从硕鼠解析出地址自己下载……

这不是重点,重点是:自己动手玩一玩。 - 顺便学习下几个python标准库:=urllib=、=urllib2=、=re=。 - 初步学习http报头知识 Extra bonus: - flv文件结构

都是随便看看。

下载视频

简单起见,直接从硕鼠抓取地址。

首先我们随便找一个视频地址,比如来自sina的憨豆特工。我们把地址用硕鼠解析出来看看:

original_jaVP_5b4d00008fb1125d.jpg
Figure 1: 硕鼠

哇哦,一个电影被分成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文件规范

original_yzzH_5943000093b01191.jpg
Figure 2: flash-data

Practice

抓取这里的视频。并按名称保存他们:

作为正则和urllib、urllib2的练习。