摘要:異步下載國(guó)旗圖片和國(guó)家名數(shù)據(jù)用來捕獲異常保存圖片文件負(fù)責(zé)下載的主函數(shù),由傳遞國(guó)家名是數(shù)據(jù)。異步獲取圖片異步獲取國(guó)家名中的子句在沒有異常時(shí)會(huì)運(yùn)行這里獲取循環(huán)是為了在保存圖片時(shí)不阻塞函數(shù)內(nèi)部維護(hù)了一個(gè)對(duì)象注。
異步下載國(guó)旗圖片和國(guó)家名數(shù)據(jù)
import aiohttp import asyncio import os import time import sys POP20_CC = ("CN IN US ID BR PK NG BD RU JP MX PH VN ET EG DE IR CD FR").split() BASE_URL = "http://flupy.org/data/flags" DEST_DIR = "downloads/" class FetchError(Exception): #用來捕獲異常 def __init__(self, country_code): self.country_code = country_code def save_flag(img, filename): #保存圖片文件 path = os.path.join(DEST_DIR, filename) with open(path, "wb") as fp: fp.write(img) async def http_get(session, url): #負(fù)責(zé)下載的主函數(shù),session由download_many傳遞 async with session.get(url) as resp: if resp.status == 200: ctype = resp.headers.get("Content-type", "").lower() if "json" in ctype or url.endswith(".json"): #國(guó)家名是json數(shù)據(jù)。如果內(nèi)容類型是json data = await resp.json() #那么就用json()方法獲取內(nèi)容 else: data = await resp.read() #否則直接獲取元數(shù)據(jù) return data elif resp.status == 404: #捕獲異常 raise web.HTTPNotFound() else: raise aiohttp.errors.HttpProcessingError(code=res.sstatus, message=res.reason, headers=res.headers) async def get_flag(session, cc): #獲取圖片 url = "{}/{cc}/{cc}.gif".format(BASE_URL, cc=cc.lower()) image = await http_get(session, url) #這里是Io請(qǐng)求需要異步操作 return image async def get_country(session, cc): #獲取國(guó)家名 url = "{}/{cc}/metadata.json".format(BASE_URL, cc=cc.lower()) metadata = await http_get(session, url) #這里是Io請(qǐng)求需要異步操作 return metadata["country"] def show(text): print(text + "[OK] ", end="") sys.stdout.flush() #挨個(gè)輸出國(guó)家名,沒有這個(gè)刷新緩沖區(qū)方法就會(huì)最后一下子輸出所有國(guó)家名。 async def download_one(session, cc): try: image = await get_flag(session, cc) #異步獲取圖片 country = await get_country(session, cc) #異步獲取國(guó)家名 except web.HTTPNotFound: msg = "not found" except Exception as exc: raise FetchError(cc) from exc else: #try中的else子句在沒有except異常時(shí)會(huì)運(yùn)行 country = country.replace(" ", "_") filename = "{}-{}.gif".format(cc, country) loop = asyncio.get_event_loop() #這里獲取循環(huán)是為了在保存圖片時(shí)不阻塞 loop.run_in_executor(None, save_flag, image, filename) #run_in_excutor函數(shù)內(nèi)部維護(hù)了一個(gè)TheardPollExecutor對(duì)象[注1]。第一個(gè)參數(shù)默認(rèn)為concurrent.futures.Executor實(shí)例。 show(cc) return cc async def download_many(cc_list): async with aiohttp.ClientSession() as session: #獲取ClientSession對(duì)象 res = await asyncio.gather(*[asyncio.ensure_future(download_one(session, cc)) for cc in sorted(cc_list)]) #gather函數(shù)如果參數(shù)為協(xié)程對(duì)象它會(huì)自動(dòng)排定為一個(gè)task,這里我們直接用的ensure_future方法生成了task對(duì)象。然后并發(fā)的運(yùn)行他們,返回一個(gè)結(jié)果聚合值列表。 return len(res) def main(): t0 = time.time() loop = asyncio.get_event_loop() count = loop.run_until_complete(download_many(POP20_CC)) loop.close() elapsed = time.time() - t0 msg = " {} flags download in {:.2f}s" print(msg.format(count, elapsed)) if __name__ == "__main__": main() #def a(*x): #print(x) #a([1,2]) --> ([1,2],) #a(*[1,2]) --> (1,2) #*號(hào)可以將列表或元組里的元素解包,每個(gè)元素作為多帶帶的參數(shù)傳入
其實(shí),異步庫(kù)依賴于低層線程(直至內(nèi)核級(jí)線程),但是這些庫(kù)的用戶無需創(chuàng)建線程,也無需知道用到了基礎(chǔ)設(shè)施中的低層線程。在應(yīng)用中,我們只需確保沒有阻塞的代碼,事件循環(huán)會(huì)在背后處理并發(fā)。異步系統(tǒng)能避免用戶線程級(jí)的開銷,這是它能比多線程系統(tǒng)管理更多并發(fā)連接的原因。
【注1】The loop.run_in_executor() method can be used with a concurrent.futures.ThreadPoolExecutor to execute blocking code in a different OS thread without blocking the OS thread that the event loop runs in.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/43818.html
摘要:介紹本篇博客將繼續(xù)上一篇博客爬蟲之使用的模塊爬取各國(guó)國(guó)旗的內(nèi)容,將用來實(shí)現(xiàn)這個(gè)爬蟲,下載全世界國(guó)家的國(guó)旗圖片。 介紹 ??本篇博客將繼續(xù)上一篇博客:Python爬蟲之使用Fiddler+Postman+Python的requests模塊爬取各國(guó)國(guó)旗 的內(nèi)容,將用Java來實(shí)現(xiàn)這個(gè)爬蟲,下載全世界國(guó)家的國(guó)旗圖片。項(xiàng)目不再過多介紹,具體可以參考上一篇博客。??我們將全世界國(guó)家的名稱放在一個(gè)...
摘要:流程作為上述過程的一個(gè)演示,我們使用的網(wǎng)址為頁面如下在表單中輸入德國(guó),跳轉(zhuǎn)后的頁面如下我們可以發(fā)現(xiàn),在搜索的結(jié)果中,會(huì)出現(xiàn)德國(guó)這個(gè)搜索結(jié)果。點(diǎn)擊該搜索結(jié)果,跳轉(zhuǎn)后的頁面如下在這個(gè)頁面中有我們需要的德國(guó)的國(guó)旗。 介紹 ??本篇博客將會(huì)介紹一個(gè)Python爬蟲,用來爬取各個(gè)國(guó)家的國(guó)旗,主要的目標(biāo)是為了展示如何在Python的requests模塊中使用POST方法來爬取網(wǎng)頁內(nèi)容。??為了知道...
摘要:標(biāo)準(zhǔn)庫(kù)中所有阻塞型函數(shù)都會(huì)釋放,允許其他線程運(yùn)行。如果調(diào)用引發(fā)異常,那么當(dāng)從迭代器檢索其值時(shí),將引發(fā)異常。總結(jié)自版就支持線程了,只不過是使用線程的最新方式。類封裝了模塊的組件,使使用線程變得更加方便。下一篇筆記應(yīng)該是使用處理并發(fā)。 作為Python程序員,平時(shí)很少使用并發(fā)編程,偶爾使用也只需要派生出一批獨(dú)立的線程,然后放到隊(duì)列中,批量執(zhí)行。所以,不夸張的說,雖然我知道線程、進(jìn)程、并行、...
摘要:是之后引入的標(biāo)準(zhǔn)庫(kù)的,這個(gè)包使用事件循環(huán)驅(qū)動(dòng)的協(xié)程實(shí)現(xiàn)并發(fā)。沒有能從外部終止線程,因?yàn)榫€程隨時(shí)可能被中斷。上一篇并發(fā)使用處理并發(fā)我們介紹過的,在中,只是調(diào)度執(zhí)行某物的結(jié)果。 asyncio asyncio 是Python3.4 之后引入的標(biāo)準(zhǔn)庫(kù)的,這個(gè)包使用事件循環(huán)驅(qū)動(dòng)的協(xié)程實(shí)現(xiàn)并發(fā)。asyncio 包在引入標(biāo)準(zhǔn)庫(kù)之前代號(hào) Tulip(郁金香),所以在網(wǎng)上搜索資料時(shí),會(huì)經(jīng)??吹竭@種花的...
摘要:本文重點(diǎn)掌握異步編程的相關(guān)概念了解期物的概念意義和使用方法了解中的阻塞型函數(shù)釋放的特點(diǎn)。一異步編程相關(guān)概念阻塞程序未得到所需計(jì)算資源時(shí)被掛起的狀態(tài)。 導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之控制流程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、掌握異步編程的相關(guān)概念;2、了解期物future的概念、意義和使用方法;3、了解Python...
閱讀 1885·2021-11-23 09:51
閱讀 1027·2021-10-08 10:05
閱讀 3494·2021-09-26 09:55
閱讀 1102·2021-09-22 15:21
閱讀 1681·2021-09-09 09:33
閱讀 1463·2019-08-30 15:56
閱讀 1345·2019-08-30 15:55
閱讀 1024·2019-08-30 13:19