파이썬 웹 표준 라이브러리

파이썬 웹프로그래밍(한빛출판사) 책의 내용을 정리한 것입니다.

웹 클라이언트 라이브러리

urlparse 모듈

URL 의 분해, 조립, 변경 등 을 처리하는 함수

from urlparse import urlparse  
result = urlparse("http://www.python.org:80/guido/python.html;philosophy?overall=3\n10")  

urllib2 모듈

urlopen 함수

주어진 URL 에서 데이터를 가져오는 기본 기능 제공하며, 형식은 다음과 같다.

urlopen(url, data=None, [timeout])

간단한 요청은 다음과 같이 가능하다.

from urllib2 import urlopen  
data = "query=python"  
f = urlopen("http://www.example.com', data)  
print f.read(300)  

다음과 같이 Request 클래스를 활용하여 헤더를 지정할 수도 있다.

import urllib2  
req = urllib2.Request("http://www.example.com")  
req.add_header("Content-Type", "text/plain")  
req.add_data("query=python")  
f = urllib2.urlopen(req)  
print f.read(300)  

인증 데이터나 쿠키 데이터를 추가하여 요청을 보낼 수 있는데, 이를 위해서는 각 기능에 맞는 핸들러를 정의하고, 그 핸들러를 build_opener() 함수로 오프너를 등록하고, install_opener() 함수를 이용하여 디폴트 오프너로 설정하면 된다. 다음은 HttpBasicAuthHandler 클래스를 이용하여 인증데이터를 보내는 예이다.

import urllib2

auth_handler = urllib2.HTTPBasicAuthHandler()  
auth_handler.add_password(realm='PDQ Application',  
        url='http://mahler:8092/site-updates.py',
        user='klem',
        passwd='kadidd!ehopper')
opener = urllib2.build_opener(auth_handler)

urllib2.install_opener(opener)  
u = urllib2.urlopen("http://www.exmaple.com/login.html")  

HTTPCookieProcessor 클래스를 사용하여 쿠키를 함께 보낼 수도 있다.

import urllib2

cookie_handler = urllib2.HTTPCookieProcessor()

opener = urllib2.build_opener(cookie_handler)  
urllib2.install_opener(opener)  
u = urllib2.urlopen('http://www.example.com/login.html')  

프록시 서버를 통해 http 요청을 보내기 위해서는 ProxyHandlerProxyBasicAuthHandler 클래스를 사용할 수 있다.

import urllib2

proxy_handler = urllib2.ProxyHandler({'http': 'http://www.example.com:3128/'})  
proxy_auth_handler = urllib2.ProxyBasicAuthHandler()  
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')

opener = urllib2.build_opener(proxy_handler, proxy_auth_handler)  
urllib2.install_opener(opener)  
u = opener.open('http://www.example.com/login.html')  

urllib2 모듈 예제

HTMLParser 클래스를 상속 받아 html 에서 img 태그만을 추출하여 정보를 출력하는 예제이다.

from urllib2 import urlopen  
from HTMLParser import HTMLParser

class ImageParser(HTMLParser):  
    def handle_starttag(self, tag, attrs):
        if tag != 'img':
            return
        if not hasattr(self, 'result'):
            self.result = []
        for name, value in attrs:
            if name == 'src':
                self.result.append(value)

def parseImage(data):  
    parser = ImageParser()
    parser.feed(data)
    dataSet = set(x for x in parser.result)
    print '\n'.join(sorted(dataSet))

def main():  
    url = 'http://www.google.co.kr'

    f = urlopen(url)
    charset = f.info().getparam('charset')
    data = f.read().decode(charset)
    f.close()

    print "\n>>>>>>>>>> Fetch Images from", url
    parseImage(data)

if __name__ == '__main__':  
    main()

결과는 다음과 같다.

httplib 모듈

HTTP 프로토콜 요청에 대한 저수준의 더 세밀한 기능이 필요할 때 사용할 수 있다.

  • httplib 모듈 사용 순서
    • 연결 객체 생성
    • 요청 전송
      • request(method, url, body, headers) 형식
    • 응답 객체 생성
    • 응답 데이터 읽음
    • 연결 닫음

GET 방식 요청의 경우는 다음과 같이 구현할 수 있다.

import httplib  
// 연결 객체 생성
conn = httplib.HTTPConnection("www.example.com")  
// 요청 전송
conn.request("GET", '/index.html')  
// 응답 객체 생성
r1 = conn.getresponse()  
// 응답 데이터 읽음
data1 = r1.read()  
// 연결 닫음
conn.close()  

하나의 연결 객체를 이용하여 여러 번의 request 를 하기 위해선 이 전의 request 에 대한 응답을 모두 읽어야 가능하다.

POST 메소드로 요청은 아래와 같은 코드로 구현할 수 있다.

import httplib, urllib  
params = urllib.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'})  
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}  
conn = httplib.HTTPConnection("bugs.python.org")  
conn.request("POST", "", params, headers)  
response = conn.getresponse()  
data = response.read()  
conn.close()  

