본문 바로가기
  • 실행력이 모든걸 결정한다
Python

[Python] 파이썬 웹 표준 라이브러리

by 김코더 김주역 2023. 1. 19.
반응형

이 포스팅은 파이썬 3.x 버전을 기준으로 설명한다.

 

1. 웹 라이브러리 구성

- urllib 패키지는 웹 클라이언트를 작성하는 데 사용되는 모듈을 담고 있다.

- http 패키지는 서버용과 클라이언트용 라이브러리로 나누어 모듈을 담고 있다.

 

 

 

2. 웹 클라이언트 라이브러리

1) urllib.parse

urllib.parse 모듈은 URL의 분해, 조립, 변경, 문자 인코딩 및 디코딩을 처리하는 함수를 제공한다.

 

[주요 함수]

urlparse()

- URL을 파싱한 결과로 ParseResult 객체를 반환한다.

from urllib.parse import urlparse
print(urlparse("https://www.example.com/guide/1?ie=utf8&page=3#memo_1"))
# ParseResult(scheme='https', netloc='www.example.com', path='/guide/1', params='', query='ie=utf8&page=3', fragment='memo_1')

 

 

2) urllib.request

urllib.request 모듈은 주어진 URL 요청으로부터 데이터를 가져오는 기능을 제공한다.

 

[주요 함수]

urlopen()

- URL 요청을 수행하고 http.client.HTTPResponse 객체를 반환한다.

- 기본적으로 GET 방식을 사용한다.

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

※ url : 문자열 또는 urllib.request.Request 객체가 올 수 있다. 헤더 조작이 필요하다면 Request 객체를 만들어서 넣으면 된다.

※ data : POST 방식으로 요청을 보낼 때 바이트 스트링 형식의 query string을 넣는 곳이다. data 인자가 지정되면 자동으로 POST 방식을 사용한다.
※ timeout : 타임아웃 시간을 초 단위로 표시한다.

 

# 예시 1 ) 단순한 POST 방식의 요청
f=urlopen("http://www.example.com", bytes("ie=utf8&page=3", encoding='utf-8'))

 

# 예시 2) Request 객체로 요청 헤더 지정
from urllib.request import urlopen, Request
from urllib.parse import urlencode

url="https://www.example.com"
data={'name':'김주역', 'age':26}
encData=urlencode(data)
postData=bytes(encData, encoding='utf-8')
req=Request(url, data=postData)
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
f=urlopen(req)

 

build_opener()

- 오프너에 HTTP의 특정 고급 기능에 맞는 핸들러 객체를 등록하고, urllib.request.OpenerDirector 객체를 반환한다.

- 인증 데이터나 쿠키 데이터를 추가하여 요청을 보내거나, 프록시 서버로 요청을 보낼 때 사용할 수 있다.

# 예시 3) 인증 데이터 전송
from urllib.request import HTTPBasicAuthHandler, build_opener

auth_uri='https://www.example.com/auth/'
auth_handler = HTTPBasicAuthHandler()
auth_handler.add_password(realm='kjy', user='jykim', passwd='0703', uri=auth_uri)
opener=build_opener(auth_handler)
response=opener.open(auth_uri) # http.client.HTTPResponse 객체 반환

※ urllib.request.OpenerDirector의 open() 메소드의 인자에 문자열 외에도 urllib.request.Request 객체가 올 수 있다.

 

# 예시 4) 쿠키 데이터 전송
from urllib.request import Request, HTTPCookieProcessor, build_opener

url='https://www.example.com/cookie/'
cookie_handler=HTTPCookieProcessor()
opener=build_opener(cookie_handler)
req=Request(url)
response=opener.open(req)

 

# 예시 5) 프록시 서버를 통해 웹 서버로 요청을 전송
from urllib.request import ProxyHandler, ProxyBasicAuthHandler, build_opener, install_opener, urlopen

url='https://www.example.com'
proxyServer='https://www.proxy.com:7999/'
proxy_handler=ProxyHandler({'http':proxyServer}) # 프록시 서버 설정을 무시하려면 {}을 넣으면 된다.
proxy_auth_handler=ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')

opener=build_opener(proxy_handler, proxy_auth_handler)
install_opener(opener) # 디폴트 오프너로 지정하면 urlopen() 함수로 요청을 보낼 수 있다.
f=urlopen(url)

 

 

3) http.client

http.client 모듈은 urllib.request 모듈로는 쉽게 처리할 수 없는 세밀한 기능이 필요할 때 사용된다. urllib.request 모듈은 http.client 모듈에서 제공하는 API를 사용해서 만들어진 모듈이다.

# 예시 6) GET 요청
from http.client import HTTPConnection

conn=HTTPConnection('www.google.com') # url이 아닌 host를 인자로 줘야 한다.
conn.request('GET', '/') # request(method, url, [body], [headers]) 형식이다. body, headers는 생략 가능하다.
resp=conn.getresponse() # http.client.HTTPResponse 객체를 반환한다.
print(resp.status, resp.reason) # 200 OK

 

