关闭
当前位置:首页 - 最新微博大事件 - 正文

压力测试,Python网络爬虫的同步和异步,苹果电脑

admin 2019-04-08 258°c

作者:我为峰2014

专栏:https://www.jianshu.com/u/c1ab741ef52e


一、同步与异步

#同步编程(同一时刻只能做一件事,做完了才干做下一件工作)
<-a_url-><-b_url-><-c_url->
#异步编程 (能够近似的了解成同一时刻有多个工作在做,但有先后)
<-a_url->
<-b_url->
<-c_url->
<-d_url->
<-e_url->
<-f_url->
<-g_url->
<-h_url->
<--i_url-->
<--j_url-->

模板

import asyncio
#函数名:做现在的使命时不等候,能持续做其他使命。
async def donow_meantime_dontwait(url):
response = await requests.get(url)
#函数名:快速高效的做使命
async def fast_do_your_thing():
await asyncio.wait([donow_meantime_dontwait(url) for url in urls])
#下面两行都是套路,记住就好
loop = asyncio.get_event_loop()
loop.run_until_complete(fast_do_your_thing())


tips:await表达式中的目标有必要是awaitablereques窦志明ts不支持非堵塞aiohttp是用于异步恳求的库


代码

import asyncio
import requests
import time
import aiohttp
urls = ['https://book.douban.com/tag/小说','https://book.douban.com/tag/科幻',
'https://book.douban.com/tag/漫画','https://book.douban.com/tag/奇幻',
'https://book.douban.com/tag/前史','https://book.douban.com/tag/经济学']
async def requests_meantime_dont_wait(url):
print(url)
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
print(resp.status)
print("{url} 得到呼应".format(url=url))
async def fast_requsts(urls):
start = time.time()
await asyncio.wait([requests_meantime_dont_wait(url) for url in urls])
end 上海中山医院= time.time()
print("Complete in {} seconds".format(end - start))
loop = asyncio.get_event_loop()
loop.run_until_complete(fast_requsts(urls))


gevent简介

gevent是一个python的并发库,它为各种并发和网络相关的使命供给了整齐的API。

gevent中用到的首要方式是greenlet,它是以C扩展模块方式接入Python的轻量级协程。 gre压力测验,Python网络爬虫的同步和异步,苹果电脑enlet悉数运转在主程序操作体系进程的内部,但它们被协作式地调度。

山公补丁

requests库是堵塞式的,为了将requests同步更改为异步。只要将requests库堵塞式更改为非堵塞,异步操作才干完结。

而gevent库中的山公补丁(monkey patch),gevent能够修正规范库里边大部分的堵塞式体系调用。这样在不改动原有代码的状况下,将运用的堵塞式办法,变成协程式的(异步)。

代码

from gevent import monkey
import gevent
import requests
import time
monkey.patch_all()
def req(url):
print(url)
resp = requests.get(url)
print(resp.status_code,url)
def synchronous_times(urls):
"""同步恳求运转时刻"""
start = time.time()
for url in urls:
req(url)
end = time.time()
print('同步履行时刻 {} s'.format(end-start))
def asynchronous_times(urls):
"""异步恳求运转时刻"""
start = time.time()
gevent.joinall([gevent.spawn(req,url) for url in urls])
end = ti压力测验,Python网络爬虫的同步和异步,苹果电脑me.time()
print('异步履行时刻 {} s'.format(end - start))
urls = ['https://book.douban.com/tag/小说','https://book.douban.com/ta压力测验,Python网络爬虫的同步和异步,苹果电脑g/科幻',
'htt周涛的女儿ps://book.douban.com/tag/漫画','https://book.douban.com/tag/奇幻',
'https://book.douban.com/tag/前史','https://book.douban.com/tag/经济学']
synchronous_times(urls)
asynchronous_times(urls)

gevent:异步理论与实战

Python网络爬虫的同步和异步


gevent库中压力测验,Python网络爬虫的同步和异步,苹果电脑运用的最中心的是Greenlet-一种用C写的轻量级python模块。在恣意时刻,体系只能答应一个Greenlet处于运转状况

一个greenlet遇到IO操作时,比方拜访网络,就主动切换到其他的greenlet,比及IO操作完结,再在恰当的时分切换回来持续履行。由于IO操作十分耗时,常常使程序处于等候状况,有了gevent为咱们主动切换协程,就确保总有greenlet在运转,而不是等候IO。

串行和异步

高并发的中心是让一个大的使命分红一批子使命,而且子使命会被被体系高功率的调度,完结同步或许异步。在两个子使命之间切换,也便是常常提到的上下文切换。

同步便是让子使命串行,而异步有点影兼顾之术,但在恣意时刻点,真身只要一个,子使命并不是真实的并行,而是充分运用了碎片化的时刻,让程序不要糟蹋在等候上。这便是异步,功率杠杆的。

gevent中的上下文切换是经过yield完结。在这个比如中,咱们会有两个子使命,相互运用对方等候的时刻做自己的工作。这儿咱们运用gevent.sleep(0)代表程序会在这儿停0秒。