다음은 PUT 메소드로 요청을 보내는 예이다.

import httplib  
body = "*****filecontents*****"  
conn = httplib.HTTPConnection("localhost", 8888)  
conn.request("PUT", "/file", body)  
response = conn.getresponse()  

웹 서버 라이브러리

웹 서버를 만드는 가장 기본적인 방법

  • BaseHTTPServer 모듈을 import 한다.
  • BaseHTTPRequestHandler를 상속받아 원하는 로직으로 핸들러 클래스를 정의한다.
  • 서버의 ip, port 및 핸들러 클래스를 인자로 하여 HTTPServer 객체를 생성한다.
  • HTTPServer 객체의 serve_forever() 메소드를 호출한다.

BaseHTTPServer 모듈

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

class MyHandler(BaseHTTPRequestHandler):  
    def do_GET(self):
        self.wfile.write("Hello World")

if __name__ == '__main__':  
    server = HTTPServer(('', 8888), MyHandler)
    print 'Started WebServer on port 8888...'
    print 'Press ^C to quit WebServer'
    server.serve_forever()

SimpleHTTPServer 모듈

간단한 핸들러(SimpleHTTPRequestHandler)가 미리 구현되어 있어 필요할 때 즉시 웹 서버를 실행할 수 있다.
SimpleHTTPRequestHandler 는 do_GET(), do_HEAD() 메소드가 정의되어 있어서 GET 및 HEAD 방식을 처리할 수 있다.

$ python -m SimpleHTTPServer 8888

CGIHTTPServer 모듈

CGIHTTPServer 모듈에는 CGIHTTPRequestHandler 가 미리 정의되어 있고, 이는 do_POST() 메소드가 정의되어 있어 POST 방식을 처리할 수 있다. 또한, SimpleHTTPRequestHandler 를 상속받고 있어서 GET, HEAD 방식 역시 처리 가능하다.

xxxHTTPServer 모듈간의 관계

이 한 장의 그림으로 모든걸 설명할 수 있음.

CGI/WSGI 라이브러리

WSGI(Web Server Gateway Interface): 웹 서버와 웹 애플리케이션을 연결해주는 규격

웹 프레임워크와 아파치와 같은 웹 서버와의 연동을 위해 사용.

CGI 관련 모듈

웹 서버와 웹 어플리케이션 간의 데이터를 주고 받기 위한 규격

  • CGIHTTPServer 모듈
  • cgi 모듈: http 요청에 포함된 파라미터를 처리하기 위한 FieldStorage 클래스를 정의
  • cgitb 모듈: CGI 어플리케이션 실행 중 오류 발생 시 관련 정보를 브라우저에 표시

WSGI 개요

웹 서버와 웹 어플리케이션의 연동을 위해 웹 프레임워크가 사용하는 규격.

WSGI 서버의 어플리케이션 처리 과정

  1. Request (@웹 서버)
  2. Request의 URL 분석 (@웹 서버)
  3. WSGIScriptAlias 에 정의된 URL 이면, WSGI 서버에 처리 위임 (@웹 서버)
  4. 파라미터 전달
  5. WSGIScriptAlias 에 정의된 wsgi.py 실행 (@WSGI 서버)
  6. application(eviron, start_response) 함수 호출 (@WSGI 서버)
  7. call
  8. environ 환경변수 처리 (@application)
  9. 뷰 처리, HTTPRequest 객체 생성 (@application)
  10. start_response() 함수 호출 (@application)
  11. return HTTPResponse (@application)
  12. return
  13. 표준 출력에 결과 출력 (@WSGI 서버)
  14. 처리 결과
  15. Response (@웹 서버)

wsgiref.simple_server 모듈

def my_app(environ, start_response):  
    status = "200 OK"
    headers = [('Content-Type', 'text/plain')]
    start_response(status, headers)
    return ["This is a sample WSGI Application."]

if __name__ == '__main__':  
    from wsgiref.simple_server import make_server

    print "Started WSGI Server on port 8888..."
    server = make_server('', 8888, my_app)
    server.serve_forever()

위 코드는 wsgiref.simple_server 모듈을 이용한 간단한 WSGI 서버를 만드는 예이다.

  • 예제에서 보듯 make_server()를 호출할 때 my_app() 과 같은 호출 가능한 함수나 메소드를 인자로 넘겨주어야 한다. 이는 어플리케이션 프로그램과 웹 서버 프로그램을 독립적으로 작성할 수 있게 해주는 WSGI 규격의 중요한 원칙에 해당한다.
  • my_app() 함수는 WSGI 규격을 준수하는 어플리케이션 코드이다.