以爬取知乎为例,进行python 多进程爬虫性能分析

以爬取知乎为例,进行python 多进程爬虫性能分析

如果对多进程multiproessing模块不熟悉,请先浏览

  • python 使用multiprocessing模块进行多进程爬虫

问题背景:

爬取知乎赞同超过10K的回答集合内的问题

分别采用以下策略爬取,对性能进行分析,并考虑对临界资源互斥访问

  • 单进程爬取
  • 多进程process爬取
  • 多进程Pool爬取

单进程爬取

爬取前50页

代码:

import requests
from lxml import etree
import time

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36',
    'referer': 'https://www.zhihu.com/collection/38887091'
}

def get_one_page(url,i):
    response=requests.get(url,headers=headers)
    html=etree.HTML(response.content)
    #items=html.xpath('//div[@class="zm-item"]//')
    #print(len(items))
    titles=html.xpath('//h2[@class="zm-item-title"]/a/text()')
    print('状态码{}---页数:{}'.format(response.status_code,i))
    for title in titles:
        print('第{}页-- {}'.format(i,title))

if __name__=='__main__':
    base_url ='https://www.zhihu.com/collection/38887091'
    start_time = time.time()
    p=[]
    for i in range(1,50):
        url=base_url+'?page='+str(i)
        get_one_page(url,i)
    end_time = time.time()
    print('\n--------------用时{}s------------\n'.format(float(end_time-start_time)))

部分输出结果:

状态码200---页数:49
第49页-- 林志玲宣布结婚,你有什么想说的?
第49页-- 有哪些让你拍案叫绝或亮瞎眼的神翻译?
第49页-- 如何评价格力电器举报奥克斯生产销售不合格空调?
第49页-- 如何评价「因少了一个芒果,跪求原谅的圆通快递员险遭开除,最后警察出具证明」?
第49页-- 公务员和一千万你选哪个?
第49页-- 男朋友妈妈知道了他儿子给我下跪的照片被我发在朋友圈里了,非常生气不同意我们在一起了,我该怎么办?
第49页-- 为什么我们平常穿汉服就会让路人觉得很奇怪?
第49页-- 在美国为什么黑人会号召大家去看《黑豹》而不是《绿皮书》?
第49页-- 有哪些超短却能让人笑抽的笑话?

--------------用时86.62711977958679s------------

用process类开启多进程

代码:

import requests
from lxml import etree
from multiprocessing import Process
import multiprocessing
import time
import os

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36',
    'referer': 'https://www.zhihu.com/collection/38887091'
}

def get_one_page(url,i):
    response=requests.get(url,headers=headers)
    html=etree.HTML(response.content)
    titles=html.xpath('//h2[@class="zm-item-title"]/a/text()')
    print('状态码{}---页数:{}----进程id:{}'.format(response.status_code,i,os.getpid()))
    for title in titles:
        print('第{}页-- {}'.format(i,title))

if __name__=='__main__':
    base_url ='https://www.zhihu.com/collection/38887091'
    start_time = time.time()
    p=[]
    for i in range(1,50):
        url=base_url+'?page='+str(i)
        p = Process(target=get_one_page, args=(url,i))
        p.start()
    while True:
        if len(multiprocessing.active_children())==0:
            end_time = time.time()
            print('\n--------------用时{}s------------\n'.format(float(end_time-start_time)))
            exit()

部分输出结果:

状态码200---页数:33----进程id:32476
第33页-- 资本的力量可以有多大?
第33页-- 有什么事是外国人来了中国之后才知道的?
第33页-- 为什么部分学霸不情愿帮助同学回答问题?
第33页-- 一壶 100℃ 的开水从多高倒进嘴里不会觉得烫?
第33页-- 为什么组装台式机电脑会成瘾?
第33页-- 如何看待「20年后打老师案」常某一审被判有期徒刑一年六个月?
第33页-- 除了迅雷外,还有什么靠谱的下载软件?
第33页-- 有没有谁让你感叹道世界上怎么会有如此好看的人?
第33页-- 如何评价福原爱?
第33页-- 你曾经做过最羞耻的事是什么?
状态码200---页数:15----进程id:37656
第15页-- 我儿子赌输了 5 万,我该怎么处理?
第15页-- 如何看待《上海堡垒》导演滕华涛公开道歉?流量电影是否已死?
''''''
省略
''''''

