利用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字符串排序方法
Aug 29 Python
python中的计时器timeit的使用方法
Oct 20 Python
redis之django-redis的简单缓存使用
Jun 07 Python
对DJango视图(views)和模版(templates)的使用详解
Jul 17 Python
提升Python效率之使用循环机制代替递归函数
Jul 23 Python
python实现ssh及sftp功能(实例代码)
Mar 16 Python
Python request操作步骤及代码实例
Apr 13 Python
使用Keras训练好的.h5模型来测试一个实例
Jul 06 Python
Python设计密码强度校验程序
Jul 30 Python
互斥锁解决 Python 中多线程共享全局变量的问题(推荐)
Sep 28 Python
python实现猜拳游戏项目
Nov 30 Python
Python实现随机爬山算法
Jan 29 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
PHPlet在Windows下的安装
2006/10/09 PHP
php计划任务之验证是否有多个进程调用同一个job的方法
2015/12/07 PHP
thinkPHP简单调用函数与类库的方法
2017/03/15 PHP
PHP中引用类型和值类型功能与用法示例
2019/02/26 PHP
利用ASP发送和接收XML数据的处理方法与代码
2007/11/13 Javascript
javascript日期转换 时间戳转日期格式
2011/11/05 Javascript
node.js中的buffer.length方法使用说明
2014/12/14 Javascript
详解JavaScript的回调函数
2015/11/20 Javascript
PHP自动加载autoload和命名空间的应用小结
2017/12/01 Javascript
如何将HTML字符转换为DOM节点并动态添加到文档中详解
2018/08/19 Javascript
JS实现将对象转化为数组的方法分析
2019/01/21 Javascript
vue 避免变量赋值后双向绑定的操作
2020/11/07 Javascript
python代码检查工具pylint 让你的python更规范
2012/09/05 Python
python实现复制整个目录的方法
2015/05/12 Python
Python实现检测文件MD5值的方法示例
2018/04/11 Python
初次部署django+gunicorn+nginx的方法步骤
2019/09/11 Python
解决pycharm中导入自己写的.py函数出错问题
2020/02/12 Python
keras实现调用自己训练的模型,并去掉全连接层
2020/06/09 Python
python绘图pyecharts+pandas的使用详解
2020/12/13 Python
使用html5+css3来实现slider切换效果告别javascript+css
2013/01/08 HTML / CSS
萌新的HTML5 入门指南
2020/11/06 HTML / CSS
ShellScript面试题一则-ShellScript编程
2014/03/05 面试题
东方红海科技面试题软件测试方面
2012/02/08 面试题
大学新生军训感言
2014/02/25 职场文书
国培计划培训感言
2014/03/11 职场文书
道路施工安全责任书
2014/07/24 职场文书
中秋节国旗下演讲稿
2014/09/05 职场文书
幼儿园迎国庆65周年活动策划方案
2014/09/16 职场文书
2014年司法所工作总结
2014/11/22 职场文书
小学音乐教师个人工作总结
2015/02/05 职场文书
商业计划书如何写?关键问题有哪些?
2019/07/11 职场文书
Nginx解决前端访问资源跨域问题的方法详解
2021/03/31 Servers
MySQL EXPLAIN输出列的详细解释
2021/05/12 MySQL
MySQL中的隐藏列的具体查看
2021/09/04 MySQL
聊聊Lombok中的@Builder注解使用教程
2021/11/17 Java/Android
python前后端自定义分页器
2022/04/13 Python