웹 크롤링하기 [Beautiful Soup]
반응형

 

위키 검색에서 예상치 못한 문제점이 발생하였다.

1) 모델에서 뱉어내는 개 이름이 정확한 품종의 풀네임이 아닌 경우가 있어서, 위키에서 검색을 잘 못한다.

ex) 웰시코기의 경우 풀네임이 Pembroke Welsh Corgi -> Pembroke로는 검색이 안됨.

2) 그리고 위키API에서 없는 페이지의 경우, 특정 페이지가 아닌 링크가 담긴 검색결과가 나온다.

따라서 우선 특정 사이트에서 크롤링하는 방법을 사용하기로 했다.

기존 사이트의 URL을 통해 크롤링을 하려고 하면, 추가 라이브러리를 사용하면 된다.

우선 타겟으로 한 사이트는 다음과 같다. 미국 애견 협회로 세계에서 2번째로 오래되었다고 한다.

www.abc.org

 

그리고 1번의 문제를 해결하기 위해, 위 사이트에서 검색한 결과에서

제일 상단에 위치한 저 Breed Information (종 정보) 링크를 통해 정보를 얻어내고자 한다.

 

BeautifulSoup을 사용한 크롤링

파이썬으로 크롤링을 할때 가볍게 사용하는 라이브러리로 Selenium과 Beautiful Soup가 있는데, 더 간편한 느낌의 Beautiful soup를 사용하도록 하겠다.

pip install requests beautifulsoup4

 

간단한 사용법은 다음과 같다. 생성되는 저 BeautifulSoup 객체를 조작하여 크롤링을 하면 된다.

from bs4 import BeautifulSoup

#파일 열어서 넘기기
with open("htmlfile.html") as fp:
    ss  = BeautifulSoup(fp)

#html 내의 내용을 문자열로 넘기기
ss = BeautifulSoup("<html>abcabacabc</html>")

 

URL을 통해 객체를 생성하는 방법은 다음과 같다.

from urllib.request import urlopen

#타겟 사이트
html = urlopen("https://www.akc.org/?s=" + class_name)
bsObject = BeautifulSoup(html,"html.parser")

 

자 그렇다면, BeautifulSoup 객체를 어떻게 조작해야 할까.

타겟 사이트에서 어느 부분이 html 문서에서 어떤 역할을 하는지 먼저 파악해야 한다.

가장 간편한 방법은 크롬 개발자모드를 사용하는 방법이다.

크롬으로 사이트 접속 -> f12 (개발자모드) -> Elements -> ctrl+shift+c 누르기 -> 궁금한 부분 클릭gkrl

 

a 태그안에 들어있는 저 주소를 가져오는 것이 1차 목표이므로,

HTML의 내부 태그에 따라 여러 메소드가 존재하지만, 나는 find_all 메소드를 사용하여 원하는 정보를 얻어내고자 한다.

 #get secondUrl 
    for link in bsObject.find_all('a'):
        url = link.get('href')
        if url is not None:
            if("/dog-breeds/" in url) and not(url.endswith("/dog-breeds/")):
                secondUrl = url #secondUrl로 저장
                print(link.text.strip(), url)
                break

 

a태그 내용을 다 긁어오고 -> 그중 href를 추출해서 -> 원하는 정보에 맞는 타겟만 뽑아내면 된다.

 

그럼 이제 다시 이 링크를 통해 들어가서 정보를 뽑아내려한다.

find 메소드를 다음과 같이 사용하면 태그와 특정 클래스를 특정하여 얻어낼 수 있다.

name = bsObject.find("h1",{"class" : "page-header__title"}).string

 

함께 제공하는 사진 역시, db에서 가져오는 링크형식이어서 무자비하게 링크를 긁어왔다.

최종적인 메소드는 다음과 같다.

#search from site
def dogSite(class_name):
    html = urlopen("https://www.akc.org/?s=" + class_name)
    bsObject = BeautifulSoup(html,"html.parser")

    secondUrl = None
    result = []
    img_src = []
    count = 0

    #get secondURL 
    for link in bsObject.find_all('a'):
        url = link.get('href')
        if url is not None:
            if("/dog-breeds/" in url) and not(url.endswith("/dog-breeds/")):
                secondUrl = url
                print(link.text.strip(), url)
                break

    #search at secondURL
    if secondUrl is None:
        information = "Sorry, We can't find an information"
        name = class_name
        result = None
        img_src = None

    else:
        html = urlopen(secondUrl)
        bsObject = BeautifulSoup(html,"html.parser")

        #종 이름
        name = bsObject.find("h1",{"class" : "page-header__title"}).string
        name = name.replace("\n","").strip()

        #정보 (요약)
        for contents in bsObject.find_all("span",{"class":"attribute-list__text"}):
            result.append(contents.string)

        #설명
        information = bsObject.find("div",{"class" : "breed-hero__footer"}).string
        information = information.replace("\n","").strip()


        #사진
        for img in bsObject.find_all("img",{"class" : "media-wrap__image lozad"}):

            img_src.append(img.get('data-src'))
            count = count+1
            #사진 5장 제한
            if(count == 6):
                break

    return name, result, information, img_src

결과 화면

크롤링은 다른 사이트의 정보를 무단으로 가져오는 것이니 만큼, 저작권의 문제가 존재할 수 있으니 유의하자!

 

전문가가 아니라 정확하지 않은 지식이 담겨있을 수 있습니다.
언제든지 댓글로 의견을 남겨주세요!

반응형