python/크롤링

[파이썬 크롤러] 셀레니움을 이용한 크롤링

끼발자 2021. 7. 22. 14:29
반응형

이번 포스트에서는 Selenium을 이용한 크롤러를 제작 해 보겠다.

 

bs4를 이용한 크롤러는 아래 링크 확인.

 

2021.07.21 - [python] - [파이썬 기초] 웹 크롤러 만들기

설치

pip install selenium

이전 포스트에서 셀레니움이 제어 가능한 웹 드라이버를 이용해 크롤링을 수행한다 말 했었고,

사용되는 브라우저가 크롬을 비롯해 다양하다고 언급했었다.

 

패키지를 훑어보면 사용가능한 드라이버를 알 수 있다.

  • Firefox
  • Chrome
  • Ie
  • Edge
  • Opera
  • Safari
  • BlackBerry
  • PhantomJS
  • Android

등등

 

크롬에서 수집이 불가해서 다른 브라우저를 사용한 적이 있지만, 대부분 크롬을 사용한다.

우리가 사용하고있는 크롬대신, 크롬 드라이버라는 프로그램을 사용하기때문에, 사용중인 크롬 버전에 맞는 크롬 드라이버를 다운받자.

내 크롬 정보는 크롬 우측상단 계정표시 오른쪽 점 세개를 클릭. Chrome 정보를 누르면 된다.

크롬 버전에 맞게 드라이버를 설치해주고, 파이썬 프로젝트로 경로를 바꿔주거나, 절대경로를 적어두자.

 

https://chromedriver.chromium.org/downloads

 

ChromeDriver - WebDriver for Chrome - Downloads

Current Releases If you are using Chrome version 92, please download ChromeDriver 92.0.4515.43 If you are using Chrome version 91, please download ChromeDriver 91.0.4472.101 If you are using Chrome version 90, please download ChromeDriver 90.0.4430.24 If y

chromedriver.chromium.org

 

 

설치를 마쳤다면 일단 무지성으로 임포트 해보자.

상기 언급했듯, 셀레니움 패키지의 웹드라이버 모듈을 사용 할 것이다.

from selenium import webdriver

당장 필요한 준비는 끝났다.

driver = webdriver.Chrome(크롬드라이버 경로)

크롬 드라이버 경로는 절대경로로 썼다면 '절대경로/chromedriver.exe' or '절대경로/chromedriver' 이다.

exe는 윈도우, 없는 경우는 mac이나 기타 unix계열 os이니 본인의 os에 맞는 경로를 적어주자.

물론 프로젝트와 같은 디렉터리에 넣었다면, 그냥 절대경로는 무시해도 좋다.

 

혹시 IOS를 사용하고있으며, 확인되지 않은 개발자라면서 실행이 안된다면,

보안 및 개인정보 보호 > 일반 > 다음에서 다운로드한 앱 허용 을 허용해주면 된다.

 

정상적으로 실행이 되면,

이런 화면이 뜬다.

 

이제 코드를 통해서 저 웹페이지를 제어해보자.

크롬 드라이버는 지금 driver 라는 변수에 할당되어있으니, driver.명령어를 통해 제어한다.

driver.get('https://www.billboard.com/charts/hot-100')

자, 이전 포스트와 마찬가지로 빌보드에 접근해보자.

셀레니움을 이용하면, xpath를 이용해서 더 편하게 데이터에 접근할 수 있다.

전에 했던 class_name을 이용해서 데이터를 불러올 수도 있고, xpath를 이용할 수도 있다.

두 예시를 모두 알아보자.

 

F12를 눌러 개발자 도구를 열고, 어제와 마찬가지로 원하는 위치의 element를 눌러 해당 코드로 이동한다.

커서가 올라가 있는 버튼을 누른 뒤, 숫자 1에 커서를 올려 클릭하면 랭크에 대한 html소스로 이동한다.

<span class="chart-element__rank__number">1</span>

이제 driver 에서 위의 값을 찾아오는 코드를 알아보자.

 

  1. class name으로 읽는 방법.
  2. xpath를 통해 읽는 방법

우선 바로 알 수 있는 class_name으로 접근해보자.

driver.find_elements_by_class_name('chart-element__rank__number')

직관적인 명령어다. elements를 찾아라 class name으로.

중요한것은, elements인데, rank__number에 해당하는 클래스네임을 모두 찾고싶으면, elements를 사용하고

그렇지 않다면 element를 사용한다. 

bs4의 find_all 과 find 의 차이라고 생각하면 쉽다.

 

메소드에서 알 수 있듯, element는 해당 객체 한개를, elements는 리스트에 객체들을 담아서 반환해준다.

물론 저대로 출력한다면, 이해할 수 없는 클래스 객체만 나오는데, 여기서 우리가 원하는 값 ( 이 예시에서는 숫자 )을

얻으려면 .text를 사용하면 된다.

 

위의 코드를 그대로 썼다면, 리스트로 반환되므로 앞선 포스트에서 사용한 리스트 컴프리헨션을 사용해 숫자만 리스트에 담아보자

[rank.text for rank in driver.find_elements_by_class_name('chart-element__rank__number')]

나의 경우에 어떤 이유인지 103개가 뽑혀있다.

해당 페이지의 소스가 크게 달라지지 않을거라 생각하고, 뒤에 세 개는 리스트 인덱싱으로 빼자.

[rank.text for rank in driver.find_elements_by_class_name('chart-element__rank__number')][:-3]

 

자. 클래스명으로 순위를 추출해냈다.

이제 xpath를 이용하여 동일한 수행을 해보자.

 

위에서 1에 해당하는 소스에서 우클릭 > Copy > Copy XPath를 눌러 XPath를 복사하자.

driver.find_elements_by_xpath(XPATH)

자, 복사한 XPath로 elements를 찾아보자.

 

우리는 class name으로 찾았을 때 처럼, 랭크에 해당하는 값이 여러개 나오기를 기대했다.

하지만, 어떤가? 여러개를 담으려 리스트에 넣었지만 초라하게 1이라는 숫자 한 개만 들어가있다.

 

이렇게 알 수 있듯, XPath는 어떤 특징을 가지는게 아니라, 해당하는 유니크한 위치를 지정한다는 것을 알 수 있다.

그럼 XPath를 통해서는 랭크를 얻을 수 없을까?

 

숫자 2에 해당하는 XPath를 알아보자. 

1에 해당하는 xpath와 매우 유사해보인다. 

편법이긴 하지만, for 문을 통해서 변화는 위치만 바꿔서 담아보자.

lst = []
for i in range(1,101):
    lst.append(driver.find_element_by_xpath(f'//*[@id="charts"]/div/div[7]/div/ol/li[{i}]/button/span[1]/span[1]').text)

 

앗...

 

잘 가다가 중간에 에러가 나온다.

1~10까지는 잘 들어왔는데, 11에 해당하는 XPath가 없는 것 같다.

10위까지 끊고 광고를 넣어서 해당 XPath가 없다. i가 10일때마다  1씩 더해주면 올바르게 작동할까?

 

lst = []
tmp = -1
for i in range(1,101):
    if i%10 == 1:
        tmp += 1
    lst.append(driver.find_element_by_xpath(f'//*[@id="charts"]/div/div[7]/div/ol/li[{i+tmp}]/button/span[1]/span[1]').text)

 

이렇게까지 할 일인가 싶지만. 일단 완성했다.

빈 리스트를 만들고, 순위에 해당하는 XPath가 li[]안에 숫자만 바꿔주면 된다.

10이 증가할 때마다 한개씩 건너뛰어야 하므로 임시변수 tmp를 만들고, -1을 넣어준다.

10으로 나누어 떨어진 나머지가 1일 때마다 1씩 더해주기 때문에, 초기값이 -1이어야 i+tmp를 했을 때,

십의자리가 없어도 i + tmp ==> i +0 이 된다.

 

다른 좋은 방법이 있다면 그렇게 써도 좋다. 코드에 정답은 없으니

 

이렇게 1부터 100까지 숫자를 얻어왔다. 동일한 방법으로 가수와 제목도 얻을 수 있다.

 

이전 포스트에서는 결과만 보여줬지만, pandas의 dataframe에 어떻게 넣어야 하는지도 공유해본다.

import pandas as pd
## pandas 패키지가 없다면 pip install pandas 를 통해 설치해야한다.

Billboard = pd.DataFrame(columns = ['Rank','Title','Artist']
rank = []   # 여기엔 
title = []  # 앞에서 각각의 변수명에 해당하는
artist = [] # 크롤링한 결과를 담아준다.
###############
#####크롤링######
###############
Billboard['Rank'] = rank
Billboard['Title'] = title
Billboard['Artist'] = artist

Billboard.to_csv('today_billboard_chart.csv',index = 0,encoding='utf-8')

 

이렇게 빌보드 hot100 을 얻어오는 파이썬 코드를 만들고, 결과를 csv로 바꿔 저장까지 완료했다.

 

반응형