15.6 非交互式地下载文件
wget
网络就像是一个堆满了图片、电影和音乐文件的丰富宝藏,可供人随时下载。问题是对于一个有200多首MP3的文件集,如果让你逐一手工下载每个文件,你很快就会烦了,心情变得糟糕,不断唉声叹气。wget
这个命令就是用于无干扰地下载多个文件和Web网站。只要一个操作来设置好命令,它就会高高兴兴地下载指定的东西,可能会持续好几个小时,一直到全部下载完。
当然,最难处理的还是如何建立这个命令。wget
也是一个功能超级强大的程序,详细介绍完它的方方面面真得又够写一整本书了,所以这里没有展示它的所有功能,只重点介绍用它可以做的两件事: 下载整个一组文件(本节介绍的内容),以及下载整个网站(下一节将要介绍的内容)。
假设有以下应用场景:你发现了一个非常精彩的网站,叫做“The Old Time Radio Archives”。在这个网站上有很多怀旧经典歌曲,而且提供了MP3格式的下载,多达365首。确切地说,一年中的每一天都可以欣赏一首。如果能把这些MP3文件都抓回来,肯定是好事。但是一想到要在每首MP3文件的超链接上右点击鼠标,选择“目标另存为(Save Link As)”菜单项,再单击“保存(OK)”按钮来开始下载,这么大量烦琐的劳动就不那么吸引人了。
再检查一下这些MP3链接的目录结构,你会注意到这些链接都是按同样的目录进行组织的,如下所示:
http://www.oldtimeradioarchives.com/mp3/
season_10/
season_11/
...
season_20/
...
season_3/
season_4/
...
season_9/
说明 这些目录并没有按数字顺序来排序(人通常是按数字的大小来排序的),而是按字母顺序来排序的,计算机默认对数字就是这样排序的,除非指定其他的排序方式。因此,“10”就排在了“3”的前面。
在每个目录中都包含多个MP3文件,一些目录可能只包含为数不多的几个文件,而另一些目录包含的文件则可能差不多有20个。如果单击链接,进入到目录中,就会打开一个网页,上面列出了这个目录中的所有文件,如下所示:
[BACK] Parent Directory 19-May-2002 01:03 -
[SND] 1944-12-24_532.mp3 06-Jul-2002 13:54 6.0M
[SND] 1944-12-31_533.mp3 06-Jul-2002 14:28 6.5M
[SND] 1945-01-07_534.mp3 06-Jul-2002 20:05 6.8M
[SND]
是一个音乐符号的GIF图像,在每个文件的前面演示。
所以,现在的问题是:如何下载这些位于不同目录中的具有不同文件名称的所有MP3文件。答案就是wget
。
先在计算机上创建一个目录,保存要下载的MP3文件。
$ mkdir radio_mp3s
使用cd
命令,进入到新创建的那个目录,再运行wget
,如下所示:
$ cd radio_mp3s
$ wget -r -l2 -np -w 5 -A.mp3 -R.html,.gif
➥http://www.oldtimeradioarchives.com/mp3/`
接下来逐一介绍这个命令和它的选项。
不用多说,wget
是你运行的命令,命令行的最末尾是你希望wget
使用的URL:http://www.oldtimeradioarchives.com/mp3。不过,最重要的东西,是位于命令名和URL之间的各个参数。
wget
的-r
(或--recursive
)选项会沿着链接,深入到各个子目录中搜索文件。通过告诉wget
以递归方式进行下载,可以保证wget
遍历每个season_#
子目录,抓取回它找到的所有MP3文件。
-l2
(或--level=[#]
)选项不但重要,而且也很微妙。它用于告诉wget
在取回文件时最多应该递归多深。小写的字母l
在这里代表“level(层)”,数字表示wget
应该向下搜索的最大深度。如果将层数指定为-l1
,wget
将只搜索/mp3
这一层目录。当然,这一层上什么也下载不到。记住,/mp3
目录中还包含其他子目录:season_10
、season_11
等,这些目录才包含你想要下载的MP3文件。通过指定-l2
,也就是让wget
先进入/mp3
(这是第一层目录),然后再依次进入每个season_#
目录,抓取回子目录中的任何东西。在指定层数时,要非常小心。稍不留神,就可能在非常短的时间内把硬盘空间塞满。
避免下载过多文件的一种办法是使用-np
(或--no-parent
)选项,它可以阻止wget递归到父目录。如果回头看看前面列出的文件列表,你会注意到每个链接的第一部分都指向同一父目录。换句话说,在/season_10
目录中,它的父目录是/mp3
;而/season_11
、/season_12
等各目录的父目录都是/mp3
。不过,你应该不希望wget
向上搜索,而是希望它只向下搜索。也就是说,在每个season_#
目录中,肯定不需要浪费时间让wget
向上搜索相同的目录(/mp3
)。
接下来的那个选项不是必须的,但是如果使用这个选项一定会让你显得很有礼貌。-w
(或--wait=[#]
)选项可以在每两个文件的下载之间引入一个短暂的时间间隔。这有助于当连续不断地从服务器下载文件时,避免对服务器产生过重的负担。在默认情况下,wget
下载间隔数字的单位是秒;如果需要,也可以在数字后面添加一个m
,以指定分钟,或是用h
指定小时,甚至用d
来指定天数。
现在轮到介绍一个非常有趣的选项了。-A
(或--accept
)用于告诉wget
:你只想下载某种类型的文件,而其他文件则不需要下载。A代表accept(接受),后面跟着需要下载的各种文件的后缀名[用逗号(,)分隔]。如果你只想下载一种类型的文件(例如MP3文件),可以这样来指定参数:-A.mp3。
相反,-R
(或--reject
)选项则是告诉wget
不想下载的文件: HTML和GIF文件。排除了这些类型的文件后,wget
就不会下载前面展示的[SND]
所代表的那些小音乐符号的图片文件。排除文件的后缀列表也是用逗号(,)分隔的,例如-R.html,.gif
。
运行带有这些选项的wget
命令,就会把你想要的365首MP3文件全部下载到计算机中。如果因为某些原因(例如,路由器停止工作了;有人绊到了以太网线上,把它从电脑上拉开了;挖掘机铲断了公司的光纤),wget
传输中断了,这时只要重复命令,并加上-c
(或--continue
)选项。这个选项告诉wget
接着下载没有下载完的文件。这样就不必再重新下载所有文件。
下面再举个用wget
下载文件的例子。London DJ发行了两部MP3专辑,由Beatles(甲壳虫乐队)和Beastie Boys这两个乐队的作品组成。当然,我们要听Beastles的。在www.djbc.net/beastles,MP3链接一个接一个地列在这个页面中。
下列命令将从这个页面中提取出各个链接,把它们写到一个文件中,然后再用wget
开始下载这些链接:
$ dog --links http://www.djbc.net/beastles/ | grep
➥mp3 > beastles ; wget -i beastles
--12:58:12-- http://www.djbc.net/beastles/
➥webcontent/djbc-holdittogethernow.mp3
=> 'djbc-holdittogethernow.mp3'
Resolving www.djbc.net... 216.227.209.173
Connecting to www.djbc.net|216.227.209.173|:80...
➥connected.
HTTP request sent, awaiting response... 200 OK
Length: 4,533,083 (4.3M) [audio/mpeg]
100%[=========>] 4,533,083 203.20K/s ETA 00:00
12:58:39 (166.88 KB/s) - 'djbc-holdittogethernow.
➥mp3' saved [4533083/4533083]
在第5章中学过cat
命令,它可以把文件输出到STDOUT(标准输出设备)。5.4节提到了一种比cat
更好的命令,叫做dog
(确实是真的,因为“狗”比“猫”要好多了)。如果用--links
选项,并将它指向某个URL,这时再调用dog
,它就会取回那个页面上的所有链接,并显示在STDOUT上。在上面的例子中,用管道符将这些链接发送给grep
,让grep
过滤掉除了包含mp3以外的所有行,再将生成的MP3链接重定向到一个名为beastles
的文本文件(管道和重定向是第4章介绍的内容,grep
命令是第9章中介绍的内容)。
分号(在4.1节有所介绍)用于结束前面的命令,并开始引入另一个新命令:wget
。-i
(或--input-file
)选项是告诉wget
从文件(而不是STDIN,标准输入设备)中查找要下载的URL。如果要下载的链接有多个,可以把它们放在一个文件中,并在wget
中使用-i
选项。在这个例子中,wget
指定通过dog
和grep
而创建的beastles
文件,这样就可以依次开始下载每个MP3文件了。
现在,说真的,还能再简单些吗? 嗯,Linux命令行的功能是很强大的!