第5页-- 墨家在中国为什么消失得这么彻底?
第5页-- 如何评价郭杰瑞?
第5页-- 为什么熊猫能跟功夫扯上关系呢?
状态码200---页数:48----进程id:26764
状态码200---页数:45----进程id:22364
状态码200---页数:9----进程id:9796
第9页-- 如何看待漫画主笔狼人小姐自称 15 万包裹被销毁德邦仅赔 300 元一事?
第45页-- 可乐怎么喝好喝?
第48页-- 如何看待屠呦呦团队再次重大发现,解决青蒿素抗药性,及青蒿素可用于治疗红斑狼疮的前景?
状态码200---页数:8----进程id:2168
第8页-- 为什么录取通知书要用EMS邮递?
第8页-- 为什么知乎上有些人黑无印良品(MUJI)?
第8页-- 如何看待北大以“成绩太低,极可能被退学”为由将考生退档?
第8页-- 《哪吒之魔童降世》这部动画是否一般?
第9页-- 中国义务教育阶段和普通高中教育中的哪一科目最失败?
第45页-- 为什么越来越多的年轻人感觉工作没有动力、职业发展没有希望,迷茫和中年危机等现象普遍发生?
第48页-- 为什么男朋友在明知我生气的情况下,不哄我而讲道理?
状态码200---页数:14----进程id:14036
状态码200---页数:23----进程id:14032
第23页-- 你为 Cosplay 牺牲最大的一次是怎样的?
第23页-- 有哪些非常冷门的冷知识?
第14页-- 肚子上面的肉怎么减?
第45页-- 景甜为啥会看上张继科?
第8页-- 如何看待《上海堡垒》豆瓣开画评分4.2分,目前已跌至3.6分?有可能反向超越《逐梦演艺圈》 ?
第9页-- 如何看待上海迪士尼不接受调解,坚持翻包检查?
第9页-- 孩子考到了约定的成绩,可我不想兑现给他游戏充值的许诺了怎么办?
状态码200---页数:13----进程id:34272
状态码200---页数:47----进程id:33360
第47页-- 女生穿JK制服或者Lolita,男生穿什么出去比较好?
第47页-- 历史上有哪些值得尊敬的小人物?
第47页-- 武侠小说为什么会没落?
第23页-- 你是什么时候感觉到「中国强大了」?
第14页-- 印度真的有部分中国新闻上说的那么落后吗?
第45页-- 你写过的最浪漫的情话是什么呢?
第8页-- 如何看待上海迪士尼禁止自带饮食被大学生告了?
第9页-- 在医院喊护士换针水是称呼「护士」还是称呼「医生」显得更有礼貌?
第13页-- 为何有人无法接受韩国是发达国家的事实?
状态码200---页数:1----进程id:29384
第48页-- 电动自行车新国标为什么会遭那么多人排斥?
状态码200---页数:42----进程id:31300
第42页-- 为什么会有莫名的到付快递?
第8页-- 如何看待上海迪士尼禁止自带饮食被大学生告了?
第9页-- 长得好看但没啥文化的女孩子最终都怎么样了?
''''''
省略
''''''
第7页-- 女生讨厌男生叫她们小姐姐吗?
第7页-- 如何看待斗鱼主播Mix晴子在与乔碧萝殿下连麦过程中的表现?
第7页-- 为什么有这么多人不喜欢小米?
第30页-- 黑人的身份让迈克尔·杰克逊遭受了多少苦难?
第30页-- 如何看待河南省永城市一玛莎拉蒂车主酒驾逃逸,途中又撞击一辆宝马造成 2 死 4 伤这一事故?
第30页-- 如何惹一只金毛生气?
第30页-- 如何看待六小龄童 2018 年 10 月对网民的表态?
第30页-- 如果九九八十一难的最后一难是让唐僧吃肉,唐僧该不该吃?
第30页-- 如何看待孟美岐讲述自己创造101后期几乎每天只睡30分钟觉?

--------------用时18.920397758483887s------------

相比单进程程爬取50页用时86秒,多进程爬取50页仅用时19秒,速度提升很快。

但是,通过打印信息可以看出,多进程争相占用打印资源,某一进程还没有打印完,就被其他资源占用。

为了能够使某一进程在打印时,能打印完,再被其他进程占用,我们可以使用lock锁

process类与lock锁多进程爬虫

代码:

import requests
from lxml import etree
from multiprocessing import Process,Lock
import multiprocessing
import time
import os

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36',
    'referer': 'https://www.zhihu.com/collection/38887091'
}

