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}\n time: \033[#{color_code}m#{diff}\033[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 '\tStauts: %s' % r.getcode()
        print '\tTime: \033[%dm%f\033[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]=='\x1f\x8b\x08\x00\x00\x00':

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM