进程+线程+队列爬取斗图网

  • 需求:爬取斗图网数据
  • 首先我们使用线程的方式,爬取前4页数据
    • 准备工作
      • 图片链接存在页面源代码中
      • 但是,界面使用了懒加载技术,真正的url在data-original中
import requests
from lxml import etree
from concurrent.futures import ThreadPoolExecutor
import time

def get_src_url():
    for page in range(1, 5):
        url = f'https://www.pkdoutu.com/photo/list/?page={page}'
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
        }
        resp = requests.get(url =url,headers = headers)
        tree = etree.HTML(resp.text)
        data_original_list = tree.xpath("//li[@class='list-group-item']//a/img/@data-original")
        #下载图片
        with ThreadPoolExecutor(10) as t:
            for src_url in data_original_list:
                print(src_url)
                # download_img(src_url)
                t.submit(download_img,src_url)
                print('一张图片下载完成')

def download_img(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
    }
    img_data = requests.get(url=url,headers=headers).content
    img_name = url.split('/')[-1]
    with open(f'doutu/{img_name}','wb') as f:
        f.write(img_data)

if __name__ == '__main__':
    start = time.time()
    get_src_url()
    end = time.time()
    print(f'总共用时:{end - start}')
  • 使用上述代码,总共花了16s时间

  • 思考:

    • 我们在下载图片的时候,使用了多线程,但是获取图片url还是单线程的
    • 需要等待前一页数据下载完毕才会获取下一页图片的地址
    • 如果,我们使用两个进程,一个专门负责获取图片地址,另外一个专门下载图片,效率是不是会加快呢?
      • 但是,进程只能是不能直接通信的
      • 一般来讲,进程之间想要相互通信,我们有以下几种办法
        • 文件,效率慢,并发不好处理
        • 网络,需要写网络传输,麻烦
        • 队列--本篇使用方法,注意:不是所有队列都支持进程之间通信,python中使用multiprocess(底层就是网络传输)
        • 数据库
import requests
from lxml import etree
from concurrent.futures import ThreadPoolExecutor
import time
from multiprocessing import Queue
from multiprocessing import Process

#专门获取url
def get_src_url(q):
    for page in range(1, 5):
        url = f'https://www.pkdoutu.com/photo/list/?page={page}'
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
        }
        resp = requests.get(url =url,headers = headers)
        tree = etree.HTML(resp.text)
        data_original_list = tree.xpath("//li[@class='list-group-item']//a/img/@data-original")
        for src_url in data_original_list:
            print(src_url)
            # download_img(src_url)
            #把拿到的url 塞入队列
            q.put(src_url)
    q.put("结束")
    #第一个进程跑完后,塞入一个结束的标志,不然第二个进程不知道啥时候结束
    #注意:不能用判断队列为空结束

#第二个进程,负责下载图片
def img_process(q):     #从队列中提取url,下载图片
    with ThreadPoolExecutor(10) as t:
        while 1:       #不确定队列中有多少个,那就一直那,直到取到结束标志
            img_url = q.get()         #get是一个阻塞操作
            if img_url == '结束':
                break
            t.submit(download_img,img_url)


def download_img(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
    }
    img_data = requests.get(url=url,headers=headers).content
    img_name = url.split('/')[-1]
    with open(f'doutu/{img_name}','wb') as f:
        f.write(img_data)

if __name__ == '__main__':
    #准备队列
    start = time.time()
    q = Queue()   #主进程
    p1 = Process(target=get_src_url,args=(q,))    #单独开辟了内存空姐
    p2 = Process(target=img_process,args=(q,))

    p1.start()
    p2.start()

    p1.join()
    p2.join()

    end = time.time()
    print(f'总共用时:{end - start}')
posted @ 2023-01-19 22:57  Tony_xiao  阅读(88)  评论(0编辑  收藏  举报