RSS

월간 보관물: 10월 2012

공공 데이터 긁어 오기

예전부터 만들고 싶었던, 착한 가게를 소개하는 sns앱에 대해서 진지하게 고민하기 시작한 지, 오늘로 삼일째. 추석 연휴를 보내고 목요일 근무가 제대로 될 리 없었던 차에, 퇴근 직전에 착한 가격 업소를 정부에서 관리하고 있다는 것을 검색을 통해 알게 되었다.

[관련기사] 우리 동네 착한 가격 업소 아세요? 
– 행정안전부, 7,132개 착한가격업소 선정 –

어려운 경제여건에서도 저렴한 가격으로 영업하며 어려운 이웃과 지역사회를 위해 봉사하는 착한가격업소가 전국적으로 7,132개 선정되었다.

(하략)

이런 공공데이터가 있다면 내가 만들고자하는 “착한 가게”의 기초자료로 활용하기 적절하다는 생각에, 살펴보았다. 하지만 좌절스럽게도 open api나 파일형태로 제공되는 데이터는 없었다. 그냥 게시판처럼 목록과 상세 내용이 있는 페이지가 전부라니. 우리나라의 공공정보의 현주소려니 체념하고, 어떻게 데이터를 긁어올 수 있을지 고민해봤다.

공공 데이터 긁어 오기 시작

쿼리 파라미터를 순차적으로 증가시키면 거기에 맞는 상세 페이지가 만들어지는 형태라서, 순차적으로 주소를 호출하고 HTML를 파싱해서 내가 원하는 데이터를 가져오기로 했다.

이 작업을 위해서 레일스를 활용하기로 했다. 가져온 데이터는 기준위치에서 얼마나 떨어져있는지 쿼리가 가능한 MongoDB를 사용한다. 레일스에서 해당 데이터를 긁어 오기 위해서 rake task를 하나 생성했다.  rake는 rails의 make나 ant같은 툴로 특정 task를 코딩해두면 rake 명령으로 실행할 수 있다. task를 정의하는 부분이다.

Nokogiri를 활용한 HTML 파싱

위 코드에서 Nokogiri라는 gem를 사용했는데, XML이나 HTML같은 well-form document에서 xpath를 사용해서 특정 element(태그)나 attritbute로 찾아내고 이동하고 데이터를 추출하는 일련의 기능을 묶어 놓은 것이다. jquery랑 유사한 기능이다. url로 데이터를 가져와서 Nokogiri로 HTML를 파싱한다.

xpath란?

nokogiri를 제대로 활용하기 위해서는 xpath라는 것을 이해하면 좋은데, Michael Kay의 표현을 빌려오자면, xpath란 ‘데이터베이스에서 SELECT가 있다면 XSLT에는 xpath가 있다’ 즉 HTML이라는 document에서 내가 원하는 데이터를 뽑아내기 위한 문법 정도로 이해하고 있으면 되겠다.

위 코드에서 data.phone = doc.xpath(“//th[text()=’전화번호’]/following-sibling::*”).text 부분을 보면 xpath 함수 안에 들어가는 내용이 xpath 문법이다. 풀어 쓰면 “전화번호를 innerText로 갖고 있는 <th> 태그 바로 뒤에 있는 태그들”에 해당된다.

이렇게 어떤 HTML이나 XML이라 하더라도 xpath를 잘 정의해두면 특정 데이터를 쉽게 가져올 수 있을 것이다. 행안부의 착한 가격 가게 페이지가 아닌 다른 어떤 페이지라고 하더라도 xpath의 내용만 고침으로 필요 데이터를 가져올 수 있게 되었다.

Nokogiri와 xpath의 도움으로 몇 줄안되는 코딩으로 해당 HTML에서 우리가 원하는 데이터를 선택하고 그것을 MongoDB에 담는 데 까지 성공했다. 이제 반은 성공한 셈이다.

주소를 좌표로 바꿔보자

지오코딩

일반적으로 geocoding란 주소나, 우편번호등의 데이터에서 longitude, latitude로 대표되는 좌표계의 경위도를 찾아내는 것이다. 그 반대로 좌표에서 주소를 찾아내는 것은 리버스 지오코딩이라고 한다. 우리는 행안부의 자료에서 착한 가격 가게들의 주소를  이미 받아왔다. 이제 이 주소에 해당되는 좌표가 어떻게 바뀌게 되는지 살펴보려고 한다.

다음 open api중 지역 API를 활용

다음의 open api중에 지역 API를 활용하면 정확한 주소를 입력했을 때, 경위도를 뽑아준다. 심지어 새주소 체계에서도 잘 동작한다. 이를 활용하려면 다음 계정으로 로그인한 상태에서 API 키를 발급받아야 하는데, 매우 간단히 신청이 가능하고 즉시 활성화된다. 제한이 있다면 하루에 이 API를 호출할 수 있는 횟수가 3만번으로 제한되어 있다는 것이다. 우리의 주소데이터가 약 6천개이므로 3만번이면 나쁘지 않다.

이 코드에서 지오코딩이 어떻게 일어나는 지 볼 수 있다. 주소를 받아서 그 주소를 API의 쿼리 파라미터에 넣어 보낸다. 물론 개인적으로 받은 api_key를 함께 보내야 제대로 동작한다. 그런데 그렇게 주소를 요청했지만 데이터를 못받는 경우도 있다. 그러면 주소에서 맨 뒤 어절을 지우고 재귀호출을 한다. 그런식으로 뒤의 상세 주소를 지워감으로 주소가 모호해지고 그러면 API에서 위치를 받아오는데 성공할 수 있게 된다. 좀 어려운가? 예를 들면, “서울시 마포구 공덕동 14-1 2층 서울약국” 이런 주소로 쿼리했을 때 결과값이 오지 않는다면 서울약국을 떼고 “서울시 마포구 공덕동 14-1 2층”으로 요청해본다. 그래도 안되면 2층을 떼낸다. “서울시 마포구 공덕동 14-1” 이렇게 보내면 거의 성공하게 된다. 혹시 주소가 없는 경우라면 14-1도 떼버린다. 그러면 공덕동의 어디 쯤의 좌표를 돌려주게 되어 모호해지긴 하지만 데이터는 받게 되는 것이다. 이런 식의 heuristic 접근이 상당히 유용했다. 재귀호출을 한 것도 코드의 복잡도를 낮춰줘서 괜찮은 아이디어였던 것 같다. 🙂

이렇게 어렵게 얻어온 경위도 좌표는 MongoDB에 잘 저장되었고 이제 소기의 목적을 달성한 것으로 보인다.

남은 작업

이제 남은 작업은, 이 DB에 접근하기 위한 API wrapping layer를 하나 만들어 주고, 그것 호출해서 사용할 iOS, Android 앱을 만들면 되는 것이다. 이번 프로젝트에 Titanium을 써보려고 한다. 과연 어느 정도까지 자유도를 줄 수 있을 지 네이티브 iOS개발자로서 무척 기대된다.

Advertisements
 
댓글 2개

게시자: 켬 2012년 10월 6일 in 공공정보, 앱개발, OpenAPI, rails

 

태그: , , , ,