问题背景
前天分享了一篇《gevent:异步理论与实战》的文章,我们可以对待爬网站实时异步访问,速度会大大提高。测试的时候只是小批量爬取12个词语的信息,也就是说一瞬间我们对网站访问了12次,这还没啥问题。
words = ['good','bad','cool',
'hot','nice','better',
'head','up','down',
'right','left','east']
def asynchronous(words):
events = [gevent.spawn(fetch_word_info,word) for word in words]
wordinfos = gevent.joinall(events)
for wordinfo in wordinfos:
#获取到数据get方法
print(wordinfo.get())
end = time.time()
print("异步运行时间: %s 秒"%str(end-start))
但是客户让我爬10000+个词语的音标及注释信息,如果使用gevent的话,那几秒钟之内就给网站一股脑的发请求,说不定网站就把握封了。我们要做有良知的爬虫,写一个类似于寄生虫的爬虫,如果寄主挂掉了,对寄生虫也不是啥好事,你说是不是。
解决思路
将列表等分为若干个子列表,分批爬取。举例我们有一个数字列表(0-19),要均匀的等分为4份,也就是子列表有5个数。下面是我在*查找到的列表等分方案:
方法1
seqence = list(range(20))
size = 5 #子列表长度
output = [seqence[i:i+size] for i in range(0, len(seqence), size)]
print(output)
方法2
chunks = lambda seq, size: [seq[i: i+size] for i in range(0, len(seq), size)]
print(chunks(seq, 5))
方法3
def chunks(seq,size):
for i in range(0,len(seq), size):
yield seq[i:i+size]
数据量不大的情况下,选哪一种方法都可以。如果特别大,建议使用方法3.
回到爬虫情景,解决问题
已经找到解决办法了,那么我们动手实现
def asynchronous(words):
start = time.time()
print('异步开始了')
chunks = lambda seq, size: [seq[i: i + size] for i in range(0, len(seq), size)]
for subwords in chunks(words,3):
events = [gevent.spawn(fetch_word_info, word) for word in subwords]
wordinfos = gevent.joinall(events)
for wordinfo in wordinfos:
# 获取到数据get方法
print(wordinfo.get())
time.sleep(1)
end = time.time()
print("异步运行时间: %s 秒" % str(end - start))
asynchronous(words)