Python3,此神器,让爬取速率提升10倍。
让爬取速率提升10倍的神器
- 1、引言
- 2、requests_cache
-
- 2.1 介绍
- 2.2 安装
- 2.3 代码实例
-
- 2.3.1 CachedSession 方法
- 2.3.2 install_cache方法
- 2.3.3 Cache Headers 方法
- 3、 总结
1、引言
小屌丝:有没有能提升 爬取速率的方法,
小鱼:嗯,提升方法有好多种,例如 多线程、装饰器,都可以啊
小屌丝:嗯,那有没有其他的方法呢?
小鱼:额,容我想一下,
小鱼:嘿~ 想到了
小屌丝:那是啥?
小鱼:requests_cache
此时,小屌丝的表情
2、requests_cache
2.1 介绍
requests_cache是 requests 库的一个扩展包,利用它我们可以非常方便地实现请求的缓存,直接得到对应的爬取结果。
2.2 安装
老规矩, pip 方式安装:
pip install requests-cache
其他方式安装:
《Python3,选择Python自动安装第三方库,从此跟pip说拜拜!!》
《Python3:我低调的只用一行代码,就导入Python所有库!!》
安装完,我们就来看看它的用法。
2.3 代码实例
2.3.1 CachedSession 方法
1、requests默认请求
为了能体现出它的速度,我们先写一个默认请求
代码展示
# -*- coding:utf-8 -*-# @Time : 2022-03-18# @Author : carl_DJ'''requests 方法请求'''import requestsimport time#开始时间start = time.time()#sessionsession = requests.session()#循环爬取,10次for i in range(10): session.get('http://httpbin.org/delay/2') print(f'Finish{i + 1} requests')end = time.time()print('Cost time', end - start)
运行结果
Finish2 requestsFinish3 requestsFinish4 requestsFinish5 requestsFinish6 requestsFinish7 requestsFinish8 requestsFinish9 requestsFinish10 requestsCost time 24.35784935951233Process finished with exit code 0
我们可以看到 花费了24+秒
那么,我们使用CachedSession 方法来看看,能不能提速
2、CachedSession 方法
代码展示
# -*- coding:utf-8 -*-# @Time : 2022-03-18# @Author : carl_DJimport requests_cacheimport timestart = time.time()#CachedSession方法,在本地生成 demo_cache.sqlitesession = requests_cache.CachedSession('demo_cache')for i in range(10): session.get('http://httpbin.org/delay/2') print(f'Finish{i + 1} requests')end = time.time()print('Cost time', end -start)
运行结果
Finish1 requestsFinish2 requestsFinish3 requestsFinish4 requestsFinish5 requestsFinish6 requestsFinish7 requestsFinish8 requestsFinish9 requestsFinish10 requestsCost time 8.624990701675415Process finished with exit code 0
本地生成demo_cache.sqlite数据库
文件的内容,我们看下
我们可以可以看到,这个 key-value 记录中的 key 是一个 hash 值,value 是一个 Blob 对象,里面的内容就是 Response 的结果。
可以猜到,每次请求都会有一个对应的 key 生成,然后 requests-cache 把对应的结果存储到了 SQLite 数据库中了,后续的请求和第一次请求的 URL 是一样的,经过一些计算它们的 key 也都是一样的,所以后续 2-10 请求就立马返回了。
是的,利用这个机制,我们就可以跳过很多重复请求了,大大节省爬取时间。
2.3.2 install_cache方法
1、Patch 写法
当然,我们还有另一个方法,在不修改原有的代码请求方式,
追加一个方法,来实现爬取速率的提升。
代码展示
# -*- coding:utf-8 -*-# @Time : 2022-03-18# @Author : carl_DJimport requestsimport requests_cacheimport time#调用requests_cache.install_cache方法requests_cache.install_cache('demo_path_cache')start = time.time()session = requests.session()for i in range(10): session.get('http://httpbin.org/delay/2') print(f'Finish{i + 1} requests')end = time.time()print('Cost time', end -start)
运行结果
Finish1 requestsFinish2 requestsFinish3 requestsFinish4 requestsFinish5 requestsFinish6 requestsFinish7 requestsFinish8 requestsFinish9 requestsFinish10 requestsCost time 7.516860723495483Process finished with exit code 0
生成文件
2、修改配置
前两个demo,requests-cache 默认使用了 SQLite 作为缓存对象,
而我们这次,使用filesystem 作为缓存对象
代码展示
# -*- coding:utf-8 -*-# @Time : 2022-03-18# @Author : carl_DJimport requestsimport requests_cacheimport time#使用filesystem作为缓存对象requests_cache.install_cache('demo_file_cache', backend='filesystem')start = time.time()session = requests.session()for i in range(10): session.get('http://httpbin.org/delay/2') print(f'Finish{i + 1} requests')end = time.time()print('Cost time', end -start)
运行结果
其他后端有:
[‘dynamodb’, ‘filesystem’, ‘gridfs’, ‘memory’, ‘mongodb’, ‘redis’, ‘sqlite’]
具体的差异,我们来看下
Backend | Class | Alias | Dependencies |
---|---|---|---|
SQLite | SQLiteCache | sqlite | |
Redis | RedisCache | redis | redis-py |
MongoDB | MongoCache | mongodb | pymongo |
GridFS | GridFSCache | gridfs | pymongo |
DynamoDB | DynamoDbCache | dynamodb | boto3 |
Filesystem | FileCache | filesystem | |
Memory | BaseCache | memory |
如果使用redis
backend = requests_cache.RedisCache(host='localhost', port=6379)requests_cache.install_cache('demo_redis_cache', backend=backend)
3、只对某一个请求进行缓存
# -*- coding:utf-8 -*-# @Time : 2022-03-18# @Author : carl_DJimport timeimport requestsimport requests_cache#allowable_methods 方式,只对post请求进行缓存requests_cache.install_cache('demo_post_cache', allowable_methods=['POST'])start = time.time()session = requests.Session()for i in range(10): session.get('http://httpbin.org/delay/2') print(f'Finished {i + 1} requests')end = time.time()print('Cost time for get', end - start)start = time.time()for i in range(10): session.post('http://httpbin.org/delay/2') print(f'Finished {i + 1} requests')end = time.time()print('Cost time for post', end - start)
运行结果
Finished 1 requestsFinished 2 requestsFinished 3 requestsFinished 4 requestsFinished 5 requestsFinished 6 requestsFinished 7 requestsFinished 8 requestsFinished 9 requestsFinished 10 requestsCost time for get 29.42441463470459Finished 1 requestsFinished 2 requestsFinished 3 requestsFinished 4 requestsFinished 5 requestsFinished 6 requestsFinished 7 requestsFinished 8 requestsFinished 9 requestsFinished 10 requestsCost time for post 2.611323595046997Process finished with exit code 0
这时候就看到 GET 请求由于没有缓存,就花了 24 多秒才结束,而 POST 由于使用了缓存,2秒多就结束了。
2.3.3 Cache Headers 方法
除了我们自定义缓存,requests-cache 还支持解析 HTTP Request / Response Headers 并根据 Headers 的内容来缓存。
代码展示
# -*- coding:utf-8 -*-# @Time : 2022-03-18# @Author : carl_DJimport timeimport requestsimport requests_cacherequests_cache.install_cache('demo_headers_cache')start = time.time()session = requests.Session()for i in range(10): #Request Headers 里面加上了 Cache-Control 为 no-store session.get('http://httpbin.org', headers={ 'Cache-Control': 'no-store' }) print(f'Finished {i + 1} requests')end = time.time()print('Cost time for get', end - start)start = time.time()
在 Request Headers 里面加上了 Cache-Control 为 no-store,即使我们声明了缓存那也不会生效。
3、 总结
看到这里,今天的分享就差不多到这里了。
在实际应用中,如果循环爬取的话,requests_cache确实是一个好的方法,
即节省时间,有提高效率,
关键可以利用节省的时间,来泡泡澡。
创作挑战赛
新人创作奖励来咯,坚持创作打卡瓜分现金大奖