사전 스터디 때 진행한 내용으로 아래 링크 참조
https://velog.io/@blakekim93/TIL-No.13-Python-네이버-뉴스에서-헤드라인-뉴스-목록-크롤링해서-저장하기
https://velog.io/@blakekim93/3주차-Python-크롤링-코드-마감.-전체-코드-및-실행-화면
Selenium은 주로 웹앱을 테스트하는데 이용하는 프레임워크다. webdriver라는 API를 통해 운영체제에 설치된 Chrome등의 브라우저를 제어하게 된다. 브라우저를 직접 동작시킨다는 것은 JavaScript를 이용해 비동기적으로 혹은 뒤늦게 불러와지는 컨텐츠들을 가져올 수 있다는 것이다. 즉, ‘눈에 보이는’ 컨텐츠라면 모두 가져올 수 있다는 뜻이다. 우리가 requests에서 사용했던 .text의 경우 브라우저에서 ‘소스보기’를 한 것과 같이 동작하여, JS등을 통해 동적으로 DOM이 변화한 이후의 HTML을 보여주지 않는다. 반면 Selenium은 실제 웹 브라우저가 동작하기 때문에 JS로 렌더링이 완료된 후의 DOM결과물에 접근이 가능하다.
driver.page_source: 브라우저에 보이는 그대로의 HTML, 크롬 개발자 도구의 Element 탭 내용과 동일.
requests 통해 가져온 req.text: HTTP요청 결과로 받아온 HTML, 크롬 개발자 도구의 페이지 소스 내용과 동일.
다음 내용은 작성한 코드를 기반으로 작성할 예정.
빌보드 차트 100위에 있는 노래와 가수 그리고 이미지의 링크까지 크롤링하는 코드
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
# 스크롤 다운을 위해 import함
from selenium.webdriver.common.keys import Keys
import pandas,time
# options = webdriver.ChromeOptions()
# options.add_argument('headless') # 브라우저 창을 열지 않고 실행할 수 있는 옵션
# driver = webdriver.Chrome('/Applications/chromedriver', chrome_options=options) options 사용시 이렇게 작성해야함
driver = webdriver.Chrome('/Applications/chromedriver')
driver.implicitly_wait(10)
url = 'https://www.billboard.com/charts/hot-100'
driver.get(url)
body = driver.find_element_by_css_selector('body')
for i in range(30):
body.send_keys(Keys.PAGE_DOWN)
time.sleep(0.1)
html = driver.page_source
bsObject = BeautifulSoup(html, 'html.parser')
driver.close()
musics = bsObject.select(
'div#charts > div > div.chart-list.container > ol > li > button > span.chart-element__information > span.chart-element__information__song.text--truncate.color--primary'
)
artists = bsObject.select(
'div#charts > div > div.chart-list.container > ol > li > button > span.chart-element__information > span.chart-element__information__artist.text--truncate.color--secondary'
)
imgs = bsObject.select(
'div#charts > div > div.chart-list.container > ol > li > button > span.chart-element__image'
)
hotMusic = []
hotArtist = []
images = []
for music in musics:
hotMusic.append(music.text) # text를 붙이지 않으면 태그 정보까지 함께 출력
for artist in artists:
hotArtist.append(artist.text)
for img in imgs:
img = img['style'] # style = "여기" 에 해당하는 값을 가져온다.
img_url = img[img.find('http'):img.rfind('\"')] # "여기"에서 http로 시작하고 \까지 가져온다.
images.append(img_url)
hot100 = []
for i in range(len(hotMusic)):
hot100.append([i+1, hotMusic[i], hotArtist[i], images[i]])
#time = datetime.today().strftime("%Y/%m/%d %H:%M:%S")
data = pandas.DataFrame(hot100)
data.columns = ['RANK', 'MUSIC', 'ARTIST', 'IMG_LINK']
print(data)
data.to_csv('billoboard_hot100.csv', mode = 'w', encoding='euc-kr', index=False)
Keys.PAGE_DOWN
을 하는 이유는 html문서에는 해당 공간에 style="inline-block"
이라고만 입력되어 있고 이미지 url
이 담겨 있지 않다. 즉 JavaScript
에 의해 구현된 부분으로 이미지 링크를 받아오기 위해서는 Selenium
을 통해 해당 이미지를 랜더링한 후에 받아와야 이미지 url
이 담겨 있게 된다.
또한 for img in imgs:
부분에서 img['style']
로 style
에 지정된 값을 가져올 수 있던 이유는 img
가 bs4.element.Tag
type
으로 그 안의 내용을 가져오기 위해서는 dictionary
의 key
값을 통해 가져오는 것처럼 가져올 수 있다.
img['style']
로 가져온 값은 str
이기 때문에 slicing
이 가능하다.
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
import pandas
driver = webdriver.Chrome('/Applications/chromedriver') # chromedriver 경로 지정
url = 'https://www.starbucks.co.kr/menu/drink_list.do' # 불러올 주소
driver.get(url) # driver에 전달
html = driver.page_source
bsObject = BeautifulSoup(html, 'html.parser')
menu_name = bsObject.select(
'div#container > div.content > div.product_result_wrap.product_result_wrap01 > div > dl > dd:nth-child(2) > div.product_list > dl > dd > ul > li > dl > dt > a > img'
)
name = []
img = []
menu = []
for i in menu_name:
name.append(i.get("alt"))
driver.implicitly_wait(2)
img.append(i.get("src"))
driver.implicitly_wait(2)
for i in range(len(name)):
menu.append([ name[i], img[i] ])
data = pandas.DataFrame(menu)
data.columns = ['NAME', 'IMG_LINK']
print(data)
data.to_csv('starbucks_menu.csv', mode = 'w', encoding='euc-kr', index=False)
스타벅스 코리아 페이지 또한 메뉴에 대해서는 JavaScript
로 구현이 되어 있기에 Selenium
을 사용해야 한다. (무거워서 CPU
가 뜨거워지지만 어쩔 수 없다.ㅠㅠ)