[python] 파이썬 웹 크롤링(4): API 활용하기

업데이트:

파이썬 웹 크롤링(4): API 활용하기

본 포스팅은 Web Scraping with Python by Ryan Mitchell을 참고하였습니다.

참고 링크

Chapter 4: API 활용하기

4.1 API가 뭔가요?

프로그래머들이 다른 사람의 코드로 일을 하는 것은 쉽지 않습니다. 네임스페이스 이슈부터 함수 출력 결과에 대한 오해까지, 포인트 A에서 메소드 B로가는 간단한 정보조차 악몽이 될 수 있습니다.

이것이 애플리케이션 프로그래밍 인터페이스(Applacation Programming Interface, API)가 유용해진 이유입니다. API는 이질적인 애플리케이션 간의 훌륭하고 편리한 인터페이스를 제공합니다. 이제 더이상 각 프로그램이 서로다른 프로그래머가 작성한 코드일지라도 문제가 되지 않습니다. 심지어 아키텍쳐가 다르고 서로다른 언어일지라도 문제없습니다. API는 서로다른 소프트웨어 조각들이 서로서로 정보를 교환할때 공통어 역할을 합니다.

비록 다양한 다양한 소프트웨어 애플리케이션들에 대해 다양한 API가 존재한다고 할지라도, 요즘 흔히 말하는 API는 “웹 애플리케이션 API”를 의미합니다. 일반적으로 프로그래머가 어떤 데이터에 대해 HTTP를 통한 API를 요청할 것이고, 요청에 대한 응답 데이터를 XML이나 JSON 형식으로 받게 될 것입니다.

비록 API를 사용하는 것이 웹 크롤링할 때 일반적으로 고려되는 사항은 아니지만, API와 같은 테크닉을 많이 사용합니다. 예를 들어 HTTP 요청을 보낸다던가말이죠. 뿐만 아니라 정보를 얻는다는 점에 있어서 비슷한 결과가 나타나기도합니다.

따라서 여러분은 API를 사용한 값과 윀 크롤링한 값을 조합할 수 있습니다. 이번 챕터에서는 API에 대한 개괄적인 정보와 API의 작동방식, 그리고 어떻게 웹 크롤링에 API를 사용하는지 알아보겠습니다.

4.2 API 작동방식

비록 API가 당연히 있다고 생각할 정도로 도처에 널리 퍼져있지는 않지만, 막상 찾아보면 다양한 종류의 API를 찾을 수 있습니다. 만약 여러분이 음악에 관심이 있다면, 노래 제목, 아티스트, 앨범, 유사한 음악 스타일과 아티스트와 같은 음악 정보를 주는 API가 존재합니다. 만약 여러분이 스포츠에 관심이 있다면, ESPN에서는 게임 스코어, 운동선수 정보와 같은 정보를 제공하는 API를 제공합니다. 구글은 API를 제공하는데, 이는 언어 번역, 분석, 위치정보와 같은 정보를 제공합니다. API를 사용하는 방법은 정말 쉽습니다. 웹 프라우저에 아래 주소를 입력해보세요.

http://freegeoip.net/json/50.78.253.58

이 사이트는 아래와 같은 정보를 제공합니다.

{“ip”:”50.78.253.58”,”country_code”:”US”,”country_name”:”United States,”region_ code”:”MA”,”region_name”:”Massachusetts”,”city”:”Chelmsford”,”zipcode”:”01824”, “latitude”:42.5879,”longitude”:-71.3498,”metro_code”:”506”,”area_code”:”978”}

여러분은 지금 여러분의 웹 브라우저에 주소를 입력했고, 그것에 해당하는 정보를 얻었습니다. 그러면 API와 일반적인 웹사이트는 뭐가 다를까요? HTTP를 통한 API 함수는 웹 사이트에 대한 데이터를 가지고 오고, 다운로드 하는 것과 같은 프로토콜을 사용합니다. 즉, 일반적인 인터넷과 같다는 것이죠. API와 일반 웹사이트와 다른 점은 문법이 엄격하게 규정되어 있다는 것입니다. 그리고 일반적인 웹사이트는 HTML 형태를 띄는 것과는 달리 API의 결과 데이터는 JSON이나 XML로 나타난다는 것이 서로 다른 점입니다.

4.2.1 API 메소드

HTTP를 통해 웹서버에 정보를 요청할 때 쓰이는 방법에는 4가지가 존재합니다.

  • GET
  • POST
  • PUT
  • DELETE

GET 메소드는 여러분이 웹브라우저 주소창에 주소를 입력하고 웹사이트에 방문할 때 사용합니다. 결국 GET메소드를 사용한다는 것은 http://freegeoip.net/json/50.78.253.58 주소를 요청하는 것과 같습니다. 즉, GET 메소드를 사용하는 것은 이렇게 말하는 것과 같습니다. “이봐, 웹브라우저! 나한테 정보를 보여줘”

POST 메소드는 여러분이 어떤 입력 양식을 작성하거나, 정보를 제출할 때 사용됩니다. 즉, 벡엔트 스크립트를 서버에게 보낼때 사용되는 것이죠. 여러분이 웹사이트에 로그인을 할 때마다, 여러분은 여러분의 아이디와 비밀번호를 통해 POST 메소드를 요청하는 것입니다. 즉, POST 메소드를 사용하는 것은 이렇게 말하는 것과 같습니다. “이 정보를 너의 데이터베이스에 저장해줘!”

PUT 메소드는 웹 사이트를 이용할 때 상대적으로 덜 사용되지만 API를 사용할 때는 종종 사용됩니다. PUT 요청은 어떤 오브젝트나 정보를 업데이트 하는데 사용됩니다. 새로운 유저에 대해서는 API가 POST 요청을 보냅니다. 이에 반해, 이미 존재하는 유저의 이메일 주소를 업데이트 할 때는 PUT 요청을 보냅니다.

DELETE 메소드는 이름에서부터 알수있듯, 오브젝트를 삭제할 때 사용합니다. 예를 들어 제가 http://myapi.com/user/23 과 같은 DELETE 요청을 보냈따는 이것은 유저 아이디가 23인 유저를 삭제한느 것입니다. DELETE 메소드는 public API에서는 보기 힘듭니다. 왜냐하면 누군지 모르는 사람이 데이터베이스 정보를 삭제하게 놔둘순 없으니까요. 따라서 DELETE 대신 PUT 메소드를 대용으로 많이 사용합니다.

4.2.2 인증

물론 어떤 API들은 사용할 때 어떠한 인증도 사용하지 않는 경우가 있긴하지만, 요즘 대부분의 API들은 사용하기전에 어떤 형태로든 인증을 요구합니다. 이때 인증을 요구하지 않는다는 말은 API사용을 위해 회원가입 또는 등록을 하지 않고 API 콜을 자유롭게 할 수 있다는 뜻입니다.

어떤 API들은 API 콜을 할 때마다 유료로 쵸금을 부과하기 위해 인증을 요구하거나, 혹은 월별로 구독 시스템을 가진 경우에 인증을 요구할 때가 있습니다. 다른 인증은 rate limit 유저를 정하기 위해 인증을 요구합니다. 이게 무슨말이냐면, API 요청을 보내는데 유저별로 1초당, 1시간당, 하루등과 같은 기간내 API 콜을 할 수 있는 횟수를 제한 시키는 것입니다. API 콜 횟수를 제한시키지 않는 경우에도 누가 콜을 했는지 추적할 수 있게 하기 위해 인증을 사용하기도 합니다.

API 인증의 모든 방법들이 토큰(token)이라는 것을 사용합니다. 토큰이 뭐냐면 토큰은 API 콜을 가진 상태에서 웹 서버를 통과합니다. 이 토큰이라는 것은 유저가 API 사용등록을 했을 때 유저에게 제공됩니다.

예를 들어, Guns N’Roses라는 밴드의 노래 제목 리스트를 요청하기 위해 Echo Nest API 콜을 한다고 해봅시다.

http://developer.echonest.com/api/v4/artist/songs?api_key=%20&name=guns%20n%27%20roses&format=json&start=0&results=100

이것은 내가 가입했을 때 받은 정보, 즉 api_key 값을 서버에게 제공합니다. 이는 서버에게 API 콜 요청을 보낸 사람이 Ryan Mitchell라는 사실을 알려주고, 결과를 JSON 데이터로 보내줍니다.

토큰을 이용해 URL을 통과하는 것과 더불어 토큰은 요청 헤더의 쿠키를 통해 서버를 지나가는 역할도 합니다. 헤더에 대해서는 12장에서 알아보도록 하겠습니다. 여기서는 간략히만 알아보면 이전 챕터에서 했던 urllib 패키지를 사용하면 아래와 같습니다.

token = "<your api key>"
webRequest = urllib.request.Request("http://myapi.com", headers={"token":token})
html = urlopen(webRequest)

4.3 API 응답

4.3.1 XML vs JSON

앞선 FreeGeoIP 예에서, API의 중요한 특성은 잘짜여진 형식의(well-formatted) 응답이 온다는 것입니다. 가장 잘 알려진 응답 포맷은 eXtensible Markup Language(XML)과 JavaScript Object Notation(JSON) 입니다. 최근 몇년 동안은 JSON이 XML 보다 더 유명해 졌는데, 그 이유는 몇가지 이유가 있습니다. 첫째, JSON 파일은 XML파일보다 작습니다. 예를 들어 XML 데이터는 아래와 같습니다.

<user><firstname>Ryan</firstname><lastname>Mitchell</lastname><username>Kludgist</username></user>

총 글자수는 98자 입니다. 이에 반해 JSON 데이터는 아래와 같습니다.

{"user":{"firstname":"Ryan","lastname":"Mitchell","username":"Kludgist"}}

JSON 데이터는 총 73 글자입니다. XML 데이터보다 무려 36% 작아진 모습입니다. 물론 XML 데이터를 아래와 같은 형식으로 쓸 수도 있습니다.

<user firstname="ryan" lastname="mitchell" username="Kludgist"></user>

그러나, 이는 좋지 않은 방법입니다. 왜냐하면 이런 형식은 데이터의 deep nesting을 지원하지 않기 때문입니다. 이렇게 까지 했음에도 불구하고, 이는 여전히 71 글자로 JSON 데이터와 거의 같은 길이 입니다.

XML보다 JSON 형식을 쓰는 두번째 이유는 웹에 적합하기 때문입니다. 과거에는 API요청을 받는 서버사이드 스크립트로 PHP나 닷넷(.NET)이 유명했습니다. 하지면 현재는 API 요청을 주고받는 서버사이드 스크립트로 앵귤러, backbone과 같은 프레임워크가 유명합니다. 서버사이드 테크닉은 다소 애그노스틱(기술의 작동원리를 몰라도 사용할 수 있는) 합니다. 그러나 백본(backbone)과 같은 자바스크립트 라이브러리는 JSON 데이터를 쉽게 다룰 수 있게 합니다.

비록 대부분의 API들이 XML 결과 형식을 제공하긴 하지만, 우리는 JSON 예를 사용할 것입니다.

4.3.2 API 콜

API 콜의 문법은 API 마다 다 다릅니다. 하지만 공통적으로 제공하는 표준화된 형식이 존재합니다. 예를 들어 우리가 GET 요청을 할 때 URL 경로는 당신이 어떻게 데이터로 파고드는 지를 의미합니다. 반면, 쿼리 파라미터는 필터나 추가적인 검색 내용을 요청하는데 사용됩니다.

예를 들어, 여러분이 아래와 같이 ID 1234 유저가 2014년 8월 한달간의 포스트를 가져오는 API 요청을 한다고 해봅시다.

http://socialmediasite.com/users/1234/posts?from=08012014&to=08312014

많은 다른 API들이 API 버전을 명확히 하기 위해 위와 같은 경로를 사용합니다. 예를들어, 아래는 API 버전4, JSON 형식으로 된 같은 데이터를 제공합니다.

http://socialmediasite.com/api/v4/json/users/1234/posts?from=08012014&to=08312014

또다른 API는 애초에 API 버전 정보를 요청 파라미터값으로 요구하기도합니다.

http://socialmediasite.com/users/1234/posts?format=json&from=08012014&to=08312014

4.4 구글 API 사용하기

구글은 사용하기 쉬운 API를 제공합니다. 여러분이 가장 기본적인 업무, 예를 들어, 언어 번역, 지도 위치, 달력과 같은 기능을 사용할 때마다, 구글은 해당 API를 제공합니다.

구글은 지메일, 유튜브와 같이 유명한 앱에도 API를 적용합니다. Product Page 해당 사이트에 들어가시면 소프트웨어 엔지니어를 위한 다양한 구글 API를 확인할 수 있습니다. API 콘솔에 들어가시면 API 서비스를 위한 편리한 인터페이스를 확인할 수 있습니다.

대부분의 구글 API는 사용 제한이 있는데 하루에 하루에 적개는 250개부터 많게는 2천만건의 요청을 허가합니다. 그리고 경우에 따라서는 신용카드 정보를 요구하기도 합니다. 예를 들어 구글 플레이스 API의 경우 기본 사용량은 24시간에 1000개의 요청인데, 여러분이 본인 인증을 한다면 150,000개의 요청까지 보낼 수 있습니다. 자세한 내용은 API 사용제한을 확인하면 알 수 있습니다.

4.4.1 시작하기

만약 여러분이 구글 계정이 있다면 구글 개발자 콘솔에서 API 목록을 보고 API key를 만들 수 있습니다. 여러분이 등록한 API key를 포함한 정보는 구글 API 콘솔 페이지에서 확인할 수 있습니다.

“Create new Key” 버튼을 누르고 API key를 생성할 수 있고, IP 주소나 URL을 제한시킬 수 있습니다. 여러분은 여러개의 API key를 만들 수 있습니다. 예를 들어, 각기 다른 프로젝트, 다른 도메인에 대해 서로 다른 API key를 사용할 수 있습니다. 하지만 API 사용 제한은 구글 계정 당으로 계산되므로 주의해야합니다.

4.4.2 사용 예

구글 API 중 가장 유명한 것은 지도 관련 API 입니다. 아래 예를 요청하기 전에 구글 API 콘솔에서 해당 API를 활성화 시키는 것을 잊지 말아주세요. 자, 이제 여러분의 웹 브라우저에서 간단한 GET 요청을 보내보도록 하겠습니다. 사용법은 아래와 같습니다.

https://maps.googleapis.com/maps/api/geocode/json?address=1+Science+Park+Boston
+MA+02114&key=<your API key>

응답은 아래와 같습니다.

"results" : [ { "address_components" : [ { "long_name" : "Museum Of Science
Drive
way", "short_name" : "Museum Of Science Driveway", "types" : [ "route" ] }, { "l
ong_name" : "Boston", "short_name" : "Boston", "types" : [ "locality", "politica
l" ] }, { "long_name" : "Massachusetts", "short_name" : "MA", "types" : [ "admin
istrative_area_level_1", "political" ] }, { "long_name" : "United States", "shor
t_name" : "US", "types" : [ "country", "political" ] }, { "long_name" : "0211
4", "short_name" : "02114", "types" : [ "postal_code" ] } ], "formatted_address"
: "Museum Of Science Driveway, Boston, MA 02114, USA", "geometry" : { "bounds" :
{ "northeast" : { "lat" : 42.368454, "lng" : -71.06961339999999 }, "southwest" :
{ "lat" : 42.3672568, "lng" : -71.0719624 } }, "location" : { "lat" : 42.3677994
, "lng" : -71.0708078 }, "location_type" : "GEOMETRIC_CENTER", "viewport" : { "n
ortheast" : { "lat" : 42.3692043802915, "lng" : -71.06943891970849 }, "southwest
" : { "lat" : 42.3665064197085, "lng" : -71.0721368802915 } } }, "types" : [ "ro
ute" ] } ], "status" : "OK" }

보스톤 과학 박물관의 위도와 경도 입니다.

4.4.3 JSON 데이터 파싱하기

이번 챕터에서는 API 응답값으로 받은 데이터를 파싱하는 방법에 대해 알아보겠습니다. 먼저 IP 주소를 현실 주소로 바꾸는 API를 사용해 보겠습니다.

http://freegeoip.net/json/50.78.253.58

위 요청의 아웃풋을 파싱해보겠습니다.

import json
from urllib.request import urlopen

def getCountry(ipAddress):
  response = urlopen("http://freegeoip.net/json/"+ipAddress).read()
                    .decode('utf-8')
  responseJson = json.loads(response)
  return responseJson.get("country_code")

print(getCountry("50.78.253.58"))

위 코드의 결과는 IP 주소 50.78.253.58의 국가 코드 입니다. 위 코드에서 사용한 JSON 파싱 라이브러리는 파이썬의 기본적으로 내장된 라이브러리 입니다.