파이썬(Python)과 BeautifulSoup을 이용하여 HTML Parser를 만들어보자.

 

얼마전 Node.js를 이용하여 간단한 Parser를 만들어보았습니다.

오늘은 Phython을 이용하여 비슷한 파싱 프로그램을 만들어보려고 합니다.

일단 현재 서버에 Python 환경을 확인해봐야 합니다.

# python
Python 2.6.6 (r266:84292, Jun 18 2012, 14:18:47)
[GCC 4.4.6 20110731 (Red Hat 4.4.6-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

아쉽게도 2.6이네요. 저는 3.x를 선호하니까 우선 최신버전을 설치하고 진행하겠습니다. 

먼저 3.6.1 설치를 위한 소스 파일을 다운로드받았습니다.

$ Python-3.6.1.tgz

ls -tlr
total 1020
drwxr-xr-x 24 501 501   4096 Mar 21 15:32 Tools
-rw-r--r--  1 501 501 101166 Mar 21 15:32 setup.py
-rw-r--r--  1 501 501   9066 Mar 21 15:32 README.rst
drwxr-xr-x  3 501 501   4096 Mar 21 15:32 Python
-rw-r--r--  1 501 501  41359 Mar 21 15:32 pyconfig.h.in
drwxr-xr-x  2 501 501   4096 Mar 21 15:32 Programs
drwxr-xr-x  2 501 501   4096 Mar 21 15:32 PCbuild
drwxr-xr-x  5 501 501   4096 Mar 21 15:32 PC
drwxr-xr-x  2 501 501   4096 Mar 21 15:32 Parser
drwxr-xr-x  4 501 501   4096 Mar 21 15:32 Objects
drwxr-xr-x 13 501 501   4096 Mar 21 15:32 Modules
drwxr-xr-x  2 501 501   4096 Mar 21 15:32 Misc
-rw-r--r--  1 501 501  58935 Mar 21 15:32 Makefile.pre.in
drwxr-xr-x  8 501 501   4096 Mar 21 15:32 Mac
-rw-r--r--  1 501 501  12773 Mar 21 15:32 LICENSE
drwxr-xr-x 33 501 501   4096 Mar 21 15:32 Lib
-rwxr-xr-x  1 501 501   7122 Mar 21 15:32 install-sh
drwxr-xr-x  2 501 501   4096 Mar 21 15:32 Include
drwxr-xr-x  2 501 501   4096 Mar 21 15:32 Grammar
drwxr-xr-x 18 501 501   4096 Mar 21 15:32 Doc
-rw-r--r--  1 501 501 159739 Mar 21 15:32 configure.ac
-rwxr-xr-x  1 501 501 483582 Mar 21 15:32 configure
-rwxr-xr-x  1 501 501  35740 Mar 21 15:32 config.sub
-rwxr-xr-x  1 501 501  42856 Mar 21 15:32 config.guess

빌드합니다.

$ configure --preffix=/app/python361
$ make
$ make install

빌드가 정상 완료되면 해당 경로를 PATH에 추가하여 줍니다. (/app/python361/bin)

이제 python3, pip3과 같은 실행 파일을 사용할 수 있는 상태가 되었습니다.

pip3가 꼭 되어야 합니다. BeautifulSoup를 받아야 하기 때문이죠.

(* pip에 대해서는 http://sarc.io/index.php/aws/752 에서도 언급이 된 바 있더군요)

그러면 이제 BeautifulSoup를 설치하도록 합니다.

# pip3 install beautifulSoup4
Collecting beautifulSoup4
  Downloading beautifulsoup4-4.6.0-py3-none-any.whl (86kB)
    100% |????????????????????????????????| 92kB 480kB/s
Installing collected packages: beautifulSoup4
Successfully installed beautifulSoup4-4.6.0

 

BeautifulSoup가 잘 설치되었다면 실제로 페이지 웹 소스를 획득해봅니다.

아래 Python 프로그램은 sarc.io의 웹 소스를 읽어들인 후 output.html 파일에 그 내용을 저장하는 일을 합니다. 

import urllib.request

if __name__ == "__main__":
        print("Parsing HTML...")
        requestUrl = urllib.request.Request("http://sarc.io");
        parsingHtml = urllib.request.urlopen(requestUrl).read()

        print(parsingHtml)

        f = open("./output.html", "wb")
        f.write(parsingHtml)
        f.close()

 

< 미션 : www.apache.org 홈페이지의 개별 아파치 프로젝트 이름만 뽑아 출력한다 >

꼭 먼저 www.apache.org 웹 소스를 확인해 보시기 바랍니다.

          <div class="col-md-12" id="by_name"><!-- id for eventual use by whimsy; do not move -->
            <h4>By Name</h4>
            <div class="col-lg-4 col-sm-4">
              <div class="row">
                <div class="col-lg-6 col-md-12 border-right">
                  <ul class="list-unstyled" style="margin-bottom: 0px;">
                    <li><a href="http://httpd.apache.org/" title="Apache Web Server (httpd)">HTTP Server</a></li>
                    <li class="letter-header">A</li>
                    <li><a href="http://accumulo.apache.org/" title="Sorted, distributed key/value store">Accumulo</a></li>
                    <li><a href="http://ace.apache.org/" title="Centralized life cycle management and deployment of OSGi based and related modular software artifacts for distribution.">ACE</a></li>
                    <li><a href="http://activemq.apache.org/" title="Distributed Messaging System">ActiveMQ</a></li>
                    <li><a href="http://airavata.apache.org/" title="Workflow and Computational Job Management Middleware">Airavata</a></li>
                    <li><a href="http://allura.apache.org/" title="Forge software for hosting software projects">Allura</a></li>
                    <li><a href="http://ambari.apache.org/" title="Hadoop cluster management">Ambari</a></li>
                    <li><a href="http://ant.apache.org/" title="Java-based build tool">Ant</a></li>
                    <li><a href="http://any23.apache.org/" title="Anything to Triples">Any23</a></li>
                    <li><a href="http://apex.apache.org/" title="Enterprise-grade unified stream and batch processing engine">Apex</a></li>
                    <li><a href="http://apr.apache.org/" title="Apache Portable Runtime libraries">APR</a></li>
                    <li><a href="http://archiva.apache.org/" title="Build Artifact Repository Manager">Archiva</a></li>
                    <li><a href="http://aries.apache.org/" title="Enterprise OSGi application programming model">Aries</a></li>

 

일단 <a ...>xxx</a> 형태를 뽑아내는 프로그램을 만들어봅니다.

from bs4 import BeautifulSoup
import requests

response = requests.get('http://www.apache.org')
parsedHtml = response.text
soup = BeautifulSoup(parsedHtml, 'html.parser')
print(soup.find_all('a'))

이걸로는 쉽지 않겠네요. 

이번에는 텍스트만 추출하여 보겠습니다.

from bs4 import BeautifulSoup
import requests

response = requests.get('http://www.apache.org')
parsedHtml = response.text
soup = BeautifulSoup(parsedHtml, 'html.parser')
links = soup.find_all('a')

for link in links:
        print(link.text)

 아니면 title만..

from bs4 import BeautifulSoup
import requests

response = requests.get('http://www.apache.org')
parsedHtml = response.text
soup = BeautifulSoup(parsedHtml, 'html.parser')
links = soup.find_all('a')

for link in links:
        print(link)

        if link.has_attr('title'):
                print(link.attrs['title'])

 

이런저런 시행착오 끝에. 

from bs4 import BeautifulSoup
import requests

response = requests.get('http://www.apache.org')
parsedHtml = response.text
soup = BeautifulSoup(parsedHtml, 'html.parser')

links = soup.find_all()
start = False

for link in links:
    if start == True:
        if link.has_attr('href') and link.has_attr('title'):
            print(str(link.text))
    if str(link) == '<h4>By Name</h4>':
        start = True
        print('True')