def get_one_page(url,i,lock):
    response=requests.get(url,headers=headers)
    html=etree.HTML(response.content)
    titles=html.xpath('//h2[@class="zm-item-title"]/a/text()')
    lock.acquire()
    print('状态码{}---页数:{}----进程id:{}'.format(response.status_code,i,os.getpid()))
    for title in titles:
        print('第{}页-- {}'.format(i,title))
    lock.release()

if __name__=='__main__':
    base_url ='https://www.zhihu.com/collection/38887091'
    start_time = time.time()
    p=[]
    lock=Lock()
    for i in range(1,50):
        url=base_url+'?page='+str(i)
        p = Process(target=get_one_page, args=(url,i,lock,))
        p.start()
    while True:
        if len(multiprocessing.active_children())==0:
            end_time = time.time()
            print('\n--------------用时{}s------------\n'.format(float(end_time-start_time)))
            exit()

部分输出结果:

状态码200---页数:7----进程id:36652
第7页-- 中影华腾说《哪吒》剧本抄袭《五维记忆》,是抄袭实锤还是碰瓷?你怎么看?
第7页-- 删掉男友100%完成度的塞尔达,并且在他玩儿生化危机的时候吓唬他,这个有很严重吗?
第7页-- 为什么有了洗手液和洗面奶和沐浴露了,香皂还没有被市场淘汰掉?
第7页-- 人喝下一杯冰水需要把 0 度加热到 37 度,损失了热量,这个过程可以减肥吗?
第7页-- 有哪些以为是小罪,其实是重罪,判刑很重的案例?
第7页-- 被敌人生擒后审讯,如果知道自己受不住酷刑而当场招供,是理性还是可耻?
第7页-- 女生讨厌男生叫她们小姐姐吗?
第7页-- 如何看待斗鱼主播Mix晴子在与乔碧萝殿下连麦过程中的表现?
第7页-- 谢霆锋的真实厨艺如何?
第7页-- 为什么有这么多人不喜欢小米?
状态码200---页数:33----进程id:25556
第33页-- 资本的力量可以有多大?
第33页-- 有什么事是外国人来了中国之后才知道的?
第33页-- 为什么部分学霸不情愿帮助同学回答问题?
第33页-- 一壶 100℃ 的开水从多高倒进嘴里不会觉得烫?
第33页-- 为什么组装台式机电脑会成瘾?
第33页-- 如何看待「20年后打老师案」常某一审被判有期徒刑一年六个月?
第33页-- 除了迅雷外,还有什么靠谱的下载软件?
第33页-- 有没有谁让你感叹道世界上怎么会有如此好看的人?
第33页-- 如何评价福原爱?
第33页-- 你曾经做过最羞耻的事是什么?
''''''
省略
''''''
状态码200---页数:34----进程id:1168
第34页-- 网络传言日本已经储存了够400年使用的稀土是真是假?
第34页-- 穿短裙要不要安全裤?
第34页-- 如何拉出一根 50 cm 长的屎?
第34页-- 被窝里放屁有毒吗?
第34页-- 你是从哪个细节发现男朋友或老公出轨的?
第34页-- 娱乐圈中哪个明星最惹人烦,无论做什么都烦?
第34页-- 你知道什么「能笑死人」的笑话?
第34页-- 如果你是医生,病人是你老公的爷爷,你会支付病人的检查费用200元吗?
第34页-- 有哪些是你健身之后才知道的伪健身知识?
第34页-- 认为很红却被现实打脸的明星有谁?
状态码200---页数:42----进程id:10748
第42页-- 为什么会有莫名的到付快递?
第42页-- 你老婆怀孕了,特别想吃草莓。已知草莓40元一斤,经济水平一般的你会买吗?
第42页-- 就地理条件而言,中国相较其他国家有哪些优势和劣势?
第42页-- 高中生上课喝了一口水,该不该被退学?
第42页-- 如何看待范冰冰和李晨的恋情?
第42页-- 动画《千与千寻》中千寻是怎样在最后的部分认出那些猪里边没有她父母的?
第42页-- 为什么在国外总是出现华人被歧视?
第42页-- 现在的部分女生为什么不想生孩子?
第42页-- 别人家的猫吃了我奶奶放在外面的猫粮之后死了,责任在我奶奶吗?
第42页-- 怎么评价王源的《世界上没有真正的感同身受》这首歌?

--------------用时19.77012801170349s------------

采用lock锁后,打印更加规范了,同时用时仅有微妙的增加,相比于单进程而言,效率依然有很大提升。

