這篇文章主要介紹了如何使用PyCharm Profile分析異步爬蟲效率,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
創(chuàng)新互聯(lián)建站云計(jì)算的互聯(lián)網(wǎng)服務(wù)提供商,擁有超過13年的服務(wù)器租用、成都多線服務(wù)器托管、云服務(wù)器、網(wǎng)頁(yè)空間、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗(yàn),已先后獲得國(guó)家工業(yè)和信息化部頒發(fā)的互聯(lián)網(wǎng)數(shù)據(jù)中心業(yè)務(wù)許可證。專業(yè)提供云主機(jī)、網(wǎng)頁(yè)空間、域名申請(qǐng)、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。第一個(gè)代碼如下,就是一個(gè)普通的 for 循環(huán)爬蟲。原文地址。
import requests import bs4 from colorama import Fore def main(): get_title_range() print("Done.") def get_html(episode_number: int) -> str: print(Fore.YELLOW + f"Getting HTML for episode {episode_number}", flush=True) url = f'https://talkpython.fm/{episode_number}' resp = requests.get(url) resp.raise_for_status() return resp.text def get_title(html: str, episode_number: int) -> str: print(Fore.CYAN + f"Getting TITLE for episode {episode_number}", flush=True) soup = bs4.BeautifulSoup(html, 'html.parser') header = soup.select_one('h2') if not header: return "MISSING" return header.text.strip() def get_title_range(): # Please keep this range pretty small to not DDoS my site. ;) for n in range(185, 200): html = get_html(n) title = get_title(html, n) print(Fore.WHITE + f"Title found: {title}", flush=True) if __name__ == '__main__': main()
這段代碼跑完花了37s,然后我們用 pycharm 的 profiler 工具來具體看看哪些地方比較耗時(shí)間。
點(diǎn)擊Profile (文件名稱)
之后獲取到得到一個(gè)詳細(xì)的函數(shù)調(diào)用關(guān)系、耗時(shí)圖:
可以看到 get_html 這個(gè)方法占了96.7%的時(shí)間。這個(gè)程序的 IO 耗時(shí)達(dá)到了97%,獲取 html 的時(shí)候,這段時(shí)間內(nèi)程序就在那死等著。如果我們能夠讓他不要在那兒傻傻地等待 IO 完成,而是開始干些其他有意義的事,就能節(jié)省大量的時(shí)間。
稍微做一個(gè)計(jì)算,試用asyncio異步抓取,能將時(shí)間降低多少?
get_html這個(gè)方法耗時(shí)36.8s,一共調(diào)用了15次,說明實(shí)際上獲取一個(gè)鏈接的 html 的時(shí)間為36.8s / 15 = 2.4s。**要是全異步的話,獲取15個(gè)鏈接的時(shí)間還是2.4s。**然后加上get_title這個(gè)函數(shù)的耗時(shí)0.6s,所以我們估算,改進(jìn)后的程序?qū)⒖梢杂?3s 左右的時(shí)間完成,也就是性能能夠提升13倍。
再看下改進(jìn)后的代碼。原文地址。
import asyncio from asyncio import AbstractEventLoop import aiohttp import requests import bs4 from colorama import Fore def main(): # Create loop loop = asyncio.get_event_loop() loop.run_until_complete(get_title_range(loop)) print("Done.") async def get_html(episode_number: int) -> str: print(Fore.YELLOW + f"Getting HTML for episode {episode_number}", flush=True) # Make this async with aiohttp's ClientSession url = f'https://talkpython.fm/{episode_number}' # resp = await requests.get(url) # resp.raise_for_status() async with aiohttp.ClientSession() as session: async with session.get(url) as resp: resp.raise_for_status() html = await resp.text() return html def get_title(html: str, episode_number: int) -> str: print(Fore.CYAN + f"Getting TITLE for episode {episode_number}", flush=True) soup = bs4.BeautifulSoup(html, 'html.parser') header = soup.select_one('h2') if not header: return "MISSING" return header.text.strip() async def get_title_range(loop: AbstractEventLoop): # Please keep this range pretty small to not DDoS my site. ;) tasks = [] for n in range(190, 200): tasks.append((loop.create_task(get_html(n)), n)) for task, n in tasks: html = await task title = get_title(html, n) print(Fore.WHITE + f"Title found: {title}", flush=True) if __name__ == '__main__': main()
同樣的步驟生成profile 圖:
可見現(xiàn)在耗時(shí)為大約3.8s,基本符合我們的預(yù)期了。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“如何使用PyCharm Profile分析異步爬蟲效率”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!