利用PyCharm Profile分析异步爬虫效率详解


Posted in Python onMay 08, 2019

今天比较忙,水一下

下面的代码来源于这个视频里面提到的,github 的链接为:github.com/mikeckenned…(本地下载)

第一个代码如下,就是一个普通的 for 循环爬虫。原文地址。

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('h1')
 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 工具来具体看看哪些地方比较耗时间。

点击Profile (文件名称)

利用PyCharm Profile分析异步爬虫效率详解

之后获取到得到一个详细的函数调用关系、耗时图:

利用PyCharm Profile分析异步爬虫效率详解

可以看到 get_html 这个方法占了96.7%的时间。这个程序的 IO 耗时达到了97%,获取 html 的时候,这段时间内程序就在那死等着。如果我们能够让他不要在那儿傻傻地等待 IO 完成,而是开始干些其他有意义的事,就能节省大量的时间。

稍微做一个计算,试用asyncio异步抓取,能将时间降低多少?

get_html这个方法耗时36.8s,一共调用了15次,说明实际上获取一个链接的 html 的时间为36.8s / 15 = 2.4s。**要是全异步的话,获取15个链接的时间还是2.4s。**然后加上get_title这个函数的耗时0.6s,所以我们估算,改进后的程序将可以用 3s 左右的时间完成,也就是性能能够提升13倍。

再看下改进后的代码。原文地址。

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('h1')
 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 图:

利用PyCharm Profile分析异步爬虫效率详解

可见现在耗时为大约3.8s,基本符合我们的预期了。

利用PyCharm Profile分析异步爬虫效率详解

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python实现的检测网站挂马程序
Nov 30 Python
Python中字符编码简介、方法及使用建议
Jan 08 Python
Python中实现从目录中过滤出指定文件类型的文件
Feb 02 Python
python访问系统环境变量的方法
Apr 29 Python
简单谈谈Python中的json与pickle
Jul 19 Python
Python将多个excel表格合并为一个表格
Feb 22 Python
pygame游戏之旅 调用按钮实现游戏开始功能
Nov 21 Python
PyQt5 实现给窗口设置背景图片的方法
Jun 13 Python
对python 调用类属性的方法详解
Jul 02 Python
在django中使用post方法时,需要增加csrftoken的例子
Mar 13 Python
如何通过python实现IOU计算代码实例
Nov 02 Python
asyncio异步编程之Task对象详解
Mar 13 Python
Python数据类型之String字符串实例详解
May 08 #Python
Python数据类型之List列表实例详解
May 08 #Python
Python3使用TCP编写一个简易的文件下载器功能
May 08 #Python
详解Python的三种可变参数
May 08 #Python
Python数据类型之Tuple元组实例详解
May 08 #Python
基于腾讯云服务器部署微信小程序后台服务(Python+Django)
May 08 #Python
python中正则表达式与模式匹配
May 07 #Python
You might like
据说是雅虎的一份PHP面试题附答案
2009/01/07 PHP
PHP实现微信公众平台音乐点播
2014/03/20 PHP
PHP使用数组依次替换字符串中匹配项
2016/01/08 PHP
PHP命名空间namespace用法实例分析
2016/09/27 PHP
php 判断字符串编码是utf-8 或gb2312实例
2016/11/01 PHP
用Laravel轻松处理千万级数据的方法实现
2020/12/25 PHP
[全兼容哦]--实用、简洁、炫酷的页面转入效果loing
2007/05/07 Javascript
符合W3C网页标准的iframe标签的使用方法
2007/07/19 Javascript
JS 控制非法字符的输入代码
2009/12/04 Javascript
基于jQuery的合并表格中相同文本的相邻单元格的代码
2011/04/06 Javascript
(跨浏览器基础事件/浏览器检测/判断浏览器)经验代码分享
2013/01/24 Javascript
JavaScript代码复用模式详解
2014/11/07 Javascript
微信小程序 图片等比例缩放(图片自适应屏幕)
2016/11/16 Javascript
JS使用正则实现去掉字符串左右空格的方法
2016/12/27 Javascript
jquery实现tab键进行选择后enter键触发click行为
2017/03/29 jQuery
node+koa2+mysql+bootstrap搭建一个前端论坛
2018/05/06 Javascript
新手必须知的Node.js 4个JavaScript基本概念
2018/09/16 Javascript
node错误处理与日志记录的实现
2018/12/24 Javascript
vue+element UI实现树形表格带复选框的示例代码
2019/04/16 Javascript
js实现时分秒倒计时
2019/12/03 Javascript
javascript实现点击星星小游戏
2019/12/24 Javascript
小程序跳转H5页面的方法步骤
2020/03/06 Javascript
[01:07:46]完美世界DOTA2联赛循环赛 Magma vs IO BO2第二场 11.01
2020/11/02 DOTA
python基础教程之python消息摘要算法使用示例
2014/02/10 Python
Python实现按照指定要求逆序输出一个数字的方法
2018/04/19 Python
Python包,__init__.py功能与用法分析
2020/01/07 Python
Python读取文件内容为字符串的方法(多种方法详解)
2020/03/04 Python
详解通过focusout事件解决IOS键盘收起时界面不归位的问题
2019/07/18 HTML / CSS
html5视频媒体标签video的使用方法及完整参数说明详解
2019/09/27 HTML / CSS
人力资源管理专业自荐书范文
2014/02/10 职场文书
标准化管理实施方案
2014/02/25 职场文书
大学自主招生自荐信范文
2014/02/26 职场文书
浅谈什么是SpringBoot异常处理自动配置的原理
2021/06/21 Java/Android
Python多线程 Queue 模块常见用法
2021/07/04 Python
【海涛DOTA解说】EVE女子战队独家录像加ZSMJ神牛两连发
2022/04/01 DOTA
Oracle中日期的使用方法实例
2022/07/07 Oracle