哈哈,之前说过的三四天一更,这次足足等了一周= =主要是没时间,趁着今天周六写点东西吧
这一篇主要介绍python中各异步/网络/分布式框架,教你如何不使用scrapy/pyspider进行异步/分布式爬虫。可能你会觉得,为什么有scrapy不用,要自己用别的库手写爬虫呢?其实很简单,scrapy是一个别人写好的框架,优点是提供了很多别人写好的接口,也可以通过简单的代码来自定义很多功能,而缺点其实也在于此,有些简单的功能其实只需要几行代码就能做到,而到了scrapy中你可能要用十多行甚至更多去实现它。另外,scrapy最大的缺点就是它的报错,由于它是基于twisted的,出错后并不会停止爬虫,而我们要捕捉错误就必须自定义中间件,使其通过我们自己想要的方式去处理它。因此,你必须提前想好哪儿可能出错,在爬虫之前去处理它,因为开始爬虫后,错误并不会终止你的爬虫程序。而自己写的异步处理就不会出现这种问题,你可以用一万种方式使程序出错后终止整个爬虫。
开始之前我们先来一段简单的requests爬虫以及多进程和scrapy爬虫,来看看他们的性能如何,方便后面的比较。目标网站:
正在播放《蜘蛛侠:英雄远征》 - 高清线路 - 小收影院www.p4yy.com这是百度搜蜘蛛侠英雄远征免费观看后出来的第一个网站,所以大家不要喷我分享盗版资源,是百度分享的。。。我们的目标是把这部电影爬下来。
0. requests爬虫
import requests
import re
import time
start_time = time.time()
url = 'https://rescdn.yishihui.com/longvideo/transcode/pic/live/2019070363431356wFLNws3GGuosTiVem.m3u8'
m3u8 = requests.get(url).text
url_list = re.findall(r'.*ts', m3u8)
with open('requests_spider.ts', 'wb') as f:
for url in url_list:
ts = requests.get('https://rescdn.yishihui.com/longvideo/transcode/pic/live/' + url).content
f.write(ts)
print(url, '下载完毕')
print('下载完毕n消耗时间:', time.time() - start_time)
下面是运行时间
可以看到只用requests爬虫,用了679秒下载完了整部电影
接下来是多线程,多线程thearding或者future都可以,这里贴一个future的demo:
import requests
import re
import time
import os
from concurrent import futures
start_time = time.time()
url = 'https://rescdn.yishihui.com/longvideo/transcode/pic/live/2019070363431356wFLNws3GGuosTiVem.m3u8'
m3u8 = requests.get(url).text
url_list = re.findall(r'.*ts', m3u8)
def get_ts(url):
ts = requests.get('https://rescdn.yishihui.com/longvideo/transcode/pic/live/' + url).content
with open(url[-8:], 'wb') as f:
f.write(ts)
print(url, '下载完毕')
executor = futures.ThreadPoolExecutor(max_workers=20)
future_tasks = [executor.submit(get_ts, url) for url in url_list]
futures.wait(future_tasks, return_when=futures.ALL_COMPLETED)
download_time = time.time() - start_time
with open('future_spider.ts', 'wb') as fff:
for url in url_list:
file_name = url[-8:]
with open(file_name, 'rb') as f:
byte = f.read()
fff.write(byte)
print(file_name, '加入完毕')
os.remove(file_name)
print('下载完毕n下载消耗时间:',download_time , 'n总消耗时间:', time.time() - start_time)
需要注意的是,多线程和后面的异步/分布式都不能直接将ts片段拼接到一起,必须全部下载完毕后依次读取拼接,这是因为并发/异步/分布式都是发起/接收请求都是无序的。那我们看一下多线程的消耗时间
可以看到,多线程用了338秒,需要注意的是,由于在第一次测试中,打开文件的操作只有一次,而多线程中打开文件操作有着800多次,因此实际请求的时间应该还会再短一点。
再接下来是协程,即异步爬虫,gevent和aiohttp都可以写,鉴于aiohttp网上一堆教程(同时鉴于gevent代码量更少),写一个简单的gevent的demo
from gevent import monkey
monkey.patch_all()
import os
import re
import time
import gevent
import requests
start_time = time.time()
url = 'https://rescdn.yishihui.com/longvideo/transcode/pic/live/2019070363431356wFLNws3GGuosTiVem.m3u8'
m3u8 = requests.get(url).text
url_list = re.findall(r'.*ts', m3u8)
def get_ts(url):
ts = requests.get('https://rescdn.yishihui.com/longvideo/transcode/pic/live/' + url).content
with open(url[-8:], 'wb') as f:
f.write(ts)
print(url, '下载完毕')
gevent.joinall([gevent.spawn(get_ts, url) for url in url_list])
download_time = time.time() - start_time
#注意这是另一个文件
with open('gevent_spider.ts', 'wb') as fff:
for url in url_list:
file_name = url[-8:]
with open(file_name, 'rb') as f:
byte = f.read()
fff.write(byte)
print(file_name, '加入完毕')
os.remove(file_name)
print('下载完毕n下载消耗时间:',download_time , 'n总消耗时间:', time.time() - start_time)
注意这段代码只能在linux上跑,windows上关于进程线程协程的程序总是随缘出错,线程协程尤为明显。(我本来用腾讯云的服务器跑了这段demo,但是之前的是用windows跑的,又懒得再拿linux跑+截图,而两者的网络环境/硬件都不一样,对比起来没什么意义,而且这段代码不是很严谨,patch_all会给文件的读写操作也打上猴子补丁,跟之前的几个没法比了,太快了)干脆直接告诉大家结果吧。。使用协程进行异步爬虫是远远快于前两个的。
说完这些暂停一下,介绍几个扩展库吧
- grequests,是一个gevent和requests的结合,但是功能比较单一,适合写个小demo对网站爬虫测试用,以下为grequests源码
教程就不发了,因为用的确实不是很多,不过源码值得一看,能让你更熟练的运用gevent。
- aiohttp,搭配asyncio即可进行异步爬虫,网上教程一大堆,也不多说。这个源码有兴趣的可以看看,没必要死磕,因为虽然很好但是大多数代码都用在了web搭建上,下面是一个简单的demo和源码
- twisted,这个如果你是爬虫新手,不必了解太多,但是如果你不了解它,永远不要说自己精通scrapy。建议把下面链接收藏起来,平时没事的时候看两眼
多线程和异步说完,就是分布式了。scrapy和pyspider实现分布式也不多说,百度一下你就知道。下面简单介绍几个分布式的框架
- multiprocessing的managers模块。我们知道,multiprocessing是多进程模块,而它的子模块managers支持把进程分布到多台机器中,进而实现分布式程序。demo如下
这是系统自带的库,源码可以自己在python/libs/site-packages中学习
- celery,圈重点,这是一个非常强大的分布式框架,配合redis或rabbitMQ(你可以理解为一个和redis类似的消息收发中转站)能够简单快速的搭建分布式系统,它还自带定时功能,定时爬虫特别方便。不过......由于本人还在学习阶段,对它也并没有多深的理解,就直接甩给大家一份官方文档吧= =目前自己也在看这玩意儿。
celery源码:
celery/celerygithub.com- gerapy,这是一个崔大大基于scrapy,scrapyd,scrapy-redis,scrapyd-api,scrapy-splash,jinjia2,django,vue.js,docker等编写的分布式爬虫框架。爬虫语法建构什么的和scrapy一样,支持直接部署爬虫,前端的可视化监控,一台主机管理整个分布式爬虫。安装直接pip install gerapy即可,源码如下:
其实大多都是调用已有的api进行封装,所以源码不是很难理解,建议没事可以看看,也算是巩固自己的scrapy了,用法在readme中有个大概,主要还是自己摸索,不是很难学会。崔大大nb!( 破音声~~)
这篇文章就到这儿了,以后每周一更,周六或者周日~
因为网上的app爬虫教程太少了,而且质量都很一般。pc端网页爬虫大多也是教你怎么反爬,很少有教你怎么全方面提高爬虫效率的,下一篇可能写这两个中的一个(app爬虫可能要连载好多)。想看哪个或者爬虫方面有问题的都可以评论留言(拯救零回复)或者直接私信探讨。点不点赞收不收藏评不评论其实都无所谓,大佬们给个关注行不行(手动狗头)