爬网易云音乐评论数的优化历程
为什么要爬、怎么爬就不说了。
首先
我是第一次写爬虫。
使用的是Python,且没有使用爬虫框架。
仅仅靠requests和beautifulsoup来完成。
作者:轨迹。
方法一:最早使用的方法
爬取过程:
1、模拟请求
2、获取数据
3、入库
重复1-3来完成对一首音乐的评论数的爬取。
过程如图:
该方法的不足之出在于:
每一次的网络IO都要等待本地IO,每一次的本地IO都要等待网络IO
实际操作时间:
爬100首:
爬500首:
爬5000首:
我动了动小脑袋瓜,发现事情并没有这么简单:
平均一首需要:0.9秒
那么爬1,000,000就需要:900,000秒=250小时=10.4天
就算是个睿智都知道这划!不!来!
而且,当请求数不断得增加,即使本地IO保持稳定,但网络IO不好说呀。而且测试时间恰逢下午至晚上,这可能是网易云音乐服务器的高峰期,网络IO情况就更不容乐观了。
根据该方法的不足之处,我又写了一个方法二。
方法二:方法一的改进,让请求的只做请求,入库的只做入库。
既然方法一的网络IO和本地IO需要互相等待。
不如让网络IO跑在一个线程,本地IO跑在一个线程如何?
用FIFO队列作缓冲?
过程如图:
爬100首:
爬500首:
爬5000首:
很显然,时间消耗量下降了不是一点半点。
方法 | 一 | 二 |
---|---|---|
100首 | 61.93 s | 38.41 s |
500首 | 445.23 s | 418.30 s |
5000首 | 4502.55 s | 4974.57 s |
方法三:多线程请求
在多线程上吃了点甜头之后,发现本地IO的消耗时间总是比网络IO的消耗时间多那么零点几秒。也就说,本地IO总是在等待网络IO请求到的数据。
为什么不多开几个网络IO的线程呢??
过程:
等等,这不是生产者消费者问题吗!!
要不要加写锁?要不要加读锁?
额不不不,还好Python的Queue自带锁,是线程安全的!
那就放开写吧。
2线程各爬100:
3线程各爬100:
4线程各爬100:
8线程各爬100:
16线程各爬100:
线程数 | 2 | 3 | 4 | 8 | 16 |
---|---|---|---|---|---|
每个线程各100首 | 57.04s | 63.57s | 71.68s | 120.43s | 239.05s |
平均每首 | 0.285s | 0.2119s | 0.1792s | 0.1505s | 0.1494s |
很显然:
当网络IO的线程超过8后,提升非常小,可能是因为各网络IO线程在等待其他网络IO线程的写入。
最后
以0.15秒每首的速度爬一百万首,也需要1.73天。真让人头疼。。。
爬网易云音乐评论数的优化历程
为什么要爬、怎么爬就不说了。
首先
我是第一次写爬虫。
使用的是Python,且没有使用爬虫框架。
仅仅靠requests和beautifulsoup来完成。
作者:轨迹。
方法一:最早使用的方法
爬取过程:
1、模拟请求
2、获取数据
3、入库
重复1-3来完成对一首音乐的评论数的爬取。
过程如图:
该方法的不足之出在于:
每一次的网络IO都要等待本地IO,每一次的本地IO都要等待网络IO
实际操作时间:
爬100首:
爬500首:
爬5000首:
我动了动小脑袋瓜,发现事情并没有这么简单:
平均一首需要:0.9秒
那么爬1,000,000就需要:900,000秒=250小时=10.4天
就算是个睿智都知道这划!不!来!
而且,当请求数不断得增加,即使本地IO保持稳定,但网络IO不好说呀。而且测试时间恰逢下午至晚上,这可能是网易云音乐服务器的高峰期,网络IO情况就更不容乐观了。
根据该方法的不足之处,我又写了一个方法二。
方法二:方法一的改进,让请求的只做请求,入库的只做入库。
既然方法一的网络IO和本地IO需要互相等待。
不如让网络IO跑在一个线程,本地IO跑在一个线程如何?
用FIFO队列作缓冲?
过程如图:
爬100首:
爬500首:
爬5000首:
很显然,时间消耗量下降了不是一点半点。
方法 | 一 | 二 |
---|---|---|
100首 | 61.93 s | 38.41 s |
500首 | 445.23 s | 418.30 s |
5000首 | 4502.55 s | 4974.57 s |
方法三:多线程请求
在多线程上吃了点甜头之后,发现本地IO的消耗时间总是比网络IO的消耗时间多那么零点几秒。也就说,本地IO总是在等待网络IO请求到的数据。
为什么不多开几个网络IO的线程呢??
过程:
等等,这不是生产者消费者问题吗!!
要不要加写锁?要不要加读锁?
额不不不,还好Python的Queue自带锁,是线程安全的!
那就放开写吧。
2线程各爬100:
3线程各爬100:
4线程各爬100:
8线程各爬100:
16线程各爬100:
线程数 | 2 | 3 | 4 | 8 | 16 |
---|---|---|---|---|---|
每个线程各100首 | 57.04s | 63.57s | 71.68s | 120.43s | 239.05s |
平均每首 | 0.285s | 0.2119s | 0.1792s | 0.1505s | 0.1494s |
很显然:
当网络IO的线程超过8后,提升非常小,可能是因为各网络IO线程在等待其他网络IO线程的写入。
最后
以0.15秒每首的速度爬一百万首,也需要1.73天。真让人头疼。。。
发布评论