python-协程

多协程的用法

1.gevent库

对比同步执行:

 1 import requests,time
 2 #导入requests和time
 3 start = time.time()
 4 #记录程序开始时间
 5 
 6 url_list = ['https://www.baidu.com/',
 7 'https://www.sina.com.cn/',
 8 'http://www.sohu.com/',
 9 'https://www.qq.com/',
10 'https://www.163.com/',
11 'http://www.iqiyi.com/',
12 'https://www.tmall.com/',
13 'http://www.ifeng.com/']
14 #把8个网站封装成列表
15 
16 for url in url_list:
17 #遍历url_list
18     r = requests.get(url)
19     #用requests.get()函数爬取网站
20     print(url,r.status_code)
21     #打印网址和抓取请求的状态码
22 
23 end = time.time()
24 #记录程序结束时间
25 print(end-start)
26 #end-start是结束时间减去开始时间,就是最终所花时间。
27 #最后,把时间打印出来。

多协程执行:

 1 from gevent import monkey
 2 #从gevent库里导入monkey模块。
 3 monkey.patch_all()
 4 #monkey.patch_all()能把程序变成协作式运行,就是可以帮助程序实现异步。
 5 import gevent,time,requests
 6 #导入gevent、time、requests。
 7 
 8 start = time.time()
 9 #记录程序开始时间。
10 
11 url_list = ['https://www.baidu.com/',
12 'https://www.sina.com.cn/',
13 'http://www.sohu.com/',
14 'https://www.qq.com/',
15 'https://www.163.com/',
16 'http://www.iqiyi.com/',
17 'https://www.tmall.com/',
18 'http://www.ifeng.com/']
19 #把8个网站封装成列表。
20 
21 def crawler(url):
22 #定义一个crawler()函数。
23     r = requests.get(url)
24     #用requests.get()函数爬取网站。
25     print(url,time.time()-start,r.status_code)
26     #打印网址、请求运行时间、状态码。
27 
28 tasks_list = [ ]
29 #创建空的任务列表。
30 
31 for url in url_list:
32 #遍历url_list。
33     task = gevent.spawn(crawler,url)
34     #用gevent.spawn()函数创建任务。
35     tasks_list.append(task)
36     #往任务列表添加任务。
37 gevent.joinall(tasks_list)
38 #执行任务列表里的所有任务,就是让爬虫开始爬取网站。
39 end = time.time()
40 #记录程序结束时间。
41 print(end-start)
42 #打印程序最终所需时间。

第1、3行代码:从gevent库里导入了monkey模块,这个模块能将程序转换成可异步的程序。monkey.patch_all(),它的作用其实就像你的电脑有时会弹出“是否要用补丁修补漏洞或更新”一样。它能给程序打上补丁,让程序变成是异步模式,而不是同步模式。它也叫“猴子补丁”。

第5行代码:我们导入了gevent库来帮我们实现多协程,导入了time模块来帮我们记录爬取所需时间,导入了requests模块帮我们实现爬取8个网站。

第21、23、25行代码:我们定义了一个crawler函数,只要调用这个函数,它就会执行【用requests.get()爬取网站】和【打印网址、请求运行时间、状态码】这两个任务。

第33行代码:因为gevent只能处理gevent的任务对象,不能直接调用普通函数,所以需要借助gevent.spawn()来创建任务对象。

这里需要注意一点:gevent.spawn()的参数需为要调用的函数名及该函数的参数。比如,gevent.spawn(crawler,url)就是创建一个执行crawler函数的任务,参数为crawler函数名和它自身的参数url。

第35行代码:用append函数把任务添加到tasks_list的任务列表里。

第37行代码:调用gevent库里的joinall方法,能启动执行所有的任务。gevent.joinall(tasks_list)就是执行tasks_list这个任务列表里的所有任务,开始爬取

总结一下用gevent实现多协程爬取的重点:

queue模块

当我们用多协程来爬虫,需要创建大量任务时,我们可以借助queue模块。

queue翻译成中文是队列的意思。我们可以用queue模块来存储任务,让任务都变成一条整齐的队列,就像银行窗口的排号做法。因为queue其实是一种有序的数据结构,可以用来存取数据。

这样,协程就可以从队列里把任务提取出来执行,直到队列空了,任务也就处理完了。就像银行窗口的工作人员会根据排号系统里的排号,处理客人的业务,如果已经没有新的排号,就意味着客户的业务都已办理完毕。

接下来,我们来实操看看,可以怎么用queue模块和协程配合,依旧以抓取8个网站为例。

 1 from gevent import monkey
 2 monkey.patch_all()
 3 import gevent,time,requests
 4 from gevent.queue import Queue
 5 
 6 start = time.time()
 7 
 8 url_list = ['https://www.baidu.com/',
 9 'https://www.sina.com.cn/',
10 'http://www.sohu.com/',
11 'https://www.qq.com/',
12 'https://www.163.com/',
13 'http://www.iqiyi.com/',
14 'https://www.tmall.com/',
15 'http://www.ifeng.com/']
16 
17 work = Queue()
18 for url in url_list:
19     work.put_nowait(url)
20 
21 def crawler():
22     while not work.empty():
23         url = work.get_nowait()
24         r = requests.get(url)
25         print(url,work.qsize(),r.status_code)
26 
27 tasks_list  = [ ]
28 
29 for x in range(2):
30     task = gevent.spawn(crawler)
31     tasks_list.append(task)
32 gevent.joinall(tasks_list)
33 
34 end = time.time()
35 print(end-start)

因为gevent库里就带有queue,所以我们用【from gevent.queue import Queue】就能把queue模块导入。其他模块和代码我们在讲解gevent时已经讲解过了,相信你能懂。

用Queue()能创建queue对象,相当于创建了一个不限任何存储数量的空队列。如果我们往Queue()中传入参数,比如Queue(10),则表示这个队列只能存储10个任务。

创建了queue对象后,我们就能调用这个对象的put_nowait方法,把我们的每个网址都存储进我们刚刚建立好的空队列里。

work.put_nowait(url)这行代码就是把遍历的8个网站,都存储进队列里。

这里定义的crawler函数,多了三个你可能看不懂的代码:1.while not work.empty():;2.url = work.get_nowait();3.work.qsize()

这三个代码涉及到queue对象的三个方法:empty方法,是用来判断队列是不是空了的;get_nowait方法,是用来从队列里提取数据的;qsize方法,是用来判断队列里还剩多少数量的。

当然,queue对象的方法还不止这几种,比如有判断队列是否为空的empty方法,对应也有判断队列是否为满的full方法。

原文地址:https://www.cnblogs.com/mylearning-log/p/10893597.html