5.7 制作图片抓取器及下载工具

当需要下载某个网页上所有的图片时,图片抓取器(crawler)能够帮上我们的大忙。用不着把HTML源码翻个底朝天来摘取出所有的图片,我们可以用脚本解析图像文件并将它们自动下载下来。来看看这是如何实现的。

5.7.1 实战演练

用于从网页上抓取并下载图片的Bash脚本如下:

  1. #!/bin/bash
  2. #用途:图片下载工具
  3. #文件名: img_downloader.sh
  4. if [ $# -ne 3 ];
  5. then
  6. echo "Usage: $0 URL -d DIRECTORY"
  7. exit -1
  8. fi
  9. for i in {1..4}
  10. do
  11. case $1 in
  12. -d) shift; directory=$1; shift ;;
  13. *) url=${url:-$1}; shift;;
  14. esac
  15. done
  16. mkdir -p $directory;
  17. baseurl=$(echo $url | egrep -o "https?://[a-z.]+")
  18. curl -s $url | egrep -o "<img src=[^>]*>" |
  19. sed 's/<img src=\"\([^"]*\).*/\1/g' > /tmp/$$.list
  20. sed -i "s|^/|$baseurl/|" /tmp/$$.list
  21. cd $directory;
  22. while read filename;
  23. do
  24. curl -s -O "$filename" --silent
  25. done < /tmp/$$.list

使用方法:

  1. $ ./img_downloader.sh http://www.flickr.com/search/?q=linux -d images

5.7.2 工作原理

上述图片下载器脚本首先解析HTML页面,除去 5.7 制作图片抓取器及下载工具 - 图1 之外的所有标记,然后从 5.7 制作图片抓取器及下载工具 - 图2 标记中解析出src="URL" 并将图片下载到指定的目录中。这个脚本接受一个网页URL和用于存放图片的目录路径作为命令行参数。脚本开始部分用了一种巧妙的方式来解析命令行参数。[ $# -ne 3 ] 检查脚本参数数量是否为3个,如果不是,它就会退出运行,同时返回脚本用法说明。

如果是3个参数,那么就解析URL和目标目录。解析过程需要用到一些技巧:

  1. for i in {1..4}
  2. do
  3. case $1 in
  4. -d) shift; directory=$1; shift ;;
  5. *) url=${url:-$1}; shift;;
  6. esac
  7. done

for循环执行4次迭代(第4次迭代其实也没有什么影响,无非就是执行了几次case语句)。

case语句会对第一个参数($1)求值,以匹配-d 等被检查到的字符串参数。我们可以像下面那样将-d置于命令行的任意位置:

  1. $ ./img_downloader.sh -d DIR URL

或者

  1. $ ./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 "5.7 制作图片抓取器及下载工具 - 图3]*>"只打印包括属性值在内的 5.7 制作图片抓取器及下载工具 - 图4 标记。[^>]*用来匹配除 > 之外的所有字符,结果就是 5.7 制作图片抓取器及下载工具 - 图5

sed 's/src="url"进行解析,这样就可以从已经解析出来的 5.7 制作图片抓取器及下载工具 - 图6 标记中得到所有的图像文件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命令。