利用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入门篇之字典
Oct 17 Python
深入解析Python设计模式编程中建造者模式的使用
Mar 02 Python
python中MethodType方法介绍与使用示例
Aug 03 Python
Python实现重建二叉树的三种方法详解
Jun 23 Python
Python定时任务sched模块用法示例
Jul 16 Python
python使用插值法画出平滑曲线
Dec 15 Python
Python自定义一个异常类的方法
Jun 27 Python
使用 Django Highcharts 实现数据可视化过程解析
Jul 31 Python
Python列表推导式实现代码实例
Sep 09 Python
python Tkinter的简单入门教程
Apr 11 Python
Python中的程序流程控制语句
Feb 24 Python
python数字图像处理之图像自动阈值分割示例
Jun 28 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
重置版宣传动画
2020/04/09 魔兽争霸
Fatal error: session_start(): Failed to initialize storage module: files问题解决方法
2014/05/04 PHP
PHP中if和or运行效率对比
2014/12/12 PHP
php简单生成随机数的方法
2015/07/30 PHP
Yii2 RESTful中api的使用及开发实例详解
2016/07/06 PHP
Javascript学习笔记 delete运算符
2011/09/13 Javascript
js正则表达式的使用详解
2013/07/09 Javascript
解析Javascript中中括号“[]”的多义性
2013/12/03 Javascript
js实现屏幕自适应局部代码分享
2015/01/30 Javascript
js中函数声明与函数表达式
2015/06/03 Javascript
JavaScript截取指定长度字符串点击可以展开全部代码
2015/12/04 Javascript
javascript数组去重小结
2016/03/07 Javascript
JavaScript DOM节点操作方法总结
2016/08/23 Javascript
js 实现一些跨浏览器的事件方法详解及实例
2016/10/27 Javascript
AngularJS自定义插件实现网站用户引导功能示例
2016/11/07 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
2017/01/05 Javascript
JavaScript使用atan2来绘制箭头和曲线的实例
2017/09/14 Javascript
详解Vue SPA项目优化小记
2018/07/03 Javascript
Postman内建变量常用方法实例解析
2020/07/28 Javascript
vue组件添加事件@click.native操作
2020/10/30 Javascript
jquery实现广告上下滚动效果
2021/03/04 jQuery
[02:39]DOTA2国际邀请赛助威团西雅图第一天
2013/08/08 DOTA
[33:23]Secret vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python获取当前时间对应unix时间戳的方法
2015/05/15 Python
python web基础之加载静态文件实例
2018/03/20 Python
对python list 遍历删除的正确方法详解
2018/06/29 Python
Python 3.8新特征之asyncio REPL
2019/05/28 Python
在Pytorch中计算自己模型的FLOPs方式
2019/12/30 Python
深入理解HTML5定时器requestAnimationFrame的使用
2018/12/12 HTML / CSS
ruby如何进行集成操作?Ruby能进行多重继承吗?
2013/10/16 面试题
优秀班主任推荐材料
2014/12/17 职场文书
灵山大佛导游词
2015/02/04 职场文书
餐厅营销的秘密:为什么老顾客会流水?
2019/08/08 职场文书
微信小程序结合ThinkPHP5授权登陆后获取手机号
2021/11/23 PHP
Python必备技巧之字符数据操作详解
2022/03/23 Python
win10识别不了U盘怎么办 win10系统读取U盘失败的解决办法
2022/08/05 数码科技