zoukankan      html  css  js  c++  java
  • Python使用pycurl获取http的响应时间

    最近需要对节点到源站自己做个监控,简单的ping可以检测到一些东西,但是http请求的检查也要进行,于是就研究了下pycurl
    pycurl是个用c语言实现的python 库,虽然据说不是那么pythonic,但是却很高效,它支持的协议居多:

    supporting FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE and LDAP. libcurl supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading, kerberos, HTTP form based upload, proxies, cookies, user+password authentication, file transfer resume, http proxy tunneling and more!

    这一堆协议已经很多了,我需要就是http一个,相对urlib来说,这个库可能更快些。

    以下这个脚本是对某一个给定的url进行检查,并打印出http相应码,响应大小,建立连接时间,准备传输时间,传输第一个字节时间,完成时间

    #!/usr/bin/python

    # coding: UTF-8

    import StringIO

    import pycurl

    import sys

    import os

    class Test:

            def __init__(self):

                    self.contents = ''

            def body_callback(self,buf):

                    self.contents = self.contents + buf

    def test_gzip(input_url):

            t = Test()

            #gzip_test = file("gzip_test.txt", 'w')

            c = pycurl.Curl()

            c.setopt(pycurl.WRITEFUNCTION,t.body_callback)

            c.setopt(pycurl.ENCODING, 'gzip')

            c.setopt(pycurl.URL,input_url)

            c.perform()

            http_code = c.getinfo(pycurl.HTTP_CODE)

            http_conn_time =  c.getinfo(pycurl.CONNECT_TIME)

            http_pre_tran =  c.getinfo(pycurl.PRETRANSFER_TIME)

            http_start_tran =  c.getinfo(pycurl.STARTTRANSFER_TIME)

            http_total_time = c.getinfo(pycurl.TOTAL_TIME)

            http_size = c.getinfo(pycurl.SIZE_DOWNLOAD)

            print 'http_code http_size conn_time pre_tran start_tran total_time'

            print "%d %d %f %f %f %f"%(http_code,http_size,http_conn_time,http_pre_tran,http_start_tran,http_total_time)

    if __name__ == '__main__':

            input_url = sys.argv[1]

            test_gzip(input_url)


    脚本运行效果

    xu:~/curl$ python pycurl_test.py http://daxuxu.info/

    http_code http_size conn_time pre_tran start_tran total_time

    200 8703 0.748147 0.748170 1.632642 1.636552

    pycurl 的一些响应信息:
    (参考: http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html )

    pycurl.NAMELOOKUP_TIME 域名解析时间
    pycurl.CONNECT_TIME 远程服务器连接时间
    pycurl.PRETRANSFER_TIME 连接上后到开始传输时的时间
    pycurl.STARTTRANSFER_TIME 接收到第一个字节的时间
    pycurl.TOTAL_TIME 上一请求总的时间
    pycurl.REDIRECT_TIME 如果存在转向的话,花费的时间

    pycurl.EFFECTIVE_URL
    pycurl.HTTP_CODE HTTP 响应代码
    pycurl.REDIRECT_COUNT 重定向的次数
    pycurl.SIZE_UPLOAD 上传的数据大小
    pycurl.SIZE_DOWNLOAD 下载的数据大小
    pycurl.SPEED_UPLOAD 上传速度
    pycurl.HEADER_SIZE 头部大小
    pycurl.REQUEST_SIZE 请求大小
    pycurl.CONTENT_LENGTH_DOWNLOAD 下载内容长度
    pycurl.CONTENT_LENGTH_UPLOAD 上传内容长度
    pycurl.CONTENT_TYPE 内容的类型
    pycurl.RESPONSE_CODE 响应代码
    pycurl.SPEED_DOWNLOAD 下载速度
    pycurl.SSL_VERIFYRESULT
    pycurl.INFO_FILETIME 文件的时间信息

    pycurl.HTTP_CONNECTCODE HTTP 连接代码
    pycurl.HTTPAUTH_AVAIL
    pycurl.PROXYAUTH_AVAIL
    pycurl.OS_ERRNO
    pycurl.NUM_CONNECTS
    pycurl.SSL_ENGINES
    pycurl.INFO_COOKIELIST
    pycurl.LASTSOCKET
    pycurl.FTP_ENTRY_PATH

    ########################################################

    前几天看完《Python简明教程》,预想练手,想起同事的一个 ruby 代码,尝试改写成 python,顺便看看两个语言的简练程度。下面是原始的 ruby 代码:

      #!/usr/bin/env ruby

    require 'rubygems'
    require 'net/http'

    urls = ["http://icyleaf.com"]
    .times do
      urls.each do |url|
        start_at = Time.now
        Net::HTTP.get URI.parse(url)
        end_at = Time.now
        diff = end_at - start_at
        if diff <</span> . then
          color_code =
        elsif diff > . then
          color_code =
        else
          color_code =
        end
        puts "#{url}  time: 33[#{color_code}m#{diff}33[0m seconds"
      end
    end


    改写 python 的同时,考虑脚本的灵活性准备增加两个参数,第一个是请求测试次数,第二个是请求测试的 URL,而 python 默认提供了argparse 库,可以很方便的生成 --help 的帮助和解析传递的参数:

     

    #!/usr/bin/env python

    import urllib2
    import time
    import sys
    import argparse

    def benchmark(url, count):
        for i in range(count):
            s = time.time()
            r = urllib2.urlopen(urllib2.Request(url))
            e = time.time()
            diff = e - s

            if diff <</span> 0.3:
                color_code =
            elif diff > 0.8:
                color_code =
            else:
                color_code =

            print '# %d' % (i + )
            print ' Stauts: %s' % r.getcode()
            print ' Time: 33[%dm%f33[0m second(s)' % (color_code, diff)

    def main(argv):
        parser = argparse.ArgumentParser(description='url request time test')

        parser.add_argument('URL', help='request url')
        parser.add_argument('-t', '--time', action='store', dest='count', type=int, default=, help='request times')
        args = parser.parse_args(argv)

        benchmark(args.URL, args.count)

    if __name__ == '__main__':
        main(sys.argv[:])


    当然,我主要是为了练手 python 才去写的,ruby 本身也有 optparse 库用于解析参数,但是需要自己手写生成 --help 的输出,而且需要对每个参数做相应的 callback。

    效果如下:

    Posted by icyleaf on 2012-08-02

    #########################################################

     用Python编一个抓网页的程序是非常快的,下面就是一个例子:

     

    importurllib2

    html=urllib2.urlopen('http://www.server110.com').read()

    但是在实际工作中,这种写法是远远不够的,至少会遇到下面几个问题:

    网络会出错,任何错误都可能。例如机器宕了,网线断了,域名出错了,网络超时了,页面没有了,网站跳转了,服务被禁了,主机负载不够了…

    服务器加上了限制,只让常见浏览器访问

    服务器加上了防盗链的限制

    某些2B网站不管你HTTP请求里有没有Accept-Encoding头部,也不管你头部具体内容是什么,反正总给你发gzip后的内容

    URL链接千奇百怪,带汉字的也罢了,有的甚至还有回车换行

    某些网站HTTP头部里有一个Content-Type,网页里有好几个Content-Type,更过分的是,各个Content-Type还不一样,最过分的是,这些Content-Type可能都不是正文里使用的Content-Type,从而导致乱码

    网络链接很慢,乘分析几千个页面的时间,建议你可以好好吃顿饭去了

    Python本身的接口有点糙

    好吧,这么一大箩筐问题,我们来一个个搞定。

    错误处理和服务器限制

    首先是错误处理。由于urlopen本身将大部分错误,甚至包括4XX和5XX的HTTP响应,也搞成了异常,因此我们只需要捕捉异常就好了。同时,我们也可以获取urlopen返回的响应对象,读取它的HTTP状态码。除此之外,我们在urlopen的时候,也需要设置timeout参数,以保证处理好超时。下面是代码示例:

    importurllib2

    importsocket

    try:

      f=urllib2.urlopen('http://www.server110.com',timeout=10)

      code=f.getcode()

      ifcode<</span>200orcode>=300:

        #你自己的HTTP错误处理

    exceptException,e:

      ifisinstance(e,urllib2.HTTPError):

        print'http error: {0}'.format(e.code)

      elifisinstance(e,urllib2.URLError)andisinstance(e.reason,socket.timeout):

        print'url error: socket timeout {0}'.format(e.__str__())

      else:

        print'misc error: '+e.__str__()

    如果是服务器的限制,一般来说我们都可以通过查看真实浏览器的请求来设置对应的HTTP头部,例如针对浏览器的限制我们可以设置User-Agent头部,针对防盗链限制,我们可以设置Referer头部,下面是示例代码:

     

    importurllib2

    req=urllib2.Request('http://www.server110.com',

      headers={"Referer":"http://www.baidu.com",

        "User-Agent":"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24"

    })

    html=urllib2.urlopen(url=req,timeout=10).read()

    有的网站用了Cookie来限制,主要是涉及到登录和限流,这时候没有什么通用的方法,只能看能否做自动登录或者分析Cookie的问题了。

    URL与内容处理

    URL里奇形怪状的格式只能个别分析,个别处理,逮到一个算一个。例如针对URL里可能有汉字,相对路径,以及回车换行之类的问题,我们可以先用urlparse模块的urljoin函数处理相对路径的问题,然后去掉乱七八糟的回车换行之类的玩意,最后用urllib2的quote函数处理特殊字符编码和转义的问题,生成真正的URL。

    当然,在使用的过程中你会发现Python的urljoin和urlopen都有些问题,因此具体的代码我们在后面再给。

    对于那些不管三七二十一就把gzip内容丢过来的,我们直接分析它的内容格式,不要管HTTP头部就好了。代码是这样的:

     

    importurllib2

    importgzip,cStringIO

    html=urllib2.urlopen('http://www.server110.com').read()

    ifhtml[:6]=='x1fx8bx08x00x00x00':

      html=gzip.GzipFile(fileobj=cStringIO.StringIO(html)).read()

  • 相关阅读:
    【spring配置】——spring整合Quartz定时器
    Dubbo服务集群,常见容错机制:failover ,failsafe,failfase ,failback,forking
    dubbo 配置文件详解
    Windows 下Nexus搭建Maven私服
    linux下配置java环境
    nexus-2.11.4-01-bundle.tar.gz 下载地址
    XShell 连接 vm虚拟机中的redhat Linux系统
    APIO 2017 游记
    洛谷 P3128 [USACO15DEC]最大流Max Flow
    洛谷 P1197 BZOJ 1015 [JSOI2008]星球大战 (ZOJ 3261 Connections in Galaxy War)
  • 原文地址:https://www.cnblogs.com/shijiaoyun/p/4527373.html
Copyright © 2011-2022 走看看