[ Python ] Selenium을 활용한 크롤러 제작 후기

웹 검색, 크롤링, 액셀 작성, 자동화


최근 사수로부터 한가지 업무를 부여 받았다. 바로 아래 액셀파일을 채우는 일이었다. 액셀파일은 매년 1위부터 100위의 빌보드 차트를 hot rank, song, artist, writer, producer, year, lyrics 와 같은 속성으로 정리해놓은 파일이었다. 내가 할 일은 각 곡의 Writer와 Producer를 검색하여 채워넣는 일이었다. (작사가, 작곡가를 구분짓는 우리나라와 달리 미국은 Writer가 작사가와 작곡가를 포함하고 있는 개념이었다.) 문제는 수백곡도 아닌 2016년부터 1965년까지 총 5100개의 곡을 해야한다는 것이었다.

문제의 액셀 파일

이러한 업무를 부여 받고 가장 먼저 찾아본 사이트는 빌보드 공식사이트 였다. 곡에 대한 정보를 정리해 놓은 데이터셋을 제공하지 않을까하는 기대를 했었지만 빌보드 공식사이트에서는 writer와 producer에 대한 정보를 제공하지 않았다.

구글링을 하다 보니 운이 좋게도 WIKIPEDIA에서 각 곡에 대한 정보를 제공하고 있다는 사실을 알게 되었다. 위키에 몇몇 곡을 검색해본 결과 곡에 대한 정보를 아래처럼 같은 구조로 제공해주고 있었다. 하지만 5천여개의 곡을 모두 검색해 볼 수는 없으니 이번 기회에 요즘 핫한 크롤러를 만들어 자동으로 일을 시켜보기로 하였다.

WIKI에서 제공하는 곡 정보

준비 작업

Beautifulsoup, Scrapy과 같은 크롤링을 위한 라이브러리를 들어보기는 했지만 한번도 활용해본 적이 없었기 때문에 어떤 것이 적합할지에 대한 고민이 있었다. 그러던 중 Webdriver와 Selenium을 활용하여 네이버 로그인, 검색을 자동적으로 하는 방법을 알게 되었다. (참고: http://yumere.tistory.com/75) Webdriver는 코드를 통해 웹브라우저를 조작할 수 있는 API이다. 파이썬은 Selenium이라는 라이브러리를 통해 Webdriver를 활용할 수 있었다.

다음 할 일은 나의 작업을 단순화하여 컴퓨터에게 알려주는 일이었다. 나의 작업을 단순화하면 아래와 같다.

1 ) 구글 열기
2 ) 노래 검색하기
3 ) 위키피디아 검색 결과 택하기
4 ) 원하는 정보가져오기

1. 구글 열기
2. 노래 검색하기
3. 위키피디아 검색 결과 택하기
4. 원하는 정보 가져오기

코드 설명

  • xlrd, xlutils, selenium등 주요 라이브러리를 import한다. xlrd와 xlutils는 python에서 액셀을 조작하기 위한 라이브러리이다. selenium활용시 exceptions 처리를 위해선 별도로 import가 필요하다.▼
    - 라이브러리마다 xls, xlsx 등 지원하는 액셀 버전이 달라확인이 필요함
  • chromedriver의 path를 지정하여 webdriver를 실행한다. webdriver는 브라우저마다 별도의 다운이 필요하다. (크롬 웹드라이버 다운로드 링크 : https://sites.google.com/a/chromium.org/chromedriver/downloads)
  • 아래 참고자료를 읽어보면 큰 도움이 된다. 
    1) Selenium으로 무적 크롤러 만들기 
    ( https://beomi.github.io/python/2017/02/27/HowToMakeWebCrawler-With-Selenium.html )
import time
from selenium import webdriver
import xlrd
from xlutils.copy import copy
from selenium.common.exceptions import NoSuchElementException,StaleElementReferenceException
import os
# driver
driver = webdriver.Chrome(executable_path="C:/Users\yunhwan\workspace\crazy\chromedriver.exe")
  • get으로 google.com 에 접속한다. ▼
  • 액셀파일을 열고 첫번째 시트를 선택한다.
  • copy_wb를 만드는 이유는 액셀 쓰기를 copy_wb에 진행하고 같은 이름으로 덮어쓰기 위함이다. 덮어쓰는 방식 외에 파일을 수정하는 방식은 잘 모르겠다.
  • 그 다음은 시트에서 원하는 검색 키워드를 가져온다. 곡명(song)과 가수 이름(artist) 가져와서 검색 키워드로 설정하였다.
for i in range(1,101):
driver.get("https://google.com")
# 엑셀 파일 열기
wb = xlrd.open_workbook('test.xls')
sheet = wb.sheet_by_index(0)
copy_wb = copy(wb)
copy_sheet = copy_wb.get_sheet(0)
# 검색 키워드 셀에서 가져오기
song = sheet.cell(i, 1).value
artist = sheet.cell(i, 2).value
keyword = str(song) + ' ' + str(artist) #숫자인 경우가 있어서 str()
#구글 검색
elem = driver.find_element_by_id('lst-ib')
#공통
elem.send_keys(keyword)
elem.submit()
  • 구글 검색을 하면 두가지 종류의 페이지가 나온다. 웹페이지가 구조가 다르기 때문에 try, except문을 활용하였다. ▼
    - 뮤직비디오가 나올 경우와 안나올 경우
두가지 경우의 구글 검색 결과 페이지
  • xpath와 tag name을 활용해서 결과 페이지의 제목을 하나씩 확인하여 ‘Wikipedia’ 단어를 포함한 게시글에 접속한다. ▼
##### 구글 검색 결과 페이지 #####
try:
box = driver.find_element_by_xpath("//div[@id='rso']/div[2]/div")
list = box.find_elements_by_tag_name('h3')
for item in list :
#print(item.text)
if( 'Wikipedia' in item.text ):
p = item.find_element_by_tag_name('a')
p.click()
break
except NoSuchElementException:

box = driver.find_element_by_xpath("//div[@id='rso']/div/div")
list = box.find_elements_by_tag_name('h3')
for item in list:
# print(item.text)
if ('Wikipedia' in item.text):
p = item.find_element_by_tag_name('a')
p.click()
break
  • 위키 곡 정보 페이지에 접속한 후, table을 선택한 후 writer나 producer를 가져온다. ▼
  • find_element가 아닌 find_elements는 해당하는 요소들을 모두 찾아 리스트 형태로 반환한다.
  • copy_sheet.write(i, 3, a) : i행 3열에 a값을 작성한다.
##### 위키 곡정보 페이지 #####
# writer,producer
print("//////////////////////////// " + str(i) + "행을 크롤링중입니다.")
print("//////////////////////////// " + "노래명, 가수 : " + keyword)
try:
table = driver.find_element_by_tag_name('table')
tbody = table.find_element_by_tag_name("tbody")
trs = tbody.find_elements_by_tag_name("tr")

except NoSuchElementException:
print(" [예외 발생] 표 없음 ")
continue
for tr in trs:

if "Writer(s)" in tr.text:
print(tr.text)
a = ""
if tr.find_elements_by_tag_name("li"):
lis = tr.find_elements_by_tag_name("li")
for li in lis:
a = a + "," + li.text
else:
o = tr.find_elements_by_tag_name("td")
a = a + "," + o[0].text
a = a[1:]
copy_sheet.write(i, 3, a)
if "Producer" in tr.text:
print(tr.text)
a = ""
if tr.find_elements_by_tag_name("li"):
lis = tr.find_elements_by_tag_name("li")
for li in lis:
a = a + "," + li.text
else:
o = tr.find_elements_by_tag_name("td")
a = a + "," + o[0].text
a = a[1:]
copy_sheet.write(i, 4, a)
  • 작성한 액셀 파일을 같은 이름으로 덮어쓴다.▼
#저장
    copy_wb.save('test.xls')

느낀 점들

  • 프로그래밍의 본질은 결국 불편함을 해소하는 것이 아닐까? 내가 느끼는 불편함은 어떤 것들이 있는지 찬찬히 고민해봐야 겠다.
  • 사실 겪어보지 않으면 모르는 것들이 참 많다. 불편함도 마찬가지이다. 사람들이 어떤 지점에서 불편함을 느끼는가를 포착해내기 위해서는 다양한 경험이 필요할 것 같다.
  • 이번 일을 계기로 자동화에 대한 관심이 크게 증가했다. 기업 경영에 있어서 자동화는 생산성에 직결되는 문제이기 때문이다.
  • 프로젝트를 할 때 앱/웹을 만드는 것을 목표로 하는 것도 좋지만 무엇보다 중요한 것은 스스로 문제를 정의하고 해결해보는 프로세스인것 같다.

소스코드