利用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的字典和列表的使用中一些需要注意的地方
Apr 24 Python
详解Python中的__new__、__init__、__call__三个特殊方法
Jun 02 Python
Python脚本获取操作系统版本信息
Dec 17 Python
Python实现识别手写数字 简易图片存储管理系统
Jan 29 Python
python3+PyQt5实现自定义窗口部件Counters
Apr 20 Python
在python中使用requests 模拟浏览器发送请求数据的方法
Dec 26 Python
实例详解Python装饰器与闭包
Jul 29 Python
Python Pillow.Image 图像保存和参数选择方式
Jan 09 Python
Python基于smtplib协议实现发送邮件
Jun 03 Python
python框架flask入门之环境搭建及开启调试
Jun 07 Python
python退出循环的方法
Jun 18 Python
Python3+PyCharm+Django+Django REST framework配置与简单开发教程
Feb 16 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+JS无限级可伸缩菜单详解(简单易懂)
2007/01/02 PHP
JS 网站性能优化笔记
2011/05/24 PHP
php二维数组排序详解
2013/11/06 PHP
Windows下的PHP安装pear教程
2014/10/24 PHP
php猴子选大王问题解决方法
2015/05/12 PHP
PHP开发之归档格式phar文件概念与用法详解【创建,使用,解包还原提取】
2017/11/17 PHP
laravel ORM 只开启created_at的几种方法总结
2018/01/29 PHP
thinkPHP5框架导出Excel文件简单操作示例
2018/08/03 PHP
iis6+javascript Add an Extension File
2007/06/13 Javascript
慎用 somefunction.prototype 分析
2009/06/02 Javascript
jquery隐藏标签和显示标签的实例
2013/11/11 Javascript
jQuery获得内容和属性方法及示例
2013/12/02 Javascript
JS常用函数使用指南
2014/11/23 Javascript
node.js中的fs.readFile方法使用说明
2014/12/15 Javascript
深入解析JavaScript框架Backbone.js中的事件机制
2016/02/14 Javascript
微信小程序 数组(增,删,改,查)等操作实例详解
2017/01/05 Javascript
vue表单绑定实现多选框和下拉列表的实例
2017/08/12 Javascript
jQuery访问浏览器本地存储cookie、localStorage和sessionStorage的基本用法
2017/10/20 jQuery
JS实现根据数组对象的某一属性排序操作示例
2019/01/14 Javascript
Vue使用JSEncrypt实现rsa加密及挂载方法
2020/02/07 Javascript
vue随机验证码组件的封装实现
2020/02/19 Javascript
nuxt 路由、过渡特效、中间件的实现代码
2020/11/06 Javascript
[01:02:25]2014 DOTA2华西杯精英邀请赛 5 24 iG VS DK
2014/05/26 DOTA
[57:59]完美世界DOTA2联赛循环赛 Ink Ice vs LBZS BO2第一场 11.05
2020/11/05 DOTA
Python完全新手教程
2007/02/08 Python
Python异常学习笔记
2015/02/03 Python
Python 数据结构之旋转链表
2017/02/25 Python
python 内置函数filter
2017/06/01 Python
python如何查看微信消息撤回
2018/11/27 Python
tensor和numpy的互相转换的实现示例
2019/08/02 Python
基于Python解密仿射密码
2019/10/21 Python
如何用H5实现一个触屏版的轮播器的实例
2017/01/09 HTML / CSS
幼儿园小班家长寄语
2014/04/02 职场文书
九一八事变演讲稿范文
2014/09/14 职场文书
先进典型发言材料
2014/12/30 职场文书
小学入学感言
2015/08/01 职场文书