brunch

You can make anything
by writing

C.S.Lewis

by 쑹이씨 Jan 09. 2016

웹의 재사용

그리고 나의 생각

https://www.kimonolabs.com/

위 서비스는 웹페이지에서 관심 있는 정보를 손쉽게 추출하여 재사용할 수 있도록 해주는 웹 스크랩 서비스이다.


작년 안식휴가 때 위와 같은 아이디어로 프로토타입을 잡았었는데, 역시 내게는 꾸준함이 가장 부족한 역량인 듯하다. 저들은 서비스를 만들어서 이미 편의를 제공하고 있지 않은가.


웹의 재사용은 내가 가장 관심 있어하고, 오랫동안 벗어나지 못하는 인생 프로젝트인 것 같다.

처음에는 마북 닷컴을 오픈해서 온라인 서점들의 책 가격을 각각 비교해주는 일부터 시작했다.

그 이후로 나는 웹 스크래핑과 문자열의 패턴을 추출하는 것에 집중했고, 벌써 10년 넘게 느릿느릿 아이디어를 개선해 나가고 있다.


일반적인 웹 스크래핑의 여러 단계를 한번 풀어보고, 내가 생각하는 궁극(?)의 재사용방법을 제시해볼까 한다.


1. 웹 스크래핑


웹페이지는 HTTP 헤더, GET Query String, POST Request Body 의 3가지를 파악하면

모든 페이지를 재현해낼 수 있다.

HTTP 헤더에서는 Cookie, UserAgent, Referer가 영향을 미친다.

QueryString은 URL에 포함되어 있으므로 파악이 쉽다. 그러나 Pretty URL이라고 해서 경로가 QueryString역할을 하는 경우도 있으므로 주의 깊게 살펴야 한다.

Request Body는 웹 개발자 도구 등을 통해서 보는 것이 쉽다. 그러나 POST로 데이터가 넘어가더라도, QueryString의 전달이 병행될 수도 있다.


HTTP클라이언트로 해당 페이지가 재현되는데 필요한 값들을 모두 세팅해서 HTML을 얻어오자.


2. 추출


웹 스크래핑으로 얻는 것은 HTML 소스이다.

얻고자 하는 데이터가 HTML상에 있으면 그나마 다행인데, JavaScript의 연산 결과로 이를 만들어낸다면 자동화를 다시 한번 생각해봐야 할 것이다.


2-1. 문자열 추출

문자열 추출에는 두말할 것 없이 정규표현식이다. 문자열의 주변 패턴을 직접 기입하여

원하는 부분만 캡쳐(괄호로 감싸는 것)하는 과정이다.

개발 속도와 작동 속도가 모두 빠르고 불규칙적으로 보이는 문자열도 추출이 가능하나,

HTML은 유사한 패턴이 많이 나타나므로 다른 정보를 취할 위험이 있다.

이를 극복하기 위해서는 특징 있는 구역을 먼저 추출하고, 그 구역 안에서 다시 추출하는 것이 안전하고 유연하다.

간혹 그냥 문자열 찾기의 연속으로 구성하는 경우가 있는데, 나중을 위해서 정규표현식을 익히는 게 바람직할 것 같다.


2-2. HTML DOM 파서

HTML 소스를 DOM파서에 집어넣으면 트리구조로 DOM이 구성된다.

여기서 원하는 값의 위치를 XPATH로 표현하거나, CSS Selector로 표현하면 된다.

DOM을 구성할 때에는 XHTML로 변환시켜놓는 게 가장 좋다. HTML을 XHTML로 정규화해주는 툴들을 이용하면 된다.

이 방법은 HTML 태그 단위로 추출하기 때문에 문자열 사이의 값을 취할 때에는 문자열 추출을 병행해야 한다.


한계점

위와 같은 방법이 보통의 스크래핑 방법이다.

이를 서비스화 하려면, 웹 스크래핑을 위해 HTTP 요청을 미리 저장해놔야 하고, (이게 최선이다)


추출을 위해서 원하는 항목에 대한 정규식이나 XPATH, CSS셀렉터를 저장해놔야 한다.


그러나 원하는 사이트의 HTML구성이 바뀐다면(리뉴얼) 추출 패턴을 모두 새로이 짜야한다.

