爬虫实战——结合多进程、线程池爬取多张图片

需求描述

需求:结合多进程和线程池,下载一个图片网站某一页的全部图片 将上述需求分为两个进程执行:

  • 进程1、获取图片下载地址;
  • 进程2、根据图片下载地址下载图片(下载图片的时候使用线程池)

代码实现

import requests
from urllib import parse
from lxml import etree
# 多进程中的队列用于在不同的进程中传递信息
from multiprocessing import Process, Queue
from concurrent.futures import ThreadPoolExecutor


def get_img_url(q):
    """
    从图片详情页获取图片下载地址
    """
    # 图片首页网页链接
    url = 'https://m.mms591.com/filter.php?q=dongwu_zhiwu-0-0-755-2'
    resp_img = requests.get(url)
    # print(resp_img.text)
    # 用xpath解析网页,获取每个图片详情页的url
    tree = etree.HTML(resp_img.text)
    hrefs = tree.xpath('//div[@class="am-list-news-bd"]//a/@href')
    for href in hrefs:  # 每一个href是图片详情页的链接
        # print(href)
        # 拼接图片详情页链接
        href = parse.urljoin(url, href)
        # print(href)
        # 向图片详情页url发送请求,获取图片的下载地址
        child_resp = requests.get(href)
        child_tree = etree.HTML(child_resp.text)
        # 从HTML页面中解析出图片下载地址
        img_src = child_tree.xpath('/html/body/div[3]/div[2]/article/div[1]/a/img/@src')[0]
        # print(img_src)
        # 将图片下载地址放入到队列中
        q.put(img_src)
        print(f'获取图片地址{img_src}成功')
    # 向队列中添加一个表示结束的标志,否则下载图片的进程将会一直处于阻塞状态,不能结束程序
    q.put('over!')


def downloading(img_src):
    # 下载图片
    name = img_src.split("/")[-1]  # 图片名称
    with open(f'./img/{name}', mode='wb') as f:
        resp = requests.get(img_src)
        f.write(resp.content)
    print(f'{name}下载完成')


def download_img(q):
    # 用线程池下载图片
    with ThreadPoolExecutor(3) as t:
        while True:
            # 从队列中取出图片下载地址
            # 如果队列为空,就会一直阻塞,直到队列中有值
            img_src = q.get()
            if img_src == 'over!':  # 图片已经全部下载完成,结束程序运行
                break
            # 提交任务
            t.submit(downloading, img_src)


if __name__ == '__main__':
    # 由于进程之间的内存、资源是相互隔离的,所以两个进程之间不能直接通信,要通过队列等方式才能传递信息
    q = Queue()
    p1 = Process(target=get_img_url, args=(q,))
    p2 = Process(target=download_img, args=(q,))
    p1.start()
    p2.start()

你可能感兴趣的:(#,python,爬虫实战,python,爬虫,多进程,线程池)