python多线程爬取,多线程 爬虫
本文给大家带来了一些关于python的知识,包括多线程爬虫的开发和常用的搜索算法。下面就来看看吧,希望对你有帮助。
推荐:python视频教程
00-1010
多线程爬虫
掌握了请求和正则表达式之后,就可以开始实战爬取一些简单的URL了。但是,此时的爬虫只有一个进程和一个线程,因此称为单线程爬虫.单线程爬虫一次只访问一个页面,所以不能充分利用计算机的网络带宽。一个页面最多也就几百KB,所以爬虫爬一个页面,额外的网速和从请求到源代码的时间都浪费了。如果可以让爬虫同时访问10个页面,就相当于爬取速度提高了10倍。为了达到这个目的,就需要使用多线程技术了。
Python有一个全局解释器锁,GIL)。这就造成了Python的多线程是伪多线程,也就是本质上是一个线程,但是这个线程做什么都只有几毫秒。几毫秒后保存场景,改做其他事情,几毫秒后再做其他事情。一轮后,它回到第一件事,恢复场景,再做几毫秒,并保持变化.微观的单线程在宏观上就像同时做几件事。这种机制对I/O(输入/输出)密集型操作影响不大,但对CPU密集型操作,由于只能使用CPU的一个核心,所以对性能影响很大。因此,当涉及到计算密集型程序时,您需要使用多进程。Python的多进程不受GIL的影响。爬虫是一个I/O密集型程序,所以使用多线程可以大大提高爬行效率。
多线程的优势
多进程本身就是Python的多进程库,用来处理与多进程相关的操作。但是由于进程之间不能直接共享内存和堆栈资源,而且启动一个新进程的成本要比线程高很多,所以使用多线程抓取比使用多进程更有优势。多重处理下有一个哑模块,允许Python线程使用多种多重处理方法。
dummy下面有一个Pool类,用来实现线程池。
这个线程池有一个map()方法,它允许线程池中的所有线程同时执行一个函数。
例如:
学习for循环后
对于范围(10):内的I
Print(i*i)当然可以得到结果,但是代码是一个一个计算的,效率不高。而如果使用多线程技术让代码同时计算很多数的平方,就需要使用multiprocessing.dummy来实现:
使用多线程的例子:
来自多重处理。虚拟导入池定义cal_pow(num):
退货数量*数量
pool=pool(3)num=[x for x in range(10)]result=pool . map(cal _ pow,num) print ({} 。format (result))在上述代码中,先定义了一个函数用来计算平方,然后初始化了一个有3个线程的线程池。这3个线程负责计算10个数字的平方,谁先计算完手上的这个数,谁就先取下一个数继续计算,直到把所有的数字都计算完成为止。
在这个例子中,第二个参数线程池的map()方法接收两个参数,第1个参数是函数名,第2个参数是一个列表。注意:第1个参数仅仅是函数的名字,是不能带括号的.是一个iterable对象,这个iterable对象中的每个元素都将作为参数被函数clac_power2()接收。除了list,tuple,set或者dictionary都可以作为map()的第二个参数。
00-1010因为爬虫是一个I/O密集型的操作,尤其是在请求网页源代码的时候,如果是单线程开发的话,会浪费大量的时间等待网页返回。因此,将多线程技术应用到爬虫中可以大大提高爬虫的运行效率。举个例子。洗衣机洗衣服50分钟,水壶烧水15分钟,背单词1h。如果先等洗衣机洗衣服,然后等衣服洗完再烧开水,等水烧开后再背单词,总共需要125min。
但如果换一种说法,总体来说,三件事可以同时运行。假设你突然分开了另外两个人。他们一个负责把衣服放进洗衣机里等洗衣机洗完,一个负责烧水等水开,而你只需要自己背单词。水开了,负责烧水的人先消失。等到洗衣机洗完衣服,然后忙碌的负责洗衣服的人就消失了。最后,你自己背单词。同时完成三件事只需要60min分钟。
当然,你一定会发现,上面的例子并不是生活中的实际情况。事实上,没有人会同时出现在两个地方。现实生活中的情况是,人背单词的时候,专心背单词;水烧开后,水壶会发出声音提醒你;衣物洗完,洗衣机会发出“滴滴答答”的声音。所以睡醒后做相应的动作就好了。没必要。
要每分钟都去检查。上面的两种差异,其实就是多线程和事件驱动的异步模型的差异。本小节讲到的是多线程操作,后面会讲到使用异步操作的爬虫框架。现在只需要记住,在需要操作的动作数量不大的时候,这两种方式的性能没有什么区别,但是一旦动作的数量大量增长,多线程的效率提升就会下降,甚至比单线程还差。而到那个时候,只有异步操作才是解决问题的办法。
下面通过两段代码来对比单线程爬虫和多线程爬虫爬取bd首页的性能差异:
从运行结果可以看到,一个线程用时约16.2s,5个线程用时约3.5s,时间是单线程的五分之一左右。从时间上也可以看到5个线程“同时运行”的效果。但并不是说线程池设置得越大越好。从上面的结果也可以看到,5个线程运行的时间其实比一个线程运行时间的五分之一要多一点。这多出来的一点其实就是线程切换的时间。这也从侧面反映了Python的多线程在微观上还是串行的。因此,如果线程池设置得过大,线程切换导致的开销可能会抵消多线程带来的性能提升。线程池的大小需要根据实际情况来确定,并没有确切的数据。读者可以在具体的应用场景下设置不同的大小进行测试对比,找到一个最合适的数据。
爬虫的常见搜索算法
深度优先搜索
某在线教育网站的课程分类,需要爬取上面的课程信息。从首页开始,课程有几个大的分类,比如根据语言分为Python、Node.js和Golang。每个大分类下面又有很多的课程,比如Python下面有爬虫、Django和机器学习。每个课程又分为很多的课时。 在深度优先搜索的情况下,爬取路线如图所示(序号从小到大)
广度优先搜索
先后顺序如下
算法选择
例如要爬取某网站全国所有的餐馆信息和每个餐馆的订单信息。假设使用深度优先算法,那么先从某个链接爬到了餐馆A,再立刻去爬餐馆A的订单信息。由于全国有十几万家餐馆,全部爬完可能需要12小时。这样导致的问题就是,餐馆A的订单量可能是早上8点爬到的,而餐馆B是晚上8点爬到的。它们的订单量差了12小时。而对于热门餐馆来说,12小时就有可能带来几百万的收入差距。这样在做数据分析时,12小时的时间差就会导致难以对比A和B两个餐馆的销售业绩。相对于订单量来说,餐馆的数量变化要小得多。所以如果采用广度优先搜索,先在半夜0点到第二天中午12点把所有的餐馆都爬取一遍,第二天下午14点到20点再集中爬取每个餐馆的订单量。这样做,只用了6个小时就完成了订单爬取任务,缩小了由时间差异致的订单量差异。同时由于店铺隔几天抓一次影响也不大,所以请求量也减小了,使爬虫更难被网站发现。又例如,要分析实时舆情,需要爬百度贴吧。一个热门的贴吧可能有几万页的帖子,假设最早的帖子可追溯到2010年。如果采用广度优先搜索,则先把这个贴吧所有帖子的标题和网址都获取下来,然后根据这些网址进入每个帖子里面以获取每一层楼的信息。可是,既然是实时舆情,那么7年前的帖子对现在的分析意义不大,更重要的应该是新的帖子才对,所以应该优先抓取新的内容。相对于过往的内容,实时的内容才最为重要。因此,对于贴吧内容的爬取,应该采用深度优先搜索。看到一个帖子就赶紧进去,爬取它的每个楼层信息,一个帖子爬完了再爬下一个帖子。当然,这两种搜索算法并非非此即彼,需要根据实际情况灵活选择,很多时候也能够同时使用。
推荐学习:python视频教程以上就是Python详细解析之多线程爬虫与常见搜索算法的详细内容,更多请关注盛行IT软件开发工作室其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。