import gevent
def foo():
print('Running in foo')
gevent.sleep(0)
print('Explicit context switch to foo again')
def bar():
print('Explicit context to bar')
gevent.sleep(0)
print('Implicit context switch back to bar')
gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar)
])

运转的次序:

Running in foo
Explicit context to bar
Explicit context switch to foo again
Implicit context switch back to bar

同步异步的次序问题

同步运转便是串行,123456...,可是异步的次序是随机的恣意的(依据子使命耗费的时刻而定温州医学院王静)

代码

import gevent
import random
def task(pid):
"""
Some non-deterministic task
"""
gevent.sleep(random.randint(0,2)*0.001)
print('Task %s d福特嘉年华one' % pid)
#同步(成果更像串行)
def synchronous():
for i in range(1,10):
task(i)
#异步(成果更像乱步)
def asynchronous():
threads = [gevent.spawn(task, i) for i in range(10)]
gevent.joinall(threads)
print('Synchronous同步:')
synchronous()
print('Asynchronous异步:')
asynchronous()

输出

Synchronous同步:
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 燕麦8 done
Task 9 done
Asynchronous异步:
Task 1 done
Task 5 done
Task 6 done
Task 2 done
Task 4 done
Task 7 正月十三done
Task 8 don压力测验,Python网络爬虫的同步和异步,苹果电脑e
Task 9 done
Task 0 done
Task 3 done

同步事例中一切的使命都是依照次序履行,这导致主程序是堵塞式的(堵塞会暂停主程序的履行)。

gevent.spawn会对传入的使命(子使命调集)进行进行调度,gevent.joinall办法会堵塞当时程序,除非一切的greenlet都履行完毕,程序才会完毕。

实战

完结gevent究竟怎样用,把异步拜访得到的数据提取出来。

在有道词典查找框输入“headvllo”按回车。调查数据恳求状况 调查有道的url构建。

剖析url规则

#url构建只需要传入word即可
url = "http://dict.you辉县天气预报dao.com/w/eng/{}/".format(word)

解析网页数据

def fetch_word_info(word):
url = "http://dict.yo压力测验,Python网络爬虫的同步和异步,苹果电脑udao.com/w/eng/{}/".format(word)
resp = requests.get(url,headers=headers)
doc = pq(resp.text)
pros = ''
for pro in doc.items('.baav .pronounce'):
pros+=pro.text()
description = ''
for l庆丰军i in doc.items('#phrsListTab .trans-container ul li'):
description +=li.text()
return {'word':word,'音标':pros,'注释':description}

由于requests库在任何时分只答应有一个拜访完毕彻底完毕后,才干进行下一次拜访。无法经过正规途径拓宽成异步,因而这儿运用了monkey补丁

同步代码

import requests
from pyquery import PyQuery as pq
import gevent
import time
import gevent.monkey
gevent.monkey.patch_all()
words = ['good','bad','cool',
'hot','nice','better',
'head','up','down',
'right','left','east']
def synchronous():
start = time.time()
print('同步开端了')
for word in words:
print(fetch_word_info(word))
end = time.time()
print("同步运转时刻: %s 秒" % str(end - start))
#履行同步
synchronous()

异步代码

import requests
from pyquery import PyQuery as pq
import gevent
import time
import gevent.monkey
gevent.monkey.patch_all()
words = ['good','bad','cool',
'hot','nice','better',
'head','up','down',
'right','left','east']
def asynchronous():
start = time.time()
print('异步开端了')
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))
#履行异步
asynchronous()

咱们能够对待爬网站实时异步拜访,速度郑州地图会大大提高。咱们现在是爬取12个二阶魔方词语的信息,也便是说一会儿咱们对网站拜访了12次,这还没啥问题,假设爬10000+个词语,运用gevent的话,那几秒钟之内就给网站一股脑的发恳求,说不定网站就把爬虫封了。

解决办法

将列表等分为若干个子列表,分批爬取。举例咱们有一个数字列表(0-19),要均匀的等分为4份,也便是子列表有5个atsl数。下面是我在stackoverflow查找到的列表等分计划:

办法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)]
prin压力测验,Python网络爬虫的同步和异步,苹果电脑t(chunks(seq, 5))

办法3

def chunks(seq,size):
for i in range(0,len(seq), size):
yield seq[i:i+size]
prin海清的老公和儿子T(chunks(seq,5))
for x in chunks(req,5):
print(x)

数据量不大的状况下,选哪一种办法都能够。假如特别大,主张运用办法3.

着手完结

import requests
from pyquery import PyQuery as pq
import gevent
impor睛几画t time
import gevent.monkey
gevent.小炒肉monkey.patch_all()
words = ['good','bad','cool',
'hot','nice','better',
'head','up','down',
'right','left','east']
def fetch_word_info(word):
url = "http://dict.youdao.com/w/eng/{}/".format(word)
resp = requests.get(url,headers=headers)
doc = pq(resp.text)
pro牙齿贴面s = ''
for pro in doc.items('.baav .pronounce'):
pros+=pro.text()
description = ''
for li in doc.items('#phrsListTab .trans-container 深海鱼油的成效与效果ul li'):
description +=li.text()
return {'word':word,'音标':pros,'注释':description}
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)
admin 14文章 0评论 主页

  用户登录