利用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求两个文本文件以行为单位的交集、并集与差集的方法
Jun 17 Python
Python 爬虫之超链接 url中含有中文出错及解决办法
Aug 03 Python
Python实现一个Git日志统计分析的小工具
Dec 14 Python
TensorFlow用expand_dim()来增加维度的方法
Jul 26 Python
Linux下Python安装完成后使用pip命令的详细教程
Nov 22 Python
详解django+django-celery+celery的整合实战
Mar 19 Python
用django-allauth实现第三方登录的示例代码
Jun 24 Python
python requests抓取one推送文字和图片代码实例
Nov 04 Python
python随机生成库faker库api实例详解
Nov 28 Python
PyCharm2020.1.1与Python3.7.7的安装教程图文详解
Aug 07 Python
Python实战之用tkinter库做一个鼠标模拟点击器
Apr 27 Python
Python Pandas 删除列操作
Mar 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
CodeIgniter上传图片成功的全部过程分享
2013/08/12 PHP
php中的登陆login实例代码
2016/06/20 PHP
php 数据结构之链表队列
2017/10/17 PHP
JavaScript高级程序设计(第3版)学习笔记10 再访js对象
2012/10/11 Javascript
js之ActiveX控件使用说明 new ActiveXObject()
2014/03/03 Javascript
jQuery截取指定长度字符串代码
2014/08/21 Javascript
js通过iframe加载外部网页的实现代码
2015/04/05 Javascript
IE6兼容透明背景图片及解决方案
2015/08/19 Javascript
jQuery Validate验证框架经典大全
2015/09/23 Javascript
JS对大量数据进行多重过滤的方法
2016/11/04 Javascript
JavaScript获取服务器端时间的方法
2016/11/29 Javascript
用jQuery旋转插件jqueryrotate制作转盘抽奖
2017/02/10 Javascript
jquery实现tab选项卡切换效果(悬停、下方横线动画位移)
2017/05/05 jQuery
浅谈Angular2 模块懒加载的方法
2017/10/04 Javascript
vue resource post请求时遇到的坑
2017/10/19 Javascript
vue实现个人信息查看和密码修改功能
2018/05/06 Javascript
详解关于微信setData回调函数中的坑
2019/02/18 Javascript
JS合并两个数组的3种方法详解
2019/10/24 Javascript
Vue.js实现可编辑的表格
2019/12/11 Javascript
vue实现自定义多选按钮
2020/07/16 Javascript
JavaScript JSON使用原理及注意事项
2020/07/30 Javascript
[00:26]TI7不朽珍藏III——冥界亚龙不朽展示
2017/07/15 DOTA
python3.5 + PyQt5 +Eric6 实现的一个计算器代码
2017/03/11 Python
浅析Git版本控制器使用
2017/12/10 Python
python实现控制台打印的方法
2019/01/12 Python
Python实现最大子序和的方法示例
2019/07/05 Python
Django自定义模板过滤器和标签的实现方法
2019/08/21 Python
使用CSS3制作响应式导航菜单的方法
2015/07/12 HTML / CSS
美国最灵活的移动提供商:Tello
2017/07/18 全球购物
表彰先进的通报
2014/01/31 职场文书
幼儿园区域活动总结
2014/05/08 职场文书
国际贸易专业求职信
2014/06/04 职场文书
团队口号大全
2014/06/06 职场文书
神龙架导游词
2015/02/11 职场文书
清洁工工作总结
2015/08/11 职场文书
如何正确理解python装饰器
2021/06/15 Python