7/07/2016

[RUBY] Nokogiri library를 이용한 Web(HTML/XML) Parsing


프로그래밍에서 많이 활용되는 코드는 어떤것들이 있을까요?
제 생각에는 대표적으로 소켓통신, DB 연결 코드 등이 있을 것 같고 오늘의 주제로 선정한 웹 파싱도 있을 것 같다라는 느낌이 듭니다.

오늘은 웹, 즉 HTML Page에 대해서 Ruby를 이용해 쉽게 파싱하고 사용하는 방법에 대해서 소개해 드릴까 합니다.

Web(HTML/XML) Parsing이란?

아주 간단한 개념입니다. Parsing이란 구문분석, 즉 형태에 대해서 어떠한 구조로 이루어져있는지 분석하는 것을 의미하는데요. 우리가 일반적으로 사용하는 웹, 즉 HTML에 대해 구조화하는 과정을 의미합니다.

http://img.blog.csdn.net/20160514120210886

그럼 웹 파싱이 왜 필요할까?  이런 의문을 가지시는 분들도 있을겁니다.
우리는 브라우저를 통해 이미지화, 프레임에 맞춰진 아주 가공된 데이터를 보고있지만 사실 브라우저로 들어오기 전 웹 페이지는 HTML 코드로 이루어진 페이지이지요.

그래서 우리는 Parsing을 통해 이 웹 페이지를 좀 더 쉽게 다룰 수 있고 구별해 낼 수 있습니다. 이 것을 위해 Web Parsing 을 하게되는거지요.

Nokogiri!

Ruby는 Java, Python 과 같이 많은 Library를 지원합니다.
그 중 단언컨데 Ruby에서 거의 최고라고 꼽는 라이브러리가 있습니다. 바로 Nokogiri 입니다. (물론 개인적인 견해입니다. 당연 웹해킹으로 밥먹고 사는데 이만한 라이브러리가 어디있겠습니까..)

웹 요청과 관련된 툴(예를들어 WVS, Crawler 등등)을 만들때 활용하면 정말 유용한 라이브러리죠.


Install Nokogiri

nokogiri를 사용하기 위해선 nokogiri gem 설치가 필요합니다.
ruby-gem이 설치되어 있다면 gem 명령을 통해 쉽게 설치할 수 있습니다.

#> gem install nokogiri

 ** Troubleshooting **
설치 과정 중 에러가 발생하는 경우도 있습니다. 에러에 따라 대응 방법이 대부분 다르겠지만, 공통적으로 많이 발생하는 에러에 대한 해결 방법입니다.

C 에러
#> apt-get install build-essential patch 

이외
#> apt-get install ruby-dev zlib1g-dev liblzma-dev

혹시나 위 방법으로도 해결 안되는 에러가 있다면 댓글 남겨주세요.

아무튼 이제 설치가 잘 되었는지 확인해볼까요?
ruby shell을 열어 nokogiri를 불러봅니다.

#> irb
irb(main):001:0> require 'nokogiri'
=> true
irb(main):002:0> 

true 가 나온다면 정상적으로 로드된 것입니다.

Nokogiri를 이용한 HTML Parsing 1 - Load HTML/XML

nokogiri를 가지고 HTML 코드를 파싱하는 방법은 여러가지가 있습니다.
음.. 방법이라기 보단 데이터를 읽어오는 경로가 되겠네요.

1. Internet으로 부터 받아오기(From the Internets)
아무래도 nokogiri가 가장 많이 사용되는 것이 원격지에서 받아 바로 파싱하는 방법일텐데요. open-uri를 이용하여 간단하게 받아올 수 있습니다.

require 'open-uri'
page = Nokogiri::HTML(open("http://www.hahwul.com/"))
restclient를 이용해서도 받아올 수 있겠네요.

require 'nokogiri'
require 'restclient'

page = Nokogiri::HTML(RestClient.get("http://www.hahwul.com"))  
puts page.class   # => Nokogiri::HTML::Document
2. File로 부터 받아오기(From a File)

doc = File.open("blossom.xml") { |f| Nokogiri::XML(f) }

3. 소스코드에 직접 쓰기(From a Code)

html_doc = Nokogiri::HTML("<html><body><h1>Mr. Belvedere Fan Club</h1></body></html>")
xml_doc  = Nokogiri::XML("<root><aliens><alien><name>Alf</name></alien></aliens></root>")

Nokogiri를 이용한 HTML Parsing 2 - CSS를 이용한 Parsing

웹 페이지를 꾸미기 위해선 CSS(Cascading Style Sheets)를 많이 사용하죠. 이 CSS는 DOM 영역안에서 각각 구역의 디자인을 담당하게 되는데 nokogiri는 이것을 이용하여 파싱할 수 있습니다.

아래 irb log를 보면 at_css를 이용해서 값을 가져오는 것을 볼 수 있습니다.

irb(main):012:0> title = page.at_css "title"

irb(main):012:0> title = page.at_css "title"
=> #<Nokogiri::XML::Element:0x17ac6f4 name="title" children=[#<Nokogiri::XML::Text:0x17ac4ec "HAHWUL :: 하훌">]>

제가 읽어온 주소의 title content 영역의 데이터가 읽어진 것을 확인할 수 있네요.
값 바꾸기 또한 굉장히 쉬운 방법으로 가능합니다.

at_css 이외에도 하나 좋은 방법이 있습니다. 개인적으로 선호하는 방법인데요,
각각 파싱된 구역은 각각 css 메소드를 가지고 있습니다.

그래서 아래와 같은 방법으로도 찾아낼 수 있습니다. 물론 위 방법이랑 거의 비슷하죠.

irb(main):032:0* page.css("title")

irb(main):032:0* page.css("title")
=> [#<Nokogiri::XML::Element:0x13d1868 name="title" children=[#<Nokogiri::XML::Text:0x13c9ce4 "HAHWUL :: 하훌">]>]

아래 URL에 좋은 방법이 많네요. 참고하시길!

http://ruby.bastardsbook.com/chapters/html-parsing/

Nokogiri를 이용한 HTML Parsing 3 - 태그와 id값을 가지고 찾기

제 블로그 내 HTML 코드 중 짧은것을 하나 예시로 할까합니다.
위에 시간데이터와 View 를 표기하는 영역인데요, id를 Stats1_content라고 지정해놨었습니다.

<div id='Stats1_content' style='display: none;'>
<font color='black'><span class='hahwul count text-counter-wrapper' id='Stats1_totalCount'>
</span> ː Views</font>
</div>
자 이제 nokogiri를 이용해서 안에 내용을 읽어와볼까요?

page.css("div#Stats1_content")

irb(main):040:0* page.css("div#Stats1_content")
=> [#<Nokogiri::XML::Element:0x135eb24 name="div" attributes=[#<Nokogiri::XML::Attr:0x135eac0 name="id" value="Stats1_content">, #<Nokogiri::XML::Attr:0x135eaac name="style" value="display: none;">] children=[#<Nokogiri::XML::Text:0x135e37c "\n">, #<Nokogiri::XML::Element:0x135e2b4 name="font" attributes=[#<Nokogiri::XML::Attr:0x135e228 name="color" value="black">] children=[#<Nokogiri::XML::Element:0x135da6c name="span" attributes=[#<Nokogiri::XML::Attr:0x135d8a0 name="class" value="hahwul count text-counter-wrapper">, #<Nokogiri::XML::Attr:0x135d88c name="id" value="Stats1_totalCount">] children=[#<Nokogiri::XML::Text:0x135cae0 "\n">]>, #<Nokogiri::XML::Text:0x135c784 " ː Views">]>, #<Nokogiri::XML::Text:0x135c3d8 "\n">]>]

css를 이용해서 읽어옴과 동시에 div 안에 데이터들이 파싱된 형태로 로드되었고, 사용자는 더 상세하게 파싱해서 사용할 수도 있습니다.


Nokogiri를 이용한 HTML Parsing 4 - select 하여 직접 사용하기

이번 포스팅 내용 중 마지막 부분입니다. nokogiri는 parsing 및 검색을 통해 찾아낸 데이터에 대해 select 할 수 있고, select를 하게되면 그 데이터 내 값이나 행위들을 자유롭게 다룰 수 있게됩니다.

test = page.css("div#Stats1_content").select
puts test.class
위와같이 css로 찾은 후 select 메소드를 사용하면 return 값으로 선택된 객체가 잡히죠.
test 변수에 넣고 test 내 메소드를 통해서 값들을 호출할 수 있습니다.

irb(main):041:0> test = page.css("div#Stats1_content").select
=> #<Enumerator: [#<Nokogiri::XML::Element:0x135eb24 name="div" attributes=[#<Nokogiri::XML::Attr:0x135eac0 name="id" value="Stats1_content">, #<Nokogiri::XML::Attr:0x135eaac name="style" value="display: none;">] children=[#<Nokogiri::XML::Text:0x135e37c "\n">, #<Nokogiri::XML::Element:0x135e2b4 name="font" attributes=[#<Nokogiri::XML::Attr:0x135e228 name="color" value="black">] children=[#<Nokogiri::XML::Element:0x135da6c name="span" attributes=[#<Nokogiri::XML::Attr:0x135d8a0 name="class" value="hahwul count text-counter-wrapper">, #<Nokogiri::XML::Attr:0x135d88c name="id" value="Stats1_totalCount">] children=[#<Nokogiri::XML::Text:0x135cae0 "\n">]>, #<Nokogiri::XML::Text:0x135c784 " ː Views">]>, #<Nokogiri::XML::Text:0x135c3d8 "\n">]>]:select>
irb(main):042:0> puts test.class
Enumerator
=> nil

맺음말

크게 nokogiri 소개와 설치방법, 3가지 단계로 사용하는 방법에 대해서 정리해봤습니다.
물론 더 많은 기능과 메소드가 존재하지만 기초적으로 꼭 알고 있어야 할 부분에 대해서 정리해봤네요. Ruby의 HTML 파싱을 담당하는 nokogiri. ruby programmer라면 잘 알아두어야겠죠?

Reference 

http://www.nokogiri.org/tutorials/installing_nokogiri.html
http://ruby.bastardsbook.com/chapters/html-parsing/


HAHWUL

Security engineer, Gopher and H4cker!

Share: | Coffee Me:

0 개의 댓글:

Post a Comment