Python多线程爬图&Scrapy框架爬图

栏目: 编程工具 · 发布时间: 6年前

内容简介:对于日常Python爬虫由于效率问题,本次测试使用多线程和Scrapy框架来实现抓取由于IO操作不使用CPU,对于IO密集(磁盘IO/网络IO/人家交互IO)型适合用多线程,对于计算密集型:建议用多进程。但是对于python这种解释性语言带有GIL(全局解释器锁)解释器锁,同一时刻只能有一个线程在运行,遇到IO操作才会释放切换。感觉没必要多线程,但是经测试,多线程还是在很大程度能够提升效率。

一、背景

对于日常 Python 爬虫由于效率问题,本次测试使用多线程和Scrapy框架来实现抓取 斗图来 表情。

由于IO操作不使用CPU,对于IO密集(磁盘IO/网络IO/人家交互IO)型适合用多线程,对于计算密集型:建议用多进程。

  • 进程:
    优点:充分利用多核CPU(能够同时进行多个操作)
    缺点:系统资源消耗大,重新开辟内存空间
  • 线程:
    优点:共享内存,IO操作可以创造出并发操作
    缺点:抢占资源,请求上下文切换消耗时间

但是对于python这种解释性语言带有GIL(全局解释器锁)解释器锁,同一时刻只能有一个线程在运行,遇到IO操作才会释放切换。感觉没必要多线程,但是经测试,多线程还是在很大程度能够提升效率。

二、代码

2.1 多线程爬图

定义了10个线程去爬去每个页面的具体表情的url存放在类中的img_url_list内,然后通过10个线程从这个列表内取url进行本地图片下载。

核心代码

# 定义全局页面url列表
    page_url_list = []
    # 定义具体各表情图片url列表
    img_url_list = []
    # 定义rlock进程锁
    rlock = threading.RLock()

    def __init__(self,page_number=10,img_dir='imgdir',thread_number=5):
        """
        :param page_number: 抓去多少个页面,默认10
        :param img_dir: 定义图片目录
        :param thread_number:默认5个线程
        """
        self.spider_url = 'https://www.doutula.com/photo/list/?page='
        self.page_number = int(page_number)
        self.img_dir = img_dir
        self.thread_num = thread_number

 def __add_urllist(self):
        """
        定义从page_url_list 爬取具体的image的url
        :return:
        """
        while True:
            DutuSpider.rlock.acquire()
            if len(DutuSpider.page_url_list) == 0:
                DutuSpider.rlock.release()
                break
            else:
                page_url = DutuSpider.page_url_list.pop()
                DutuSpider.rlock.release()
                response = requests.get(page_url, headers=self.__set_header())
                soup = BeautifulSoup(response.content,'lxml')
                sou_list = soup.find_all('img',attrs={'class':'img-responsive lazy image_dta'})
                # 将获取到的具体表情图标的url保存添加进img_url_list 列表
                for url_content in sou_list:
                    DutuSpider.rlock.acquire()
                    DutuSpider.img_url_list.append(url_content['data-original'])
                    DutuSpider.rlock.release()

    def __download_img(self):
        """
        从image_url_list中来下载image到本地
        :return:
        """
        while True:
            DutuSpider.rlock.acquire()
            if len(DutuSpider.img_url_list) == 0:
                DutuSpider.rlock.release()
                continue
            else:
                img_url = DutuSpider.img_url_list.pop()
                DutuSpider.rlock.release()
                try:
                    # 图片名称
                    img_name = img_url.split('/')[-1]
                    # 下载图片
                    urllib.urlretrieve(img_url,os.path.join(self.img_dir,img_name))
                    print('donload img %s' % img_name)
                except Exception as e:
                    pass

    def run(self):
        # 启动thread_num个进程来爬去具体的img url 链接
        for th in range(self.thread_num):
            add_pic_t = threading.Thread(target=self.__add_urllist)
            add_pic_t.start()

        # 启动thread_num个来下载图片
        for img_th in range(self.thread_num):
            download_t = threading.Thread(target=self.__download_img)
            download_t.start()

