摘要:第三節(jié)協(xié)程繼續(xù)基礎(chǔ)框架搭好了,下面來正式的來一個(gè)項(xiàng)目吧全球設(shè)計(jì)師的作品展示平臺就從這拉幾張圖吧,具體的網(wǎng)頁解析方式網(wǎng)上有很多,在此略過,我已經(jīng)取出了一些圖片地址,保存在了里,這次就用這些吧。
第三節(jié) 協(xié)程???
繼續(xù)...基礎(chǔ)框架搭好了,下面來正式的來一個(gè)項(xiàng)目吧
behance
全球設(shè)計(jì)師的作品展示平臺
就從這拉幾張圖吧,具體的網(wǎng)頁解析方式網(wǎng)上有很多,在此略過,我已經(jīng)取出了一些圖片地址,保存在了list.txt里,這次就用這些吧。
綜合多種因素,最后選用了協(xié)程來下載圖片
即asyncio
框架則用了aiohttp
實(shí)現(xiàn)思路:
目的
將網(wǎng)絡(luò)上的圖片(最好是縮略圖)先下載到本地,記錄圖片信息,比如ID以便獲得更高質(zhì)量的圖片,將圖片顯示到界面
問題
為了更快速的展示頁面,我需要同時(shí)下載一定數(shù)量的圖片...
我需要?jiǎng)討B(tài)的將下載任務(wù)發(fā)送給后臺服務(wù)...
這里可以在程序啟動的時(shí)候設(shè)置一個(gè)配置列表cfg
from os import path as osPath, getcwd, mkdir ... def __init__(self): ... self.cfg = self.initCfg() def initCfg(self): cfg = {} # 代理,沒有可不用設(shè)置 # cfg["proxies"] = "127.0.0.1:61274" # 加載圖片列表 filename = "list.txt" if osPath.exists(filename): with open(filename, "r") as f: cfg["picList"] = f.read().strip().split(" ") # 設(shè)置圖片的保存位置 current_folder = getcwd() cfg["pic_temp"] = osPath.join( current_folder, "pic_temp") if not osPath.isdir( cfg["pic_temp"] ): mkdir(cfg["pic_temp"]) return cfg
然后傳遞給服務(wù)進(jìn)程就可以了
p = Process(target = startServiceP, args = ( self.GuiQueue, self.ServiceQueue, self.cfg ))
先來修改一下html的內(nèi)容,添加一個(gè)自定義控件,用來存放圖片:
在服務(wù)進(jìn)程ServiceEvent里添加一個(gè)方法getPicByList()
def getPicByList(self, msg): # 為圖片創(chuàng)建占位圖 imgidList = self.__creatPlaceholderImg() for imgid in imgidList: picHttp = self.cfg["picList"].pop(0) file_name = picHttp.split("/")[-1] file_path = osPath.join( self.cfg["pic_temp"], file_name ) # 圖片下載完成后需要執(zhí)行的任務(wù) _GuiRecvMsgDict = { "fun" : "setImgBg", "msg" : {"id":imgid,"fpath":file_path} } if not osPath.isfile(file_path): # 將下載任務(wù)動態(tài)添加到協(xié)程循環(huán)中 self.__run_coroutine_threadsafe( {"id": imgid,"http": picHttp,"fpath": file_path}, _GuiRecvMsgDict ) else: self.__putGui( "setImgBg", {"id":imgid,"fpath":file_path} )
當(dāng)用戶點(diǎn)擊下載圖片的按鈕后會執(zhí)行到這個(gè)方法,為了更好的體驗(yàn),在圖片下載之前先為其占據(jù)了空間,可以在其上顯示loading動畫,更重要的一點(diǎn)是,通過它可以控制圖片的顯示順序,因?yàn)橛脜f(xié)程下載圖片,你無法預(yù)知完成的順序...
def __creatPlaceholderImg(self): # 先創(chuàng)建5個(gè)占位圖 html = "" imgidList = [] time_now = "" for i in range(0, 5): time_now = "-".join( ( str(i), str(time()) ) ) # 儲存圖片的id imgidList.append( time_now ) html += self.html % ( time_now ) self.__putGui("creatPlaceholderImg", html) return imgidList
之后就到了動態(tài)創(chuàng)建協(xié)程的部分了
def __run_coroutine_threadsafe(self, data, _GuiRecvMsgDict): asyncio.run_coroutine_threadsafe(self.dld.stream_download( data, _GuiRecvMsgDict ), self.new_loop)
但在正式介紹run_coroutine_threadsafe()之前,我們需要先開啟一個(gè)協(xié)程循環(huán)
但我們已經(jīng)開啟了一個(gè)用于處理隊(duì)列的循環(huán)了,沒辦法再開一個(gè)(也不排除是咱太菜),于是另開了一個(gè)線程專來處理協(xié)程
class ServiceEvent(object): """服務(wù)進(jìn)程""" def __init__(self, _GuiQueue, cfg): ... # 主線程中創(chuàng)建一個(gè)事件循環(huán) self.new_loop = asyncio.new_event_loop() self.dld = AsyncioDownload( self.new_loop, self.GuiQueue, self.proxies )
class AsyncioDownload(object): """使用協(xié)程下載圖片""" def __init__(self, loop, _GuiRecvMsg, proxies=None ): self.GuiRecvMsg = _GuiRecvMsg self._session = None self.loop = loop self.prox = "".join(("http://", proxies)) if proxies else proxies self.timeout = 10 # 啟動一個(gè)線程,傳遞主線程中創(chuàng)建的事件循環(huán) t = Thread(target=self.start_loop, args=(self.loop,)) t.setDaemon(True) # 設(shè)置子線程為守護(hù)線程 t.start() def start_loop(self, loop): # 啟動事件循環(huán) asyncio.set_event_loop(loop) loop.run_forever() def __session(self): if self._session is None: self._session = aiohttp.ClientSession(loop=self.loop) return self._session async def stream_download(self, d, _GuiRecvMsgDict): try: client = self.__session() async with client.get( d["http"], proxy=self.prox, timeout=self.timeout) as response: if response.status != 200: print("error") return # 保存圖片到本地 if not osPath.isfile(d["fpath"]): with open(d["fpath"], "ab") as file: while True: chunk = await response.content.read(1024) if not chunk: break file.write(chunk) # 圖片下載完成后告知主線程 self.GuiRecvMsg.put(_GuiRecvMsgDict) except asyncio.TimeoutError: pass
最后,主進(jìn)程獲得圖片的id及路徑,顯示到窗口中
function setImgBg( d ){ var div = $(div[imgid="{d.id}"]); if(div){ div.post( ::this.style#background-image = "url(" + d.fpath + ")" ); } }
源碼
總結(jié):
完成這個(gè)項(xiàng)目使用了
多進(jìn)程 ---- 后臺服務(wù)
多線程 ---- 事件循環(huán)
協(xié)程 ---- IO操作
相對一個(gè)單純的爬蟲腳本來說,還是有點(diǎn)復(fù)雜的,尤其是交互,難怪這么多人不愿意寫界面...
雖然還有不足,但本次項(xiàng)目的內(nèi)容就到這了。
謝謝。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/40761.html
摘要:第二節(jié)將任務(wù)添加到隊(duì)列上一個(gè)栗子只是簡單實(shí)現(xiàn)了下網(wǎng)頁與后臺的通信你可以在這里處理任何你想要的操作你已經(jīng)點(diǎn)到我了但由于是同一個(gè)進(jìn)程,如果你做了很耗時(shí)的操作,比如下載一張圖片之類的操作你會發(fā)現(xiàn),窗口卡住了,一般表現(xiàn)為窗口泛白,出現(xiàn)未響應(yīng)的提示但 第二節(jié) 將任務(wù)添加到隊(duì)列! 上一個(gè)栗子只是簡單實(shí)現(xiàn)了下網(wǎng)頁與后臺的通信 def clickMe(self): #你可以在這里處理任何你想要...
摘要:下載地址簡介結(jié)合與編寫軟件使用方法安裝個(gè)人使用建立的環(huán)境下載并解壓下載并解壓打開控制臺轉(zhuǎn)到解壓目錄比如此時(shí)就會將安裝到第三方安裝包的目錄下我的是注冊或者修改源碼注冊方式找到位位使用控制臺注冊路徑使用絕對路徑可以復(fù)制到然后就可以了修改 下載地址: Pysciter-GitHub Sciter 簡介: 結(jié)合HTML與Python編寫軟件 使用方法: 安裝Python3 (個(gè)人使用A...
摘要:如何在中使用動畫前端掘金本文講一下中動畫應(yīng)用的部分。與的快速入門指南推薦前端掘金是非常棒的框架,能夠創(chuàng)建功能強(qiáng)大,動態(tài)功能的。自發(fā)布以來,已經(jīng)廣泛應(yīng)用于開發(fā)中。 如何在 Angular 中使用動畫 - 前端 - 掘金本文講一下Angular中動畫應(yīng)用的部分。 首先,Angular本生不提供動畫機(jī)制,需要在項(xiàng)目中加入Angular插件模塊ngAnimate才能完成Angular的動畫機(jī)制...
摘要:第四章安全管理制度發(fā)布第十條安全管理制度必須以正式文件的形式發(fā)布施行。第十一條安全管理制度由信息安全管理小組制訂,信息安全領(lǐng)導(dǎo)小組審批發(fā)布。第二十條安全管理制度的修改與廢止須經(jīng)信息安全領(lǐng)導(dǎo)組織審批確認(rèn),信息安全管理部門備案。 字?jǐn)?shù) 3610閱讀 760評論 0贊 3《xxxx安全管理制度匯編》****制度管理辦法****文...
閱讀 1677·2021-11-17 09:33
閱讀 3541·2021-11-16 11:40
閱讀 3063·2019-08-30 11:23
閱讀 1055·2019-08-29 16:36
閱讀 2472·2019-08-29 13:23
閱讀 1746·2019-08-29 12:59
閱讀 1550·2019-08-29 12:42
閱讀 1987·2019-08-28 18:22