利用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让图片按照exif信息里的创建时间进行排序的方法
Mar 16 Python
使用基于Python的Tornado框架的HTTP客户端的教程
Apr 24 Python
Python2.7简单连接与操作MySQL的方法
Apr 27 Python
Python探索之自定义实现线程池
Oct 27 Python
Python使用smtp和pop简单收发邮件完整实例
Jan 09 Python
Python实现XML文件解析的示例代码
Feb 05 Python
python实现淘宝秒杀聚划算抢购自动提醒源码
Jun 23 Python
python实现图书馆研习室自动预约功能
Apr 27 Python
python读取.mat文件的数据及实例代码
Jul 12 Python
基于Python新建用户并产生随机密码过程解析
Oct 08 Python
Python pymsql模块的使用
Sep 07 Python
利用django创建一个简易的博客网站的示例
Sep 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
php下intval()和(int)转换使用与区别
2008/07/18 PHP
mysql总结之explain
2012/02/27 PHP
PHP中比较两个字符串找出第一个不同字符位置例子
2014/04/08 PHP
JQuery打造PHP的AJAX表单提交实例
2009/11/03 Javascript
改变javascript函数内部this指针指向的三种方法
2010/04/23 Javascript
js显示时间 js显示最后修改时间
2013/01/02 Javascript
详解参数传递四种形式
2015/07/21 Javascript
JS实现字符串转日期并比较大小实例分析
2015/12/09 Javascript
JS公共小方法之判断对象是否为domElement的实例
2016/11/25 Javascript
简单实现js倒计时功能
2017/02/13 Javascript
jQuery插件HighCharts实现2D柱状图、折线图的组合多轴图效果示例【附demo源码下载】
2017/03/09 Javascript
js利用for in循环获取 一个对象的所有属性以及值的实例
2017/03/30 Javascript
基于JavaScript中字符串的match与replace方法(详解)
2017/12/04 Javascript
在Vue组件中使用 TypeScript的方法
2018/02/28 Javascript
webpack本地开发环境无法用IP访问的解决方法
2018/03/20 Javascript
Node.js事件的正确使用方法
2019/04/05 Javascript
Vue.js页面中有多个input搜索框如何实现防抖操作
2019/11/04 Javascript
vue 实现v-for循环回来的数据动态绑定id
2019/11/07 Javascript
Javascript实现鼠标移入方向感知
2020/06/24 Javascript
[01:01:52]DOTA2-DPC中国联赛定级赛 SAG vs iG BO3第二场 1月9日
2021/03/11 DOTA
Python判断直线和矩形是否相交的方法
2015/07/14 Python
Python的socket模块源码中的一些实现要点分析
2016/06/06 Python
对于Python中RawString的理解介绍
2016/07/07 Python
python pands实现execl转csv 并修改csv指定列的方法
2018/12/12 Python
在Python 中实现图片加框和加字的方法
2019/01/26 Python
tesserocr与pytesseract模块的使用方法解析
2019/08/30 Python
python FTP编程基础入门
2021/02/27 Python
荷兰皇家航空公司中国官网:KLM中国
2017/12/13 全球购物
英国最受欢迎的价格比较网站之一:MoneySuperMarket
2018/12/19 全球购物
EJB需直接实现它的业务接口或Home接口吗,请简述理由
2016/11/23 面试题
三分钟演讲稿事例
2014/03/03 职场文书
最美家庭活动方案
2014/08/31 职场文书
小学趣味运动会加油稿
2014/09/25 职场文书
房屋分割离婚协议书范本
2014/12/01 职场文书
英语感谢信范文
2015/01/20 职场文书
56句经典英文座右铭
2019/08/09 职场文书