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来判断。
最后说一件重要的事,只怕有同学错过。云计算现在白菜价了,2018年各大云计算厂商竞相降价,云服务器低至300元/年。现在不管是学习linux系统,运行长时间工作的爬虫,上线个人App或小程序,搭建网站做个人站长,都是时候上云服务了,错过这一波可能你就掉队。这里整理了一份云计算优惠活动产品列表,点击拿走不谢!
本文转自:http://blog.51cto.com/kaliarch/2162411
Python多线程爬图&Scrapy框架爬图的更多相关文章
- 使用scrapy框架爬取自己的博文(2)
之前写了一篇用scrapy框架爬取自己博文的博客,后来发现对于中文的处理一直有问题- - 显示的时候 [u'python\u4e0b\u722c\u67d0\u4e2a\u7f51\u9875\u76 ...
- Python网络爬虫之Scrapy框架(CrawlSpider)
目录 Python网络爬虫之Scrapy框架(CrawlSpider) CrawlSpider使用 爬取糗事百科糗图板块的所有页码数据 Python网络爬虫之Scrapy框架(CrawlSpider) ...
- Python逆向爬虫之scrapy框架,非常详细
爬虫系列目录 目录 Python逆向爬虫之scrapy框架,非常详细 一.爬虫入门 1.1 定义需求 1.2 需求分析 1.2.1 下载某个页面上所有的图片 1.2.2 分页 1.2.3 进行下载图片 ...
- Python爬虫进阶之Scrapy框架安装配置
Python爬虫进阶之Scrapy框架安装配置 初级的爬虫我们利用urllib和urllib2库以及正则表达式就可以完成了,不过还有更加强大的工具,爬虫框架Scrapy,这安装过程也是煞费苦心哪,在此 ...
- scrapy框架爬取糗妹妹网站妹子图分类的所有图片
爬取所有图片,一个页面的图片建一个文件夹.难点,图片中有不少.gif图片,需要重写下载规则, 创建scrapy项目 scrapy startproject qiumeimei 创建爬虫应用 cd qi ...
- Python使用Scrapy框架爬取数据存入CSV文件(Python爬虫实战4)
1. Scrapy框架 Scrapy是python下实现爬虫功能的框架,能够将数据解析.数据处理.数据存储合为一体功能的爬虫框架. 2. Scrapy安装 1. 安装依赖包 yum install g ...
- 基于python的scrapy框架爬取豆瓣电影及其可视化
1.Scrapy框架介绍 主要介绍,spiders,engine,scheduler,downloader,Item pipeline scrapy常见命令如下: 对应在scrapy文件中有,自己增加 ...
- python爬虫---scrapy框架爬取图片,scrapy手动发送请求,发送post请求,提升爬取效率,请求传参(meta),五大核心组件,中间件
# settings 配置 UA USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, l ...
- 爬虫入门(四)——Scrapy框架入门:使用Scrapy框架爬取全书网小说数据
为了入门scrapy框架,昨天写了一个爬取静态小说网站的小程序 下面我们尝试爬取全书网中网游动漫类小说的书籍信息. 一.准备阶段 明确一下爬虫页面分析的思路: 对于书籍列表页:我们需要知道打开单本书籍 ...
随机推荐
- pkill有的时候并不能杀死进程?
pkill的用法:http://man.linuxde.net/pkill 根据进程命令行,杀死进程 如下intellij.go代码为一个代理服务器,把本地请求转向一个代理 package main ...
- ubuntu下进行ssh
ubuntu下进行ssh 一, 介绍 SSH 为 Secure Shell 的缩写,由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为建立 ...
- PowerDesinger15设置字体大小
使用PowerDesigner时,它默认table的字体大小颜色等很难看: 假设通过 Symbol ---> Format进行设置.仅仅能对选中的最改动,新建的Table无效. 能够通过例如以下 ...
- Java设计模式—单例设计模式(Singleton Pattern)全然解析
转载请注明出处:http://blog.csdn.net/dmk877/article/details/50311791 相信大家都知道设计模式,听的最多的也应该是单例设计模式,这种模式也是在开发中用 ...
- react jsx 常见问题
问题一: Expected to return a value in arrow function 解决方案: 修改后: // 使用 store return ( <div> <h1 ...
- js算法:分治法-循环赛事日程表
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...
- 字节序:Big Endian 和 Little Endian
一.字节序 字节序,也就是字节的顺序,指的是多字节的数据在内存中的存放顺序. 在几乎所有的机器上,多字节对象都被存储为连续的字节序列.例如:如果C/C++中的一个int型变量 a 的起始地址是& ...
- php高效获取数据分页
mysql.php 获取数据库中的记录,全然个人经验总结,仅供參考! <? php /** *PHP+MYSQL数据库基本功能 *http://blog.csdn.net/yown */ ### ...
- NPOI2.2.0.0实例详解(十)—设置EXCEL单元格【文本格式】 NPOI 单元格 格式设为文本 HSSFDataFormat
NPOI2.2.0.0实例详解(十)—设置EXCEL单元格[文本格式] 2015年12月10日 09:55:17 阅读数:3150 using System; using System.Collect ...
- hdu5375 Gray code(DP)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5375 题目大意:给你一个二进制串,带'?'的位置能够由你来决定填'1'还是'0',补充完整之后转换成 ...