HTML 코드를 읽을 수 있어야 하고, 패턴을 설정할 수 있어야 한다. 

기술인력이 필요한 것이다.


이를 기가 막히게 해결한 것이 처음에 소개한 kimono labs의 서비스이다.

URL을 입력해서 원하는 웹페이지를 띄우고,

눈에 보이는 부분을 클릭해서 선택하면, 그것으로 XPATH가 지정된다. 

그리고 그 이후로는 같은 부분을 추출해 오는 것이다.


하지만 내가 보기에는 멀었다.

눈에 보이는 것만 추출하는 것에다가, HTML이 아닐 경우는 추출을 할 수 없다.

JSON, XML은 어쩔 텐가.


대안도 없이 지적하는 것은 아니다

내 대안은 아래와 같다.


1. DB에 정제된 데이터를 보여주는 동적 웹사이트들은 템플릿을 이용해서 페이지를 만들어낸다.

2. 이 페이지들을 서로 DIFF 하면, 바뀌는 부분만 남는다.

3. 이 바뀌는 부분들이 곧 DB에 들어있던 데이터이다.

5. 그중에서 내가 원하는 값을 고른다. 그 값의 좌우 문자열 패턴을 추려낸다. 바뀌지 않는 부분이 좌우 패턴이 되므로 길수록 좋다.

6. 좌우 패턴을 문자열 찾기 하는 것만으로 원하는 값을 다시 추출할 수 있다.

7. 이때 내가 고른 값을 저장해놓고, 학습 데이터로 재사용하게 된다.

8. 값을 뽑는 것이 실패하게 되면, 대상 페이지들을 다시 DIFF 한다.

9. 그중에서 내가 골랐던 값(학습 데이터)과 일치하는 것을 자동으로 선택하고, 좌우 패턴을 그것으로 업데이트한다.

10. 이때 잘못 뽑힐 수도 있다. 그래서 페이지간 비교를 늘려서 일치율이 높은 좌우 패턴을 우선 사용하게 하면 된다.


장황하긴 한데, 위와 같이 하면 페이지 구성이 바뀌더라도, JSON이더라도 모두 추출이 가능하다.


여기서 의문점이 하나 있을지도 모르겠다.

DIFF는 줄단위로 하는데 저딴식으로 하면 줄단위로나 뽑지 원하는 값을 뽑는 건 헛소리다 할 것이다.

그래서 토크 나이저가 필요하다. 단순히 공백 단위로 자르거나 해서 여러 줄로 나눈 다음 DIFF를 하는 것은 한계가 많다. 가격의 숫자만 추출하려면 어쩔 건가. 


그래서 목적에 맞는 토크 나이저를 Lexer로 만들어서

http주소 토큰(http://...), 전화번호 토큰(xx-xxx-xxxx), HTML text토큰(<span>... </span>), HTML 속성 토큰(src="..."), 가격 숫자 토큰(... 원) 등으로 잘라낸 리스트를 DIFF의 재료로 쓰는 것이다.


이렇게 하면 토크 나이저 작성, 같은 템플릿으로 만들어진 페이지 5개 정도, 만족하는 학습 값을 지정하는 과정만으로, 페이지의 구성이 바뀌더라도 추출 대상을 추적하는 웹 스크래퍼가 만들어진다.


진행 중인 모습

* 토크나이저 : https://github.com/sng2c/RuntimeLexer (Java), https://github.com/sng2c/Parse-Token-Lite (Perl)

* DIFF후 좌우 패턴 추출 : https://github.com/sng2c/clj-template-reverse (Clojure), https://github.com/sng2c/template-reverse-python (Python), https://github.com/sng2c/Template-Reverse (Perl)


나는 위에 말한 것을 진행 중이다. 여러 언어로 재 구현하면서 조금씩 개선시켜 왔다.

RuntimeLexer와 clj-template-reverse (java base)

또는 

Template-Reverse와 Parse-Token-Lite (perl base)

를 이용하면 위에 제시한 과정이 구현된다.


위 아이디어에 대한 문의나 질문은 언제나 환영하는 바이다.


작가의 이전글 PHP를 선택할 때
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari