DNA 포럼 API 서비스 모음 DNA Lens

Python으로 오픈API 이용 하기


Python에서 Web Service REST 요청 #

Python은 HTTP 요청들을 수행하는 많은 모듈들을 제공합니다. 이 문서에서는 Python 표준 라이브러리에 있는 urllib와 urllib2 모듈을 사용하여 어떻게 GET과 POST 요청을 수행할 수 있는지에 대해서 설명합니다.

간단한 GET 요청 #

URL로부터 데이터를 얻는 가장 간단한 방법은 urllib.urlopen 함수를 사용하는 것입니다.
import urllib

url = 'http://dna.daum.net'
u = urllib.urlopen(url)
# u is a file-like object
data = u.read()

이것은 다음 한줄로 요약될 수 있습니다.

data = urllib.urlopen(url).read()

이것은 몇몇 데이터를 빠르게 얻어오기 위해 좋지만, 일반적인 페이지와 404나 500 error같은 페이지를 쉽게 구분할 수 없습니다. urllib2 모듈은 이 HTTP 에러들 잡아내는 exception을 던지는 비슷한 함수를 하나 제공합니다.

import urllib2

try:
	data = urllib2.urlopen(url).read()
except urllib2.HTTPError, e:
	print "HTTP error: %d" % e.code
except urllib2.URLError, e:
	print "Network error: %s" % e.reason.args[1]

만약 그 서버가 200(OK) 또는 HTTP redirect와는 다른 상태코드를 반환한다면 HTTPError가 던져 집니다. Redirect들은 자동적으로 따라 갑니다.

간단한 POST 요청 #

몇몇 API들은 POST 요청을 만들어야 합니다. urllib와 urllib2 양쪽에서 제공되는 urlopen 메소드는 선택적인 두번째 인자를 통해서 POST 요청을 지원합니다.

import urllib

url = "http://apis.daum.net/search/knowledge?&output=xml&q=OpenAPI"

apikey = "DAUM_SEARCH_DEMO_APIKEY"
output = "xml"
q = "OpenAPI"

params = urllib.urlencode({
	'apikey': apikey,
	'output': output,
	'q': q
})

data = urllib.urlopen(url, params).read()

httplib2 사용하기 #

만약 urllib2 코드가 너무 복잡하다면, Joe Gregorio의 [http]httplib2 library에 관심이 갈 것입니다. 그것은 Python 표준 라이브러리에 포함되어 있지 않습니다. 그래서 따로 다운로드 받아서 설치해야 합니다.

모든 요청은 Http 클래스의 인스턴스를 통해서 넘겨집니다. 그 생성자로 디렉토리를 넘김으로써 HTTP 캐시를 활성화할 수 있습니다.

간단한 GET 요청은 다음과 같습니다.
import httplib2
http = httplib2.Http()
response, content = http.request('http://dna.daum.net/')

여기서, 응답은 서버 응답으로부터의 헤더들을 담고 있는 반면에, 내용은 응답의 몸체(body)인 사전같은 객체(dictionary-like object)입니다.

POST 요청은 urllib와 urllib2와 비슷하지만, 명시적으로 요청의 Content-Type 헤더를 application/x-www-form-urlencoded로 지정해야 합니다.

import httplib2
http = httplib2.Http()

url = "http://apis.daum.net/search/knowledge?&output=xml&q=OpenAPI"

apikey = "DAUM_SEARCH_DEMO_APIKEY"
output = "xml"
q = "OpenAPI"

import urllib
params = urllib.urlencode({
	'apikey': apikey,
	'output': output,
	'q': q
})

response, content = http.request(url, 'POST', params,
	headers={'Content-type': 'application/x-www-form-urlencoded'}
)

Python을 사용하여 JSON 파싱하기 #

JSON 자료구조는 Python 데이터 형으로 사상(map)됩니다. 그래서 이것은 어떤 XML 파싱코드없이도 직접 데이터에 접근하기 위한 강력한 도구입니다.

Python을 위한 JSON 라이브러리들 #

Python을 위한 몇몇 JSON 라이브러리가 있지만, 가장 인기있는 것은 Bob Ippolito의 [http]simplejson입니다. [http]Python Package Index로부터 simplejson을 다운받을 수 있습니다.

예제 : 웹 검색하기 #

import simplejson, urllib
apikey = "DAUM_SEARCH_DEMO_APIKEY"
SEARCH_BASE ="http://apis.daum.net/search/knowledge"


def search(query, **args):
    args.update({
            'apikey': apikey,
            'q': query,
            'output': 'json'
    })

    url = SEARCH_BASE + '?' + urllib.urlencode(args)
    result = simplejson.load(urllib.urlopen(url))

    return result['channel']

info = search('OpenAPI')
for item in info['item']:
    print item['title']
신지식에서 OpenAPI라는 키워드로 검색한 결과들의 제목을 출력해줍니다.

Python을 사용하여 XML 파싱하기 #

minidom 사용하기 #

XML을 조작하기 위해 가장 널리 이해되는 것은 W3C 승인 DOM입니다. Python은 full DOM 구현과 더 가벼운 구현을 위한 xml.dom.minidom을 지원합니다.

한 예로서,
import urllib
from xml.dom import minidom

def knowledge_by_query(q):
    url = "http://apis.daum.net/search/knowledge?apikey=DAUM_SEARCH_DEMO_APIKEY&output=xml&q=" + q
    dom = minidom.parse(urllib.urlopen(url))

    items = dom.getElementsByTagName("item")
    for item in items:
        for node in item.childNodes:
            if node.nodeName == "title":
                print node.childNodes[0].nodeValue

knowledge_by_query("OpenAPI")
신지식에서 OpenAPI라는 키워드로 검색한 결과들의 제목을 출력해줍니다.

ElementTree 사용하기 #

DOM API는 유용한 표준이지만, XML을 다루는 Python다운 방법이 아닙니다. Python에서 더욱 자연스럽게 XML을 다루기 위한 많은 시도가 있었지만, Fredrik Lundh의 [http]ElementTree가 아마 가장 성공적일 것입니다.

이번에는 ElementTree를 사용해서 신지식 OpenAPI 예제를 작성해 보겠습니다.
import urllib
from elementtree.ElementTree import parse

def knowledge_by_query(q):
    url = "http://apis.daum.net/search/knowledge?apikey=DAUM_SEARCH_DEMO_APIKEY&output=xml&q="+q
    rss = parse(urllib.urlopen(url)).getroot()
    for element in rss.findall("item"):
        print element.findtext("title")

knowledge_by_query("OpenAPI")
결과는 minidom을 이용했을 때와 똑같습니다.

참고자료 #

추후 읽을만한 꺼리 #