通过网络图片小爬虫对比Python中单线程与多线(进)程的效率

396 查看

批评 Python 的人通常都会说 Python 的多线程编程太困难了,众所周知的全局解释器锁(Global Interpreter Lock,或称 GIL)使得多个线程的 Python 代码无法同时运行。因此,如果你并非 Python 开发者,而是从其他语言如 C++ 或者 Java 转过来的话,你会觉得 Python 的多线程模块并没有以你期望的方式工作。但必须澄清的是,只要以一些特定的方式,我们仍然能够编写出并发或者并行的 Python 代码,并对性能产生完全不同的影响。如果你还不理解什么是并发和并行,建议你百度或者 Google 或者 Wiki 一下。

在这篇阐述 Python 并发与并行编程的入门教程里,我们将写一小段从 Imgur 下载最受欢迎的图片的 Python 程序。我们将分别使用顺序下载图片和同时下载多张图片的版本。在此之前,你需要先注册一个 Imgur 应用。如果你还没有 Imgur 账号,请先注册一个。

这篇教程的 Python 代码在 3.4.2 中测试通过。但只需一些小的改动就能在 Python 2中运行。两个 Python 版本的主要区别是 urllib2 这个模块。

注:考虑到国内严酷的上网环境,译者测试原作的代码时直接卡在了注册 Imgur 账号这一步。因此为了方便起见,译者替换了图片爬取资源。一开始使用的某生产商提供的图片 API ,但不知道是网络原因还是其他原因导致程序在读取最后一张图片时无法退出。所以译者一怒之下采取了原始爬虫法,参考着 requests 和 beautifulsoup4 的文档爬取了某头条 253 张图片,以为示例。译文中的代码替换为译者使用的代码,如需原始代码请参考原文 Python Multithreading Tutorial: Concurrency and Parallelism

Python 多线程起步

首先让我们来创建一个名为 download.py 的模块。这个文件包含所有抓取和下载所需图片的函数。我们将全部功能分割成如下三个函数:

  • get_links
  • download_link
  • setup_download_dir

第三个函数,setup_download_dir 将会创建一个存放下载的图片的目录,如果这个目录不存在的话。

我们首先结合 requests 和 beautifulsoup4 解析出网页中的全部图片链接。下载图片的任务非常简单,只要通过图片的 URL 抓取图片并写入文件即可。

代码看起来像这样:

接下来我们写一个使用这些函数一张张下载图片的模块。我们把它命名为single.py。我们的第一个简单版本的 图片下载器将包含一个主函数。它会调用 setup_download_dir 创建下载目录。然后,它会使用 get_links 方法抓取一系列图片的链接,由于单个网页的图片较少,这里抓取了 5 个网页的图片链接并把它们组合成一个列表。最后调用 download_link 方法将全部图片写入磁盘。这是 single.py 的代码: