python|获取接口请求耗时

简介: python|获取接口请求耗时

image.png

你想知道我们请求一个url的时候,握手和请求资源分别占用多长时间么?今天我们使用python写个小案例来看看吧。

import socket
import time
def funcRunTimes(func):
    def wrapper(*args):
        startTime = time.time()
        result = func(*args)
        endTime = time.time()
        execTime = endTime - startTime
        return (result,execTime)
    return wrapper
@funcRunTimes
def shakeHands(hosts,port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect((hosts, port))
        return s
    except Exception as e:
        print(e)
        return None
@funcRunTimes
def websiteResponseTime(fd,methods,url):
    sendMsgs = "%s %s HTTP/1.1\r\nHost: 127.0.0.1:8080\r\n\r\n" %(methods,url)
    fd.send(sendMsgs.encode())
    recv_data = ""
    while True:
        recv_data = str(fd.recv(15))
        break
    httpCode = recv_data.split(" ")[1]
    return httpCode
def main():
    hosts = "www.juejin.cn"
    port = 80
    methods = "GET"
    url = "/"
    print("执行命令为: %s %s:%d %s\n" % (methods, hosts, port, url))
    shakeInfo = shakeHands(hosts,port)
    if shakeInfo == None:
      print("errors")
      return
    responseInfo = websiteResponseTime(shakeInfo[0],methods,url)
    print("接口状态码为:" , responseInfo[0],"握手耗时: %.6fs" %(shakeInfo[1]) , "请求接口耗时: %.6fs" %(responseInfo[1]) ,"总共耗时为: %.6fs" % (shakeInfo[1] + responseInfo[1]))
if __name__ == '__main__':
    main()


项目中使用了python装饰器,若还对python装饰器不太了解的小伙伴,可以参考一下下面这篇文章:

python | 探寻python装饰器: juejin.cn/post/722093…




项目展示


打开项目,修改hostsportmethods以及url的变量,即可运行python程序便可获得该页面的详细信息的时间,其中包括TCP/IP三次握手时间 以及 请求接口耗时,最后是 总的耗时,

image.png


如何获得握手时间

在获取握手时间的时候,不能使用http库,例如: requests,因为它默认会进行tcp/ip三次握手,而后再进行资源请求,所以我们要使用socket来做这个需求。

python中,socket提供了一种跨平台的网络通信接口,可以用它来创建各种类型的网络连接。

例如代码如下:


import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8080))

在上面的代码中,我们先导入socket库,而后使用socket.socket()创建一个socket句柄,而中间的参数分别代表的意思为:

  • socket.AF_INET: 指定IPv4协议。
  • socket.SOCK_STREAM: 指定使用TCP流式套接字类型。

s.connect则开始连接服务器,其参数类型为元组类型,参数值为远程主机名 和 远程端口。


如上代码,当远程服务器连不上的时候或者其他异常的时候,该代码会抛异常,若没有异常,则证明端口通的。


我们仅需要在此之前和之后,都拉一下当前时间戳,就可以计算出握手所耗费的时间,例如:


import socket
import time
try:
    startTime = time.time()
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('127.0.0.1', 8080))
    endTime = time.time()
    print("runtimes: " , endTime-startTime)
except Exception as e:
    print("捕获异常" , e)

若没有抛错,我们即可获得握手时间。



如何获得请求时间


握手成功后,我们就可以向该服务器发送http报文了,注意最简单报文的格式是:

请求方法 请求路由 版本号

请求头(主机名)

空行


例如:

GET / HTTP/1.1
Host: 127.0.0.1:8080


如果我们不添加Host请求头,则会抛错: HTTP/1.1 400 Bad Request: missing required Host header


python中,我们直接使用s.send()函数即可发送请求,例如:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8080))
s.send(b"GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\n\r\n")

上述代码中,\r\n是换行的意思,也称之为CRLF,注意最后的2个\r\n是有一个空行,来标志http请求头的结束。


一般来说,我们请求接口后,会读取服务器返回来的状态码,以便开发验证是否是成功的。


这里可以使用s.recv()函数来读取服务器传回来的信息,例如读取从服务器返回的15个字节s.recv(15)

我们可以参考计算握手时间的方法,来计算一下资源请求的时间,代码如下:

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8080))
startTime = time.time()
s.send(b"GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\n\r\n")
recv_data = str(s.recv(15))
endTime = time.time()
print("runtimes: ", endTime - startTime,"接口返回状态码: " , recv_data.split(" ")[1])



如果远程主机和远程端口都正常的话,我们大概会得到如下的信息:

image.png


善用装饰器


我们计算握手时间,和计算资源请求时间,都是相同的代码,因为计算的功能不同,所以我们需要被迫写2次,这个时候,就可以使用装饰器,来把这个额外非核心功能给抽离出来,而将计算握手和计算资源请求都给封装为函数,而后通过函数来调用装饰器,就可以获取2种请求时间了。