# 예시 7) POST 요청
from http.client import HTTPConnection
from urllib.parse import urlencode

host="www.example.com"
data={'name':'김주역', 'age':26}
encData=urlencode(data)
headers={
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Accept' : 'text/plain',
}
conn=HTTPConnection(host)
conn.request('POST', '', encData, headers)
resp=conn.getresponse()
print(resp.status, resp.reason) # 200 OK

※ PUT 메소드 요청도 예시 7과 동일한 방법으로 진행하면 된다.

 

 

 

3. 웹 서버 라이브러리

1) HTTPServer

- 웹 서버를 만들기 위한 클래스

- 서버 IP와 PORT를 바인딩함

 

 

2) BaseHTTPRequestHandler

- 핸들러를 만들기 위한 기반 클래스

- HTTP 프로토콜 처리 로직이 들어있기 때문에 HTTP 프로토콜 관련 로직을 따로 작성할 필요가 없음

# 예시 8) BaseHTTPRequestHandler 사용
from http.server import HTTPServer, BaseHTTPRequestHandler

class MyHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response_only(200, 'OK')
        self.send_header('Content-Type', 'text/plain')
        self.end_headers()
        self.wfile.write(b"Hello, Django!") # 문자열 앞에 b를 붙이면 문자열을 바이트로 변환한다.
        
if __name__ == '__main__':
    server=HTTPServer(('localhost', 8888), MyHandler)
    server.serve_forever()

 

 

3) SimpleHTTPRequestHandler

- BaseHTTPRequestHandler 클래스를 상속받은 클래스

- 별도의 코딩 없이도 다음과 같은 명령어로 즉시 웹 서버를 실행할 수 있다. 디폴트 포트번호는 8000이다.

python -m http.server 8888

- GET, HEAD 메소드는 처리할 수 있지만 그 외의 HTTP 메소드는 처리할 수 없다.

- 요청 시 서버 디렉토리의 리스트가 나온다.

 

 

4) CGIHTTPRequestHandler

- SimpleHTTPRequestHandler 클래스를 상속받은 클래스

- 추가적으로 POST 메소드로 CGI 처리가 가능하다.

- 다음과 같은 명령어로 웹 서버를 실행하면 된다.

python -m http.server 8888 --cgi

- CGI 스크립트는 서버의 cgi-bin 디렉토리 하위에 위치해야 한다.

 

 

 

4. CGI/WSGI 라이브러리

1) CGI와 WSGI

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

- CGI 방식은 웹 서버가 각각의 클라이언트 요청에 대한 독립적인 별도의 프로세스를 직접 생성한다는 단점이 있기 때문에, 파이썬 언어로 애플리케이션을 쉽게 작성할 수 있도록 정의된 WSGI 방식이 주로 쓰인다.

- 파이썬 표준 라이브러리에는 예전의 CGI 규격을 위한 cgi, cgitb 모듈과 개선된 WSGI 규격을 위한 wsgiref 모듈이 함께 존재한다. wsgi 모듈이 cgi의 기능을 포함하기 때문에 cgi 모듈은 거의 사용되지 않는다.

※ cgi 모듈 : 요청에 포함된 파라미터를 처리하기 위한 FieldStorage 클래스가 존재

※ cgitb 모듈 : CGI 스크립트(애플리케이션)을 실행하는 과정에 발생한 에러에 대한 상세 정보를 표시

 

 

2) WSGI 서버의 애플리케이션 처리 과정

- WSGI 규격만 맞추면 어떤 웹 서버에서도 파이썬 애플리케이션을 실행할 수 있다. WSGI 처리 기능이 없는 웹 서버를 위해 mod_wsgi, uWSGI, Gunicorn과 같은 WSGI 서버가 중간에서 WSGI 규격을 처리해준다. 대부분의 파이썬 웹 프레임워크는 WSGI 서버를 제공한다.

- 먼저, 웹 서버에서 클라이언트의 요청을 받으면 WSGI 서버로 처리를 위임하고, WSGI 서버는 애플리케이션을 실행하고 그 결과를 웹 서버에 되돌려주고, 웹 서버는 다시 클라이언트에게 응답한다.

 

 

3) wsgiref.simple_server 모듈

- 웹 프레임워크 개발자가 웹 서버와의 연동 기능을 개발할 수 있도록 도와주는 모듈

- WSGIServer 클래스와 WSGIRequestHandler 클래스가 정의되어 있다. WSGIServer 클래스는 http.server.HTTPServer 클래스를 상속 받은 클래스고, WSGIRequestHandler 클래스는 http.server.BaseHTTPRequestHandler 클래스를 상속받은 클래스다. 장고의 runserver는 이 클래스들을 사용하여 만든 웹 서버다. 

# 예시 9) 간단한 WSGI 서버
from wsgiref.simple_server import make_server

def my_app(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    response=[b"Hello, Django!", b"How are you?"]
    return response

if __name__=='__main__':
    server=make_server('localhost', 8888, my_app)
    server.serve_forever()

 

 

● 출처 : 파이썬 웹 프로그래밍 개정판 - 김석훈

 

반응형

댓글