2.2 Scrapy框架爬图

利用Scrapy框架来爬取表情,items定义图片名称和每个图片的url,scrapy主文件来爬取每个图片的url来返回,piplines来进行本地文件存储。

核心代码

# items,定义img的url和name
class ScrapyDoutulaiItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 定义图片url和name
    img_url = scrapy.Field()
    img_name = scrapy.Field()

# 爬虫文件
class DoutulaiSpiderSpider(scrapy.Spider):
    name = 'doutulai_spider'
    allowed_domains = ['www.doutula.com']
    start_urls = ['https://www.doutula.com/photo/list/']
    page = 1

    def parse(self, response):
        content_items = ScrapyDoutulaiItem()
        # 解析img_url列表,拿到图片的url和,图片名称
        img_url_list = response.xpath('//img[@class="img-responsive lazy image_dta"]')
        # page_number = response.xpath('//*[@id="pic-detail"]/div/div[3]/div[3]/ul/li[12]/a/text()').extract_first()
        page_number = response.xpath('//a[@class="page-link"][last()]/text()').extract_first()

        for img_content in img_url_list:
            content_items['img_url'] = img_content.xpath('./@data-original').extract_first()
            content_items['img_name'] = img_content.xpath('./@data-original').extract_first().split('/')[-1]
            print(content_items)
            yield content_items
        # 不断爬取新页面
        if self.page <= page_number:
            self.page += 1
            next_url = self.start_urls[0] + '?page=' + str(self.page)
            yield scrapy.Request(next_url)

#pipeline下载图片
from urllib import urlretrieve
from scrapy_doutulai.settings import DOWNLOAD_DIR

class ScrapyDoutulaiPipeline(object):
    def __init__(self):
        """
        判断下载目录是否存在
        """
        if not os.path.exists(DOWNLOAD_DIR):
            os.makedirs(DOWNLOAD_DIR)

    def process_item(self, item, spider):
        """
        下载图片
        :param item:
        :param spider:
        :return:
        """
        try:
            filename = os.path.join(DOWNLOAD_DIR,item['img_name'])
            print(filename)
            urlretrieve(item['img_url'],filename)
        except Exception as e:
            pass

三、测试

测试使用2C2G centos7.4,python2.7版本,启动线程10个,爬去1000页的表情信息

3.1 多线程测试

  • 启动爬虫
    nohup doutulai/multithreading_spider/dutulai_spider.py &
  • 查看系统负载
    Python多线程爬图&Scrapy框架爬图 Python多线程爬图&Scrapy框架爬图
  • 查看文件信息

    Python多线程爬图&Scrapy框架爬图

    3.2 Scrapy框架爬图

  • 启动爬虫
    nohup doutulai/scrapy_doutulai/scrapy_doutulai/main.py &
  • 查看系统负载
    Python多线程爬图&Scrapy框架爬图 Python多线程爬图&Scrapy框架爬图
  • 查看文件信息

    Python多线程爬图&Scrapy框架爬图
  • 爬取的图片
    Python多线程爬图&Scrapy框架爬图

四、总结

  • 经测试自己写的多线程爬图,CPU使用率很高,磁盘IO很大。Scrapy默认也是10个线程,但由于自己有磁盘IO操作,CPU使用平稳。
  • 虽然Python有GIL,但是在适当的场景下利用其多线程会很大程度的提升效率。之前如果单线程10分钟,利用多线程可以缩短3/2的 时间,具体需要结合线程数,磁盘与网络IO来判断。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

High Performance Python

High Performance Python

Andrew Lewis / O'Reilly Media, Inc. / 2010-09-15 / USD 34.99

Chapter 1. Introduction Section 1.1. The High Performance Buzz-word Chapter 2. The Theory of Computation Section 2.1. Introduction Section 2.2. Problems Section 2.3. Models of Computati......一起来看看 《High Performance Python》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具