Istnieją doskonałe narzędzia w Bibliotece standardowej zarówno do analizowania nagłówków RFC 821, jak i do analizowania całych żądań HTTP. Oto ciąg przykład żądanie (zauważ, że Python traktuje go jako jeden wielki ciąg, choć jesteśmy zerwania go w kilku liniach, dla czytelności), które możemy nakarmić moich przykładów:
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'
)
Jak @TryPyPy zwraca uwagę, można użyć mimetools.Message
do analizowania nagłówków - choć trzeba dodać, że powstałe Message
obiekt działa jak słownika nagłówkami po zakończeniu jej tworzenia:
# 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"
Ale to, oczywiście, ignoruje linię żądanie lub sprawia, że sam je analizujesz. Okazuje się, że istnieje o wiele lepsze rozwiązanie.
Biblioteka standardowa przeanalizuje dla Ciebie HTTP, jeśli używasz jego BaseHTTPRequestHandler
. Chociaż jego dokumentacja jest nieco niejasna - problem z całym pakietem narzędzi HTTP i adresów URL w Bibliotece standardowej - wszystko, co musisz zrobić, aby sparsować ciąg, to (a) zawinięcie łańcucha znaków w StringIO()
, (b) raw_requestline
, tak aby był gotowy do analizy i (c) przechwytywać wszelkie kody błędów, które występują podczas analizowania, zamiast pozwalać na zapisanie ich z powrotem do klienta (ponieważ nie mamy takiego!).
Więc tutaj jest nasza specjalizacja klasy Biblioteka standardowa:
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
Ponownie życzę ludzie Biblioteka standardowa sobie sprawę, że podczas analizowania HTTP powinny być podzielone w sposób, który nie wymaga od nas, aby napisać dziewięć linie kodu, aby poprawnie go nazwać, ale co możesz zrobić? Oto jak można wykorzystać tę prostą klasę:
# 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"
Jeśli wystąpił błąd podczas parsowania The error_code
nie będzie None
:
# 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')"
wolę korzystania z biblioteki Standardowy tak dlatego podejrzewam że już napotkali i rozwiązali jakieś skrajne przypadki, które mogą mnie ugryźć, jeśli sam spróbuję ponownie wdrożyć specyfikację internetową za pomocą wyrażeń regularnych.
Czy istnieje sposób, aby zrobić to w python3? – Broseph
mimetools jest przestarzałe od 2.3 –
@Broseph Patrz odpowiedź Gowthama. – JeromeJ