爬虫项目介绍
本次爬虫项目将爬取豆瓣 Top250 电影的图片, 其网址为: https://movie.douban.com/top250 , 具体页面如下图所示:
本次爬虫项目将分别不使用多线程和使用多线程来完成, 通过两者的对比, 显示出多线程在爬虫项目中的巨大优势. 本文所使用的多线程用到了 concurrent.futures 模块, 该模块是 Python 中最广为使用的并发库, 它可以非常方便地将任务并行化. 在 concurrent.futures 模块中, 共有两种并发模块, 分别如下:
多线程模式: ThreadPoolExecutor, 适合 IO 密集型任务;
多进程模式: ProcessPoolExecutor, 适合计算密集型任务.
具体的关于该模块的介绍可以参考其官方网址: https://docs.python.org/3/library/concurrent.futures.html .
本次爬虫项目将会用到 concurrent.futures 模块中的 ThreadPoolExecutor 类, 多线程豆瓣 Top250 电影图片. 下面将会给出本次爬虫项目分别不使用多线程和使用多线程的对比, 以此来展示多线程在爬虫中的巨大优势.
不使用多线程
首先, 我们不使用多线程来下载豆瓣 Top250 电影图片, 其完整的 Python 代码如下:
- import time
- import requests
- import urllib.request
- from bs4 import BeautifulSoup
- # 该函数用于下载图片
- # 传入函数: 网页的网址 url
- def download_picture(url):
- # 获取网页的源代码
- r = requests.get(url)
- # 利用 BeautifulSoup 将获取到的文本解析成 HTML
- soup = BeautifulSoup(r.text, "lxml")
- # 获取网页中的电影图片
- content = soup.find('div', class_='article')
- images = content.find_all('img')
- # 获取电影图片的名称和下载地址
- picture_name_list = [image['alt'] for image in images]
- picture_link_list = [image['src'] for image in images]
- # 利用 urllib.request..urlretrieve 正式下载图片
- for picture_name, picture_link in zip(picture_name_list, picture_link_list):
- urllib.request.urlretrieve(picture_link, 'E://douban/%s.jpg' % picture_name)
- def main():
- # 全部 10 个网页
- start_urls = ["https://movie.douban.com/top250"]
- for i in range(1, 10):
- start_urls.append("https://movie.douban.com/top250?start=%d&filter=" % (25 * i))
- # 统计该爬虫的消耗时间
- t1 = time.time()
- print('*' * 50)
- for url in start_urls:
- download_picture(url)
- t2 = time.time()
- print('不使用多线程, 总共耗时:%s'%(t2-t1))
- print('*' * 50)
- main()
其输出结果如下:
**************************************************
不使用多线程, 总共耗时: 79.93260931968689
**************************************************
去 E 盘中的 douban 文件夹查看, 如下图:
我们可以看到, 在不使用多线程的情况下, 这个爬虫总共耗时约 80s, 完成了豆瓣 Top250 电影图片的下载.
使用多线程
接下来, 我们使用多线程来下载豆瓣 Top250 电影图片, 其完整的 Python 代码如下:
- import time
- import requests
- import urllib.request
- from bs4 import BeautifulSoup
- from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
- # 该函数用于下载图片
- # 传入函数: 网页的网址 url
- def download_picture(url):
- # 获取网页的源代码
- r = requests.get(url)
- # 利用 BeautifulSoup 将获取到的文本解析成 HTML
- soup = BeautifulSoup(r.text, "lxml")
- # 获取网页中的电影图片
- content = soup.find('div', class_='article')
- images = content.find_all('img')
- # 获取电影图片的名称和下载地址
- picture_name_list = [image['alt'] for image in images]
- picture_link_list = [image['src'] for image in images]
- # 利用 urllib.request..urlretrieve 正式下载图片
- for picture_name, picture_link in zip(picture_name_list, picture_link_list):
- urllib.request.urlretrieve(picture_link, 'E://douban/%s.jpg' % picture_name)
- def main():
- # 全部 10 个网页
- start_urls = ["https://movie.douban.com/top250"]
- for i in range(1, 10):
- start_urls.append("https://movie.douban.com/top250?start=%d&filter=" % (25 * i))
- # 统计该爬虫的消耗时间
- print('*' * 50)
- t3 = time.time()
- # 利用并发下载电影图片
- executor = ThreadPoolExecutor(max_workers=10) # 可以自己调整 max_workers, 即线程的个数
- # submit()的参数: 第一个为函数, 之后为该函数的传入参数, 允许有多个
- future_tasks = [executor.submit(download_picture, url) for url in start_urls]
- # 等待所有的线程完成, 才进入后续的执行
- wait(future_tasks, return_when=ALL_COMPLETED)
- t4 = time.time()
- print('使用多线程, 总共耗时:%s' % (t4 - t3))
- print('*' * 50)
- main()
其输出结果如下:
**************************************************
使用多线程, 总共耗时: 9.361606121063232
**************************************************
再去 E 盘中的 douban 文件夹查看, 发现同样也下载了 250 张电影图片.
总结
通过上述两个爬虫程序的对比, 我们不难发现, 同样是下载豆瓣 Top250 电影, 10 个网页中的图片, 在没有使用多线程的情况下, 总共耗时约 80s, 而在使用多线程 (10 个线程) 的情况下, 总共耗时约 9.5 秒, 效率整整提高了约 8 倍. 这样的效率提升在爬虫中无疑是令人兴奋的.
希望读者在看了本篇博客后, 也能尝试着在自己的爬虫中使用多线程, 说不定会有意外的惊喜哦~~ 因为, 大名鼎鼎的 Python 爬虫框架 Scrapy, 也是使用多线程来提升爬虫速度的哦!
注意: 本人现已开通两个微信公众号: 因为 Python(微信号为: python_math)以及轻松学会 Python 爬虫(微信号为: easy_web_scrape), 欢迎大家关注哦~~
来源: https://www.cnblogs.com/jclian91/p/9200948.html