我们先将装饰器抽离出来:

def funcRunTimes(func):
    def wrapper(*args):
        startTime = time.time()
        result = func(*args)
        endTime = time.time()
        execTime = endTime - startTime
        return (result,execTime)
    return wrapper



我们在funcRunTimes中直接返回wrapper函数,而在wrapper函数中,定义开始时间和结束时间,在二者的中间执行函数func,最后将func的结果以及函数执行的时间封装为一个元组进行返回。


此时,我们可以封装函数了,例如我们想获取握手的时间,我们可以这样写:

@funcRunTimes
def shakeHands(hosts,port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect((hosts, port))
        return s
    except Exception as e:
        print(e)
        return None


如果该远程主机可以连上,我们直接返回socket句柄,若连接不上,直接打印错误,返回None

调用该函数的是,我们接收返回值即可:

shakeInfo = shakeHands(hosts,port)

注意,shakeInfo是一个元组,有2个元组,第一个是socket句柄,第二个是执行该函数所需要的时间。

我们再将资源请求函数封装一下,就可以完成这个项目了。



总结


我们使用python socket连接服务器,以及发送http报文,再计算2个函数所执行的时间,便可以获取到握手和资源请求的时间了,最后再将获取时间的函数提取出来,封装为装饰器,供函数调用,即可得到函数的执行时间了。


相关文章
|
2月前
|
C语言 Python
python 调用c接口
【10月更文挑战第12天】 ctypes是Python的一个外部库,提供和C语言兼容的数据类型,可以很方便地调用C DLL中的函数
55 0
|
10天前
|
数据采集 存储 XML
Python爬虫:深入探索1688关键词接口获取之道
在数字化经济中,数据尤其在电商领域的价值日益凸显。1688作为中国领先的B2B平台,其关键词接口对商家至关重要。本文介绍如何通过Python爬虫技术,合法合规地获取1688关键词接口,助力商家洞察市场趋势,优化营销策略。
|
11天前
|
JSON 安全 API
Python调用API接口的方法
Python调用API接口的方法
53 5
|
10天前
|
数据采集 JSON 测试技术
Grequests,非常 Nice 的 Python 异步 HTTP 请求神器
在Python开发中,处理HTTP请求至关重要。`grequests`库基于`requests`,支持异步请求,通过`gevent`实现并发,提高性能。本文介绍了`grequests`的安装、基本与高级功能,如GET/POST请求、并发控制等,并探讨其在实际项目中的应用。
20 3
|
2月前
|
数据采集 前端开发 算法
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
本文介绍了如何使用 Python 的 `requests` 库应对复杂的 HTTP 请求场景,包括 Spider Trap(蜘蛛陷阱)、SESSION 访问限制和请求频率限制。通过代理、CSS 类链接数控制、多账号切换和限流算法等技术手段,提高爬虫的稳定性和效率,增强在反爬虫环境中的生存能力。文中提供了详细的代码示例,帮助读者掌握这些高级用法。
106 1
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
|
26天前
|
JSON API 数据格式
Python中获取HTTP请求响应体的详解
本文介绍了如何使用Python的`requests`和`urllib`库发送HTTP请求并处理响应体。`requests`库简化了HTTP请求过程,适合快速开发;`urllib`库则更为底层,适用于性能要求较高的场景。文章详细演示了发送GET请求、处理JSON响应等常见操作。
39 3
|
2月前
|
JSON 缓存 API
在 Python 中使用公共类处理接口请求的响应结果
在 Python 中使用公共类处理接口请求的响应结果
36 1
|
3月前
|
JSON API 数据格式
使用Python发送包含复杂JSON结构的POST请求
使用Python发送包含复杂JSON结构的POST请求
|
3月前
|
安全 API 开发者
Web 开发新风尚!Python RESTful API 设计与实现,让你的接口更懂开发者心!
在当前的Web开发中,Python因能构建高效简洁的RESTful API而备受青睐,大大提升了开发效率和用户体验。本文将介绍RESTful API的基本原则及其在Python中的实现方法。以Flask为例,演示了如何通过不同的HTTP方法(如GET、POST、PUT、DELETE)来创建、读取、更新和删除用户信息。此示例还包括了基本的路由设置及操作,为开发者提供了清晰的API交互指南。
112 6
|
3月前
|
Java Python
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
【9月更文挑战第18天】在 Python 中,虽无明确的 `interface` 关键字,但可通过约定实现类似功能。接口主要规定了需实现的方法,不提供具体实现。抽象基类(ABC)则通过 `@abstractmethod` 装饰器定义抽象方法,子类必须实现这些方法。使用抽象基类可使继承结构更清晰、规范,并确保子类遵循指定的方法实现。然而,其使用应根据实际需求决定,避免过度设计导致代码复杂。