利用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 相关文章推荐
Python3基础之函数用法
Aug 13 Python
python中__call__方法示例分析
Oct 11 Python
Python实现在Linux系统下更改当前进程运行用户
Feb 04 Python
详解python 字符串和日期之间转换 StringAndDate
May 04 Python
基于Python3.6+splinter实现自动抢火车票
Sep 25 Python
Python检查ping终端的方法
Jan 26 Python
把pandas转换int型为str型的方法
Jan 29 Python
将pip源更换到国内镜像的详细步骤
Apr 07 Python
python下的opencv画矩形和文字注释的实现方法
Jul 09 Python
pytorch加载自定义网络权重的实现
Jan 07 Python
Python替换NumPy数组中大于某个值的所有元素实例
Jun 08 Python
python状态机transitions库详解
Jun 02 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
新的一年,新的期待:DC在2020年的四部动画电影
2020/01/01 欧美动漫
PHP的FTP学习(三)
2006/10/09 PHP
php创建基本身份认证站点的方法详解
2013/06/08 PHP
php批量更改数据库表前缀实现方法
2013/10/26 PHP
PHP实现简单注册登录系统
2020/12/28 PHP
File, FileReader 和 Ajax 文件上传实例分析(php)
2011/04/27 Javascript
给Flash加一个超链接(推荐使用透明层)兼容主流浏览器
2013/06/09 Javascript
ActiveX控件与Javascript之间的交互示例
2014/06/04 Javascript
node.js中的fs.writeFile方法使用说明
2014/12/14 Javascript
使用jquery实现仿百度自动补全特效
2015/07/23 Javascript
JQuery菜单效果的两个实例讲解(3)
2015/09/17 Javascript
JavaScript地理位置信息API
2016/06/11 Javascript
Three.js学习之网格
2016/08/10 Javascript
从零学习node.js之搭建http服务器(二)
2017/02/21 Javascript
jquery mobile实现可折叠的导航按钮
2017/03/11 Javascript
微信小程序联网请求的轮播图
2017/07/07 Javascript
简化vuex的状态管理方案的方法
2018/06/02 Javascript
vue组件间通信六种方式(总结篇)
2019/05/15 Javascript
Servlet返回的数据js解析2种方法
2019/12/12 Javascript
vantUI 获得piker选中值的自定义ID操作
2020/11/04 Javascript
[08:42]DOTA2每周TOP10 精彩击杀集锦vol.2
2014/06/25 DOTA
Python编程实现的图片识别功能示例
2017/08/03 Python
Python使用pickle模块存储数据报错解决示例代码
2018/01/26 Python
django+mysql的使用示例
2018/11/23 Python
Python HTML解析模块HTMLParser用法分析【爬虫工具】
2019/04/05 Python
Python企业编码生成系统之系统主要函数设计详解
2019/07/26 Python
keras实现theano和tensorflow训练的模型相互转换
2020/06/19 Python
北京鼎普科技股份有限公司软件测试面试题
2012/04/07 面试题
公务员职务工作的自我评价
2013/11/01 职场文书
护士上岗前培训自我鉴定
2014/04/20 职场文书
校园环保建议书
2014/05/14 职场文书
领导班子党的群众路线对照检查材料
2014/09/25 职场文书
遗失证明范文
2015/06/19 职场文书
2015年中秋寄语
2015/07/31 职场文书
SQL Server中使用判断语句(IF ELSE/CASE WHEN )案例
2021/07/07 SQL Server
python脚本框架webpy模板赋值实现
2021/11/20 Python