协程又叫微线程,但与线程是完全不同的概念。线程之间是并发的,开发者不知道它们在什么时候切换;而协程是属于一个线程的,它们之间的切换开发者是明确的。在介绍完协程后会给出一个使用urllib爬取网页中图片的地址的例子演示协程。
一个函数:
def func():
for i in range(1,10):
return i
只会执行一次返回,如果要得到1~10的数据只能返回一个列表。但如果将return改为另一种写法,就可以分次得到:
def func():
for i in range(1,10):
yield i
使用yield返回数据的函数叫做生成器,它可以通过如下方法不断获取值:
f = func()
f.next()
f.next()
如果该生成器要不断获得外界值,也可以使用yield来获取:
def func():
r = 0
n = yield r
if not n:
return
for i in range(1,10):
yield i
外界通过send方法传入值:
f = func()
f.send(5)
f.next()
f.next()
可以将该函数作为参数传入另一个高阶函数,协作运行:
def func2(f)
f = func()
f.send(5)
print f.next()
print f.next()
这种形式的程序就叫做协程。
import urllib
import re
#this function is slow, use thread to costume more cpu
def get_html(url):
page = urllib.urlopen(url)
return page.read()
addr_pattern = re.compile(r'\/[^\/]+;illust_id\=\d+')
pic_pattern = re.compile(r'http[^\>]*\.jpg')
#an address has many pictures,so find the pattern
def get_addr(html):
global addr_pattern
while(1):
print type(html)
s = '1'
if(type(html)!=type(s)):
html = yield ''
continue
strs = re.split(r'\n',html)
for s in strs:
m = addr_pattern.search(s)
if(m):
yield m.group()
#over
html = yield ''
#an address has only one picture, get its address
def get_pic(url):
global pic_pattern
m = pic_pattern.search(get_html(url))
print m
if(m):
return m.group()
def mainfunc():
url = 'https://www.pixiv.net/search.php?word=Fate%2FGrandOrder&s_mode=s_tag_full&order=date_d&p='
fout = open('address.txt','a')
page = 1
f = get_addr(get_html(url+str(page)))
while(page<5):
h = f.next()
if(h==''):
print 'page%s'%page
page = page + 1
h = f.send(get_html(url+str(page)))
h = 'https://www.pixiv.net'+h
s = get_pic(h)
if(s):
fout.write(s)
fout.write('\n\r')
fout.close()
if __name__ == '__main__':
mainfunc()
功能是爬取P站的图片地址。但尝试下载图片却被拒绝访问了,问题还没能解决。
参考资料:
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868328689835ecd883d910145dfa8227b539725e5ed000
爬虫 http://www.cnblogs.com/fnng/p/3576154.html