2011-01-13 26 views
26

私は生のHTTPの文字列を持っています。オブジェクトのフィールドを表現したいと思います。 HTTP文字列から個々のヘッダーを解析する方法はありますか?生のHTTPヘッダーを解析します。

'GET /search?sourceid=chrome&ie=UTF-8&q=ergterst HTTP/1.1\r\nHost: www.google.com\r\nConnection: keep-alive\r\nAccept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.45 Safari/534.13\r\nAccept-Encoding: gzip,deflate,sdch\r\nAvail-Dictionary: GeNLY2f-\r\nAccept-Language: en-US,en;q=0.8\r\n 
[...]' 

答えて

7

これは、あなたがGET行を取り除く場合は正常に動作するようです:あなたの例を解析し、オブジェクトに最初の行からの情報を追加するための

import mimetools 
from StringIO import StringIO 

he = "Host: www.google.com\r\nConnection: keep-alive\r\nAccept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.45 Safari/534.13\r\nAccept-Encoding: gzip,deflate,sdch\r\nAvail-Dictionary: GeNLY2f-\r\nAccept-Language: en-US,en;q=0.8\r\n" 

m = mimetools.Message(StringIO(he)) 

print m.headers 

の方法は、次のようになります。

import mimetools 
from StringIO import StringIO 

he = 'GET /search?sourceid=chrome&ie=UTF-8&q=ergterst HTTP/1.1\r\nHost: www.google.com\r\nConnection: keep-alive\r\n' 

# Pop the first line for further processing 
request, he = he.split('\r\n', 1)  

# Get the headers 
m = mimetools.Message(StringIO(he)) 

# Add request information 
m.dict['method'], m.dict['path'], m.dict['http-version'] = request.split()  

print m['method'], m['path'], m['http-version'] 
print m['Connection'] 
print m.headers 
print m.dict 
+0

ありますか? – Broseph

+0

mimetoolsは2以降廃止予定です。3 –

+0

@Broseph Gowthamの答えを参照してください。 – JeromeJ

72

標準ライブラリには、RFC 821ヘッダーの解析と、HTTP要求全体の解析用に優れたツールがあります。 @TryPyPyが指摘するように、

request_text = (
    'GET /who/ken/trust.html HTTP/1.1\r\n' 
    'Host: cm.bell-labs.com\r\n' 
    'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n' 
    'Accept: text/html;q=0.9,text/plain\r\n' 
    '\r\n' 
    ) 

:ここでは、私の例に送り込むことができ、例えば要求文字列(Pythonは、我々は、読みやすくするために、いくつかのラインを渡ってそれを壊しているにもかかわらず、一つの大きな文字列として扱うことに注意してください)ですあなたは、ヘッダーを解析するmimetools.Messageを使用することができます - 私たちは、あなたがそれを作成完了したら結果Messageオブジェクトは、ヘッダーの辞書のように作用することを追加する必要がありますけれども:

# Ignore the request line and parse only the headers 

from mimetools import Message 
from StringIO import StringIO 
request_line, headers_alone = request_text.split('\r\n', 1) 
headers = Message(StringIO(headers_alone)) 

print len(headers)  # -> "3" 
print headers.keys() # -> ['accept-charset', 'host', 'accept'] 
print headers['Host'] # -> "cm.bell-labs.com" 

しかし、これを、当然のことながら、要求ラインを無視しますか、あなた自身でそれを解析します。はるかに良い解決策があることが判明しました。

標準ライブラリは、BaseHTTPRequestHandlerを使用すると、HTTPを解析します。標準ライブラリのHTTPツールとURLツールのすべての問題は、文字列を解析するために必要な作業は、(a)文字列をStringIO()にラップし、(b) raw_requestlineを解析する準備が整うようにしてください。(c)パース中に発生したエラーコードをキャプチャするのではなく、クライアントに書き戻すのではなくキャプチャします。だからここ

は、標準ライブラリのクラスの私達の専門である:

再び
from BaseHTTPServer import BaseHTTPRequestHandler 
from StringIO import StringIO 

class HTTPRequest(BaseHTTPRequestHandler): 
    def __init__(self, request_text): 
     self.rfile = StringIO(request_text) 
     self.raw_requestline = self.rfile.readline() 
     self.error_code = self.error_message = None 
     self.parse_request() 

    def send_error(self, code, message): 
     self.error_code = code 
     self.error_message = message 

、私は標準ライブラリの人々は、HTTP解析が9を書くために私たちを必要としないようにして破られるべきであることを認識していた希望します適切に呼び出すためのコード行はありますが、何ができますか?ここでは、この単純なクラスを使用する方法である:

# Using this new class is really easy! 

request = HTTPRequest(request_text) 

print request.error_code  # None (check this first) 
print request.command   # "GET" 
print request.path    # "/who/ken/trust.html" 
print request.request_version # "HTTP/1.1" 
print len(request.headers)  # 3 
print request.headers.keys() # ['accept-charset', 'host', 'accept'] 
print request.headers['host'] # "cm.bell-labs.com" 

エラーが解析中に存在する場合、error_codeNoneではありません。

# Parsing can result in an error code and message 

request = HTTPRequest('GET\r\nHeader: Value\r\n\r\n') 

print request.error_code  # 400 
print request.error_message # "Bad request syntax ('GET')" 

私が疑うので、私はこのような標準ライブラリを使用して好みます彼らはすでに遭遇し、正規表現で自分自身でインターネット仕様を再実装しようとすると、私を噛んでしまう可能性のあるあらゆる場合を解決しました。

+0

これは素晴らしい、ありがとう!しかし、私はHTTPヘッダー情報の順序を維持する必要があります(辞書は順序を維持しません)。これを行うためにとにかくありますか? – jeffrey

+1

わかりません! Pythonがこの構文解析を行うために使用する 'Message'と要求クラスの深部は、ヘッダーの辞書を作成するコード行であるべきです。代わりに単純な 'dict'の代わりに' OrderedDict'を使うと言えば、順序を知ることができますが、コードを少しだけ見ただけで、ヘッダ辞書の作成場所を知ることができませんでした。 –

7

mimetoolsは、Python 2.3から廃止され、Python 3(link)から完全に削除されました。ここで

は、あなたは、Python 3で行うべきかです:のpython3でこれを行う方法は

import email 
import io 
import pprint 

# […] 

request_line, headers_alone = request_text.split('\r\n', 1) 
message = email.message_from_file(io.StringIO(headers_alone)) 
headers = dict(message.items()) 
pprint.pprint(headers, width=160) 
+0

'email.message_from_file(io.StringIO(headers_alone))'は 'email.message_from_string(headers_alone)'に置き換えることができます。 – eigenein

関連する問題