python scrapy框架基如何实现多线程_Python多线程爬图&Scrapy框架爬图

【小宅按】对于日常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 &

查看系统负载查看文件信息

3.2 Scrapy框架爬图启动爬虫nohup doutulai/scrapy_doutulai/scrapy_doutulai/main.py &

查看系统负载查看文件信息爬取的图片

3.3 持久化存储在OSS上

最终配合阿里云OSS的API来将图片持久化存储在对象存储内。

整体image下载地址:图片压缩包

总结经测试笔者写的多线程爬图,CPU使用率很高,磁盘IO很大。Scrapy默认也是10个线程,但由于自有磁盘IO操作,CPU使用平稳。

虽然Python有GIL,但是在适当的场景下利用其多线程会很大程度的提升效率。之前如果单线程10分钟,利用多线程可以缩短3/2的 时间,具体需要结合线程数,磁盘与网络IO来判断。

更多精彩内容,请滑至顶部点击右上角关注小宅哦~

来源:51CTO 作者 KaliArch

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值