programming

파이썬 웹 크롤링 예제를 통해 쉽게 배우기 (web crawling with python)


by Kitle · 2017. 06. 08.



파이썬을 통해 아주 쉽고 간단하게 웹의 정보를 가져올 수 있는 방법을 알아보겠습니다. 아주아주 간단하게 웹 사이트를 테스트 할 수 있는 파이썬 스크립트 입니다.


준비하기

요구 파이썬 라이브러리


beautifulsoup4와 requests 두개가 필요합니다.

pip 명령어를 이용하여 설치해줍니다. 설치 방법은 다음과 같습니다.

$ pip install beautifulsoup4
$ pip install requests


알고리즘 구성하기

다음과 같은 구성으로 진행합니다.


웹사이트 내부의 링크는 본인 사이트의 링크와 외부 사이트 링크가 혼재되어 있을 겁니다. 따라서 기준을 정하고 내부사이트인 경우 탐색해가며 크롤링을 진행하고, 외부 사이트의 경우는 크롤링을 하지 않는 것이죠. baseurl 설정을 통해 분기를 만들면 됩니다.

내부 사이트인 경우는 baseurl로 시작하는 경우라고 볼 수 있습이다. 이 경우는 추가적으로 다시 페이지를 스캔하며 테스트 하겠죠? URL을 잘 불러오는 경우 또 다시 크롤링 할 페이지가 되므로 목록에 추가하고, error가 떨어지면 화면에 해당 error 출력합니다. (error 리스트는 현재 따로 저장하지 않습니다)


baseurl 이 kitle.xyz 이고, 발견한 URL 이 kitle.xyz/blabla 면 blabla는 내부 사이트로 인식하고 추가로 스캔할 사이트에 추가함


baseurl 로 시작하지 않는 URL 은 외부 사이트로 간주하고, 테스트 리스트에는 추가하지만 스캔을 하지는 않습니다. (하게되면 거의 무한루프입니다)


*스터디 용으로 작성된 코드로, 실무용으로는 많은 예외처리가 필요합니다.


코드는 python3 기준으로 쓰여있습니다. python2 버전은 특히 print 문 및 구문문법을 변경해야 합니다.


구현하기

#-*- coding: utf-8 -*-

from urllib.request import urlopen

from urllib.request import HTTPError

from bs4 import BeautifulSoup

import string

# 주의! 상용으로 운영되는 사이트를 절대 baseurl 로 넣고 테스트하지마세요!!!

# 추가적인 예외처리를 충분히 추가하세요!!

# 안전을 위해 최대 테스트 카운트는 10으로 제한하였어요.


urlcallcnt = 0

baseurl="http://www.pythonscraping.com"

urllist=[]


def ScanInnerUrl(scanurl):

    try:

        html = urlopen(scanurl)

    except HTTPError as e:

        print(e,scanurl)

        return

    except ValueError as e:

        print(e,scanurl)

        return

    print('now page :',scanurl)

    bsObj = BeautifulSoup(html.read(),"html.parser")

    for link in bsObj.findAll('a'):

        if 'href' in link.attrs:

            if(link.attrs['href']=='/' or link.attrs['href'].count('#')!=0):

                #현재페이지로 이동하는 경우, 페이지내 다른 위치 이동은  skip

                continue

            else:

                makeNewUrl(link.attrs['href'])


#새로 스캔된 url 추가

def addUrl(gentempurl):

    if gentempurl not in urllist: #url 중복 방지

        print('added :',gentempurl)

        urllist.append(gentempurl)


# inner url 인경우 baeurl + inner url 로 full url 생성,

# 아닌경우는 outerurl로 바로 등록 요청

def makeNewUrl(tempurl):

    if(tempurl.count('/')!=0):

        #내부 페이지는 baseurl 추가하여 저장

        if(tempurl.startswith("http")==False):

            tempgenurl=baseurl+tempurl

            addUrl(tempgenurl)

        else:

            addUrl(tempurl)


#최초 스캔 시작 지점, 하드코딩은 추후 baseurl 로 변경할

ScanInnerUrl(baseurl)


#스캔 1회 후 부터는 내부페이지들을 돌며 계속 추가하며 스켄

for nowlist in urllist:

    if(nowlist.startswith(baseurl)==True):

        #print('Inner URL : ',nowlist)

        #상용서비스 테스트 제한 URL탐색을 10회로 제한

        if urlcallcnt < 10:

            urlcallcnt += 1

            ScanInnerUrl(nowlist)

        else:

            print('limit error')

            break


#외부 페이지는 스캔할 필요는 없고 urlopen 만 테스트

for nowlist in urllist:

    if(nowlist.startswith(baseurl)==False):

        #print('Outer URL : ',nowlist)

        print('now page :',nowlist)

        try:

            html = urlopen(nowlist)

        except HTTPError as e:

            print(e," error : ",nowlist)

        except ValueError as e:

            print(e," error :",nowlist)


print(urllist)

#끝

이상으로 마칩니다.