5.7 制作图片抓取器及下载工具
当需要下载某个网页上所有的图片时,图片抓取器(crawler)能够帮上我们的大忙。用不着把HTML源码翻个底朝天来摘取出所有的图片,我们可以用脚本解析图像文件并将它们自动下载下来。来看看这是如何实现的。
5.7.1 实战演练
用于从网页上抓取并下载图片的Bash脚本如下:
#!/bin/bash
#用途:图片下载工具
#文件名: img_downloader.sh
if [ $# -ne 3 ];
then
echo "Usage: $0 URL -d DIRECTORY"
exit -1
fi
for i in {1..4}
do
case $1 in
-d) shift; directory=$1; shift ;;
*) url=${url:-$1}; shift;;
esac
done
mkdir -p $directory;
baseurl=$(echo $url | egrep -o "https?://[a-z.]+")
curl -s $url | egrep -o "<img src=[^>]*>" |
sed 's/<img src=\"\([^"]*\).*/\1/g' > /tmp/$$.list
sed -i "s|^/|$baseurl/|" /tmp/$$.list
cd $directory;
while read filename;
do
curl -s -O "$filename" --silent
done < /tmp/$$.list
使用方法:
- $ ./img_downloader.sh http://www.flickr.com/search/?q=linux -d images
5.7.2 工作原理
上述图片下载器脚本首先解析HTML页面,除去
之外的所有标记,然后从
标记中解析出src="URL"
并将图片下载到指定的目录中。这个脚本接受一个网页URL和用于存放图片的目录路径作为命令行参数。脚本开始部分用了一种巧妙的方式来解析命令行参数。[ $# -ne 3 ]
检查脚本参数数量是否为3个,如果不是,它就会退出运行,同时返回脚本用法说明。
如果是3个参数,那么就解析URL和目标目录。解析过程需要用到一些技巧:
- for i in {1..4}
- do
- case $1 in
- -d) shift; directory=$1; shift ;;
- *) url=${url:-$1}; shift;;
- esac
- done
用for
循环执行4次迭代(第4次迭代其实也没有什么影响,无非就是执行了几次case
语句)。
case
语句会对第一个参数($1
)求值,以匹配-d
等被检查到的字符串参数。我们可以像下面那样将-d
置于命令行的任意位置:
- $ ./img_downloader.sh -d DIR URL
或者
- $ ./img_downloader.sh URL -d DIR
shift
用来移动参数。当使用shift
后,$2
的值就被赋给 $1
;如果再次使用shift
,则$3
的值被赋给 $1
,往后依次类推,因此我们通过 $1
就可以对所有的参数进行求值。
如果匹配-d
(-d)
),显然下一个参数就是目标目录的值。*)
对应默认匹配(default match)。它能够匹配除了-d
之外的任何内容。因此在默认匹配中,当 $1=""
或 $1=URL
时,我们需要采用$1=URL
,避免""
将变量url
覆盖掉。所以我们使用了url=${url:-$1}
。如果url不为空,它会返回URL值,否则返回$1
的值。
egrep -o "
只打印包括属性值在内的 ]*>"
标记。[^>]*
用来匹配除 >
之外的所有字符,结果就是
。
sed 's/
对 src="url"
进行解析,这样就可以从已经解析出来的
标记中得到所有的图像文件URL。
图像文件源路径有两种类型:相对路径和绝对路径。绝对路径包含以http:// 或 https:// 起始的完整URL,相对路径则以 / 或图像文件名起始。
绝对路径:http://example.com/image.jpg
相对路径:/image.jpg
对于以/起始的相对路径,应该用基址URL(base URL)把它转换为 http://example.com/image.jpg。
我们一开始通过解析,将基址URL存入变量baseurl
中,以便进行路径转换。
然后,用sed -i "s|^/|$baseurl/|" /tmp/$$.list
将所有的 / 替换成baseurl。
while
循环用来对图片的URL列表进行逐行迭代,并用curl
下载图像文件。与curl
一同使用的 --silent
选项可避免下载进度信息出现在屏幕上。
5.7.3 参考
5.4节讲解了
curl
命令。4.6节讲解了
sed
命令。4.3节讲解了
grep
命令。