对于该爬虫程序,耗时的原因主要时网络I/O(下载网页)较为耗时,对页面的解析与打印并不费时。如果自己运行一遍程序,可以发现,打印速度只是刚开始的时候略有慢(因为此时待打印资源较少,打印需要等待),后期当大量进程开启后,速度与无lock锁相差不多。

进程池pool开启多进程

开启4个进程

代码:

import requests
from lxml import etree
from multiprocessing import Pool
import time
import os

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36',
    'referer': 'https://www.zhihu.com/collection/38887091'
}

def get_one_page(url,i):
    response=requests.get(url,headers=headers)
    html=etree.HTML(response.content)
    titles=html.xpath('//h2[@class="zm-item-title"]/a/text()')
    print('状态码{}---页数:{}----进程id:{}'.format(response.status_code,i,os.getpid()))
    for title in titles:
        print('第{}页-- {}'.format(i,title))

if __name__=='__main__':
    base_url ='https://www.zhihu.com/collection/38887091'
    start_time = time.time()
    pool=Pool(processes=4)
    for i in range(1,50):
        url=base_url+'?page='+str(i)
        pool.apply_async(func=get_one_page,args=(url,i,))
    pool.close()
    pool.join()
    end_time = time.time()
    print('\n--------------用时{}s------------\n'.format(float(end_time-start_time)))

部分输出结果:

-----省略-----
第20页-- 为什么一些高冷漂亮的女生被痞痞的「社会人」追到了?
第20页-- 如何看待澳大利亚游泳选手莎娜杰克(Shayna Jack)被查出使用兴奋剂?
第20页-- 安检人员曾检查出哪些可怕/奇怪的物品?
状态码200---页数:21----进程id:28532
第21页-- 你小时候有哪些自以为瞒天过海却被父母知道得一清二楚的事?
第21页-- 作为圈内人,你了解的娱乐圈到底有多乱?
第21页-- 如何看待斗鱼游戏主播乔碧萝殿下直播不小心露脸这一直播事故?
状态码200---页数:22----进程id:9468
状态码200---页数:23----进程id:33536
第21页-- 为什么现在很多人用微信而不是 QQ?
第22页-- 如何看待斗鱼游戏主播乔碧萝殿下直播不小心露脸这一直播事故?
第22页-- 有哪些看了之后会喊「卧槽」的图片或视频?
-----省略-----
第49页-- 为什么我们平常穿汉服就会让路人觉得很奇怪?
第49页-- 在美国为什么黑人会号召大家去看《黑豹》而不是《绿皮书》?
第49页-- 有哪些超短却能让人笑抽的笑话?

--------------用时20.939387321472168s------------

开启8个进程:

--------------用时13.691651582717896s------------

开启12个进程

--------------用时10.17682147026062s------------

开启16个进程

--------------用时10.651509284973145s------------

开启20个进程

--------------用时12.397843599319458s------------

可以看到,使用进程池,不是进程开启的越多越好,因为进程的创建和销毁也很占用资源。

但是,通过打印信息,我们可以看出,各个进程没有互斥的访问打印资源,由于apply_async()不能传入lock作为参数,我们使用回调函数,将输出功能放在回调函数中

代码:

import requests
from lxml import etree
from multiprocessing import Pool
import time
import os

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36',
    'referer': 'https://www.zhihu.com/collection/38887091'
}

def get_one_page(url,i):
    response=requests.get(url,headers=headers)
    html=etree.HTML(response.content)
    titles=html.xpath('//h2[@class="zm-item-title"]/a/text()')
    result={}
    result['status_code']=response.status_code
    result['title']=titles
    result['page']=i
    return result

def write_to_screen(result):
    print('状态码{}---页数:{}----进程id:{}'.format(result['status_code'],result['page'],os.getpid()))
    for title in result['title']:
        print('第{}页-- {}'.format(result['page'],title))


if __name__=='__main__':
    base_url ='https://www.zhihu.com/collection/38887091'
    start_time = time.time()
    pool=Pool(processes=4)#进程数
    for i in range(1,50):
        url=base_url+'?page='+str(i)
        pool.apply_async(func=get_one_page,args=(url,i,),callback=write_to_screen)
    pool.close()
    pool.join()
    end_time = time.time()
    print('\n--------------用时{}s------------\n'.format(float(end_time-start_time)))

部分输出结果:

状态码200---页数:3----进程id:24720
第3页-- 有哪些妈见打的视频 ?
第3页-- 长得好看但没啥文化的女孩子最终都怎么样了?
第3页-- 为什么江南越写越烂?
第3页-- 若有一天机器人可以代替人类进行大部分工作,《资本论》是否还有意义?
第3页-- 年轻人买房要注意什么?
第3页-- 有哪些让你庆幸及早脱粉的明星?
第3页-- 到底有没有必要省吃俭用买劳力士?
第3页-- 夏天这么热,男生可以穿裙子么?
第3页-- 如何看待取名或解读他人姓名时「强行」引用古诗词?
第3页-- 将进酒读音到底是qiang还是jiang?
状态码200---页数:1----进程id:24720
第1页-- 消费主义是如何伪造文化来欺骗年轻人的?
第1页-- 你的孩子做过的最让你感动的事是什么?
第1页-- 穿几十块的帆布鞋丢人吗?
第1页-- 你小时候有哪些自以为瞒天过海却被父母知道得一清二楚的事?
第1页-- 为什么现在的幼儿园总折腾家长?
第1页-- 中国禁毒力度很大吗?
第1页-- 农夫山泉一年卖那么多,长白山不会枯竭吗?
第1页-- 《流浪地球》《哪吒之魔童降世》《上海堡垒》三部电影哪部对中国电影意义更加重大?
第1页-- 为什么《流浪地球》豆瓣评分只有7.9,《哪吒之魔童降世》豆瓣评分却高达8.7呢?
第1页-- 亲兄妹之间应不应该避嫌?
状态码200---页数:4----进程id:24720
第4页-- 如何看待最近因为黄晓明而兴起的「明学」?有哪些特点?
第4页-- 和平有多奢侈?
第4页-- 你知道哪些关于近视的谣言?
第4页-- 有什么让人听了背脊发凉的恐怖故事?
第4页-- 高温油炸过后的尸体还能检测出DNA是什么原理?
第4页-- 你见过最蠢的婚礼司仪说过什么话?
第4页-- 如何看待上海迪士尼禁止自带饮食被大学生告了?
第4页-- 鸡蛋有哪些方便又好吃的做法?
第4页-- 大部分警察真的上班的路上穿便装,只有到了单位才穿警服吗?
第4页-- 我如果往猫砂里拉屎,猫会帮我埋起来吗?
状态码200---页数:2----进程id:24720
第2页-- 有哪些事是你去了泰国以后才知道的?
第2页-- 你想推荐给别人哪些很爽无尿点的高分电影?
第2页-- 有哪些文艺到爆炸的句子?
第2页-- 有哪些体型很大但很温柔的动物?
第2页-- 无神论的各位一般从哪里获得精神力量?
第2页-- 缺爱的家庭会培养出什么样的孩子?
第2页-- 中影华腾说《哪吒》剧本抄袭《五维记忆》,是抄袭实锤还是碰瓷?你怎么看?
第2页-- 如何轻松瘦40斤?
第2页-- 燃烧室后面为什么要加涡轮?
第2页-- 有哪些看似很废的超能力却有出人意料的用法?

状态码200---页数:48----进程id:24720
第48页-- 如何看待屠呦呦团队再次重大发现,解决青蒿素抗药性,及青蒿素可用于治疗红斑狼疮的前景?
第48页-- 为什么男朋友在明知我生气的情况下,不哄我而讲道理?
第48页-- 电动自行车新国标为什么会遭那么多人排斥?
第48页-- 获得 NBA 总冠军是一种什么体验?
第48页-- 如何评价「因少了一个芒果,跪求原谅的圆通快递员险遭开除,最后警察出具证明」?
第48页-- 有没有什么可爱的微信头像?
第48页-- 如何评价郭杰瑞?
第48页-- 拥有稀有姓氏是一种什么样的体验?
第48页-- 西安有哪些值得玩的地方?有哪些不能错过的特色美食?
第48页-- 和巴菲特共进午餐的孙宇晨是谁?

--------------用时20.017423391342163s------------

可以看到,回调函数的进程id为父进程,所有打印输出都在父进程完成

开启8个进程

--------------用时12.832072496414185s------------

开启12进程

--------------用时11.73960018157959s------------

结果与无回调函数基本相同,有兴趣的朋友可以自己测试

综上,可以看出,在进程数较少时,选择procss类开启多进程爬虫,在进程数较多时,选择进程池进行多线程爬虫。

你可能感兴趣的:(python,爬虫)