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框架,昨天写了一个爬取静态小说网站的小程序 下面我们尝试爬取全书网中网游动漫类小说的书籍信息. 一.准备阶段 明确一下爬虫页面分析的思路: 对于书籍列表页:我们需要知道打开单本书籍 ...
随机推荐
- Windows系统下查看已共享的文件夹的方法
电脑使用时间比较长,共享过好几次文件夹,现在想取消共享,但共享文件夹的路径隐藏得太深,要怎么样才能快速找到共享文件夹的实际路径呢?” “其实现在单位常见的方法都是用网上邻居的共享文件夹,共享的文件夹也 ...
- js下载
下载用ajax不好使,得用表单提交的方式 download:function(url,paramObj){ var doc = document; //使用一个隐藏的form表单执行提交,没有则创建 ...
- poj 2318 TOYS & poj 2398 Toy Storage (叉积)
链接:poj 2318 题意:有一个矩形盒子,盒子里有一些木块线段.而且这些线段坐标是依照顺序给出的. 有n条线段,把盒子分层了n+1个区域,然后有m个玩具.这m个玩具的坐标是已知的,问最后每一个区域 ...
- 本地调用jni之VC++无法导入问题
事实上非常easy,无法导入头文件就自己新建呗 1. 首先编写java代码 class Vrv { public native void printVersion(); static { System ...
- MySQl 子查询,左右连接,多表连接学习笔记
1.子查询是指在还有一个查询语句中的SELECT子句. 例句: SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2); 当中, ...
- poj1151==codevs 3044 矩形面积求并
Atlantis Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 21511 Accepted: 8110 Descrip ...
- 关于编译(javac),import,package的再理解
1.若我们在A.java中用到了类B,当我们仅仅用 javac A.java 编译A时,编译器也会去寻找B,若类B依然是源文件,也会自动编译它.在使用javac和java命令时,有一个参数选项 -ve ...
- 最大heap
1 什么是最大heap 最大heap是一棵完全二叉树.每棵子树的根比它的两棵子树上的节点都要大. 2 建堆的过程 function max_heaptify(A): for (i = n/2向下取整: ...
- Codeforces Round #311 (Div. 2)C. Arthur and Table
C. Arthur and Table time limit per test 1 second memory limit per test 256 megabytes input standard ...
- FileStream StreamWriter StreamReader BinaryReader
FileStream vs/differences StreamWriter? http://stackoverflow.com/questions/4963667/filestream-vs-dif ...