brunch

You can make anything
by writing

C.S.Lewis

by 마르코 Feb 15. 2016

쇼핑몰 순위를 뽑아보자

이제 칼퇴근 할 수 있다

아래 링크는 <내 손 안의 비서> 첫 글이자 전체 목차




상상해보자. "나는 쇼핑몰에 다니는 마케터다. 어느 날 사장님께서 전체 쇼핑몰 리스트와 순위를 뽑아보고 싶으시단다. 그런 사이트를 찾아서 보여드렸더니, 오늘부터 매주 쇼핑몰 조회수를 정리해서, 변화 추이를 매달 보고하라고 하신다. 어디 '싫어요' 버튼이 있으면 눌러 드리고 싶다. 그래도 어쩌나 해오라면 해가야지." 이제 파이썬 비서를 불러보자.

  

스타일차트(링크)라는 사이트를 이용해보자. 생김새는 아래와 같이 생겼다.

주의! 예시로 해당 사이트를 사용하였을 뿐, 해당 사이트의 신뢰도는 보증하지 않습니다.

 


아래에 보면 여성쇼핑몰순위 전체 탭 아래에 순위별로 쇼핑몰이 쭉 나온다. 전체 페이지는 28페이지고 각 페이지는 35개의 쇼핑몰로 이뤄져있으니, 얼추 등록된 쇼핑몰 갯수는 1000개쯤 되는 듯하다. 이걸 매주 손으로 세고 있으면, 하루는 딱 날려먹기 쉽다.



아름다운 수프(BeautifulSoup4)를 마시자


이번에는 처음으로 외부 라이브러리를 가져와보도록 하자. 파이썬을 많이 사용하는 이유 중 하나는 전세계적으로 사용자 층이 두꺼워서 내가 생각하는 많은 기능을 이미 다른 개발자가 만들어 놓은 경우가 많다는 것이다. 우리는 웹페이지의 정보를 긁어와야 하는데, 이것도 어떤 친절하신 개발자님께서 만들어 놓으셨다.


혹시 아직 파이썬을 설치하지 않은 분이라면, 앞서 파이썬 설치하는 법(링크)이라는 글을 참고하자.


아래와 같이 맥의 경우 terminal에서, 윈도우의 경우 cmd 창에서 아래의 명령어를 입력한다. pip는 파이썬으로 만들어진 도구 상자들, 즉 라이브러리를 손쉽게 깔고 지울 수 있게 만들어 놓은 툴이다.


 pip install beautifulsoup4


이번에 쓸 도구 상자는 beautifulsoup4(한글, 영어)라는 라이브러리인데, 다행히 문서의 한글화가 진행되어 있다. 다만 한국어 자료의 경우 번역 투의 부자연스러운 문장들이 보인다.


이제는 다시 크롬(Chrome)으로 사이트에 들어가서, 웹페이지에 마우스 오른쪽을 누르고 '요소 검사(Inspect)'를 누른다. 그럼 이제 아래 이미지와 같이 오른쪽 혹은 하단에 탭이 열리는데, 열린 탭의 가장 왼쪽 상단에 이미지에서 파란색으로 활성화된 '네모 상자에 마우스 아이콘이 올려져 있는' 듯한 아이콘을 클릭하면 웹페이지의 구성 요소를 여기저기 뜯어볼 수 있다. 그리고 리스트 첫 번째 항목만 선택되도록 마우스를 올려놓고 클릭하면, 오른쪽 탭에 해당 하는 코드가 선택되면서 회색 음영이 생긴다. '<li' 로 시작하는 태그에 클래스(class)의 이름이 "info2"인 것을 확인할 수 있다. 



자, 이제 이걸 가지고 쇼핑몰의 이름과 조회수를 긁어와 보자.

아래 코드는 파이썬3로 작성되었습니다.
# python3

import urllib.request
from bs4 import BeautifulSoup

TARGET = "http://www.style-chart.com/rank/?&sort=F&page="
PAGES = 28

for index in range(1, PAGES):    
    with urllib.request.urlopen(TARGET + str(index + 1)) as url:
        data = url.read()
        soup = BeautifulSoup(data, "html.parser")

    query = soup.find_all('li', attrs={'class':'info2'})    

    for child in query:
        try:
            print(
                "%s\t%s" %
                (child.contents[1].strong.string, child.contents[-4].contents[-1].string)
            )
        except AttributeError:
            pass


간단하게 설명을 해보자면, 웹사이트에 접근할 수 있는 도구 상자를 가져온다.("import urllib.request") 그리고 앞서 pip로 설치한 beautifulsoup4 라이브러리 역시 가져온다.("from bs4 import BeautifulSoup") 해당 사이트는 페이지가 바뀔 때 마다 


http://www.style-chart.com/rank/?&sort=F&page=1

http://www.style-chart.com/rank/?&sort=F&page=2

http://www.style-chart.com/rank/?&sort=F&page=3


가장 마지막의 page= 이후의 숫자가 하나씩 올라가는 것을 볼 수 있고, 파이썬의 for문(링크)을 이용해서 전체 28페이지를 한 번씩 접근할 예정이다. 그래서 앞의 부분만 정리해서 빼놓는다.('TARGET = "http://www.style-chart.com/rank/?&sort=F&page="') 전체 페이지 숫자도 따로 적어놓자.("PAGES = 28") 그리고 이제 각 페이지 별로 정보를 읽어서 뷰티풀수프를 실행시킨다.("for index in range(1, PAGES): with urllib.request.urlopen(TARGET + str(index + 1)) as url: data = url.read() soup = BeautifulSoup(data, "html.parser")") 실행시킨 뷰티풀수프에 구글 크롬을 통해서 확인한, "info2"라는 클래스 이름을 가지고 전체 화면을 검색한다.("query = soup.find_all('li', attrs={'class':'info2'})") 그렇게 찾은 데이터를 다시 for문을 돌면서 화면에 출력한다.("for child in query:") ("try: print("%s\t%s" % (child.contents[1].strong.string, child.contents[-4].contents[-1].string)except AttributeError: pass")


뷰티풀수프 깊게 이해하기


이걸 아마 다른 사이트에서 적용하려면 가장 고생하는 부분이 바로 아래 두 줄의 코드일 것이다.


child.contents[1].strong.string
child.contents[-4].contents[-1].string


우리는 클래스 이름이 "info2"인 경우 전체를 query라는 변수에 저장했다. 그 후 for문을 통해서 각각의 경우를 child라는 이름으로 뽑아냈는데, 이것이 우리가 크롬을 통해서 선택한 '1위'에 해당하는 그 부분이 되겠다. 이것을 print()로 출력해보면 아래와 같다. 아래처럼 리스트 형태가 보이는데, 리스트가 잘 기억이 나지 않는다면 앞의 글(링크)를 참고하도록 하자.


[

'\n', 

<p class="txt1">...<strong>다홍</strong>...</p>, 

'\n', 

<p>...</p>, 

'\n', 

<div class="txt5">...<strong>132,668</strong>...</div>, 

'\n', 

<div class="mallBest">...</div>, 

'\n'

]


원래는 엄청 더 길지만 필요한 데이터만 가져왔고, 총 9개의 item을 갖는 리스트이다. 쇼핑몰 이름인 '다홍'은 2번째에 위치하고 있는데, 앞의 글에서 컴퓨터는 0에서부터 숫자를 세고 이것을 '인덱스'라고 부른다고 이야기했다. 그러니까 child.contents[1]을 통해서 접근할 수 있다. 즉, 1번 인덱스의 자료를 꺼내오라는 것이다. 그런데 그 안에 또 이런저런 많은 요소들이 있고, 우리는 <strong>이라는 태그 속에 있는 글자만 꺼내오고 싶다. 그래서 child.contents[1].strong을 통해서 해당하는 요소만 꺼내 올 수 있다. 그런데 이걸 출력해보면 "<strong>다홍</strong>"이라고 스타일까지 긁어온다. 글씨만 긁어오려면 뒤에 .string만 더 붙여주면 된다. 


두 번째 코드는 child.contents[-4]라고 쓰고 있는데, 순서에 왠 마이너스가 붙어있나 생각이 들 수도 있다. 눈치 빠른 사람은 느꼈겠지만, 바로 뒤에서부터 숫자를 센 것이다. 0은 음수가 없기 때문에 이번에는 그냥 1부터 숫자를 세면 된다. 조회수는 뒤에서 네 번째 들어있다. 그리고 이번에도 strong으로 빼내려고 봤더니, 앞에 다른 strong 태그를 사용하고 있는 정보가 있어서 쓸 수가 없었다. 그래서 다시 한 번 contents로 분리해봤더니, 가장 뒤의 요소여서 [-1]을 통해서 접근 할 수 있었다.



이제 퇴근할 시간


이제 터미널(윈도우는 cmd)에 출력되는 내용을 긁어서 복사해서 엑셀에 붙여넣기만 하면 된다. 매주 3초면 전체 데이터를 수집할 수 있다. 얼른 하고 집에 가자.




프로그래밍은 외계어가 아닙니다. 실생활에서 쓸 수 있는 프로그래밍을 알립니다. 그리고 댓글이 달릴수록 더 쉬워집니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari