Web Crawling 연습

박상영·2020년 6월 4일
0
  • 빌보드차트

처음 해보기도 하지만, 잘 이해하지못해 3일내내 이 코드만 붇잡고있었다.

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep
import re
import csv

csv_filename = "billboard_chart.csv"
csv_open = open(csv_filename, "w+", encoding="utf-8")
csv_writer = csv.writer(csv_open)
csv_writer.writerow(("rank", "title", "singer", "img"))

먼저 크롤링하여 받을 값들을 저장하기위해 csv를 설정해주었다, .writerow를 사용하여 해당csv의
값들의 title을 정해주었다.

site_url = "https://www.billboard.com/charts/hot-100"
driver = webdriver.Chrome("/usr/local/bin/chromedriver")
driver.implicitly_wait(20)
driver.get(site_url)

그다음 Chromedriver를 사용할 준비를 한다.
open 할 page의 url 값을 변수에 저장하고 그다음 driver에는 chromedriver의 경로를 입력해주어 그경로로 가서 실행하라는 명령을 입력했다.
하지만 막상 실행하려하니 chromedriver파일에서 문제가 생겼다. " 개발자를 확인할 수 없기 때문에“chromedriver”를 열 수 없습니다." 라고 에러가 났다.
이 에러를 풀수있는방법은 2가지가있다.
xattr -d com.apple.quarantine <name-of-executable> 이나
spctl --add --label 'Approved' <name-of-executable> 이 둘중 하나의 command 를 shell 에 입력해주면 위와같은 Error는 해결된다.

site_body = driver.find_element_by_css_selector("body")

"site_body" 에 페이지를 열고 element의 css_selector로 "body" 를넣은 이유는 개발자도구의 elements의 body부터 밑으로 내려가야 로딩을 다 받을수있기때문이다.

for i in range(20):
    site_body.send_keys(Keys.PAGE_DOWN)
    sleep(3)

send_keys()를 이용하여 해당페이지를 열었을때 밑으로 내려가면서 로딩을 다 하기위해 넣었고 sleep의 사용은 너무 빨리 내려가게되면 로딩이 되기전에 내려가기때문제 정확하게 얻고싶은 값을 얻지못했기때문이다.

html = driver.page_source

해당 page의 html 전부를 가지고 온다.

driver.quit()

그다음 웹페이지에서 볼일은 다봤으니 꺼주는quit()를 사용하여 열었던 웹페이지를 꺼준다.


bs = BeautifulSoup(html, "html.parser")

이제 BeautifulSoup을 사용할 차례이다. page의 html을 불러온 값을 "html.parser"를 사용하여 html코드를 python이 이해하는 객체 구조로 바꾸어준다.

total_list = bs.find_all("li", {"class" : re.compile("chart-list__element*")})

그다음 cvs에 저장해야될 내용이 4개이므로 하나하나 저장하지않고, for문을 사용하기위해 총list에 원하는 값을의 상위태그를 지정하여 상위태그의 값들을 저장해주었다.

for i in total_list:
    rank = i.select_one("li > button > span.chart-element__rank.flex--column.flex--xy-center.flex--no-shrink > span.chart-element__rank__number").text
    song = i.select_one("li > button > span.chart-element__information > span.chart-element__information__song.text--truncate.color--primary").text
    artist = i.select_one("li > button > span.chart-element__information > span.chart-element__information__artist.text--truncate.color--secondary").text
    img = i.select_one("li > button > span.chart-element__image.flex--no-shrink")["style"].split('"')[1]
    #print(img)
    csv_writer.writerow((rank, song, artist, img))

csv_open.close()

for문을 사용하여 select_one(하나의 값만 선택)에 selector값을 넣어주고 뒤에 .text를 사용하여 해당 text의 값만 저장되도록 해주었다.
하지만 img의 url을 얻기위해선 class뒤에 style이 또 있었기떄문에 selector값을 입력하고 그 뒤에 [attribute]를 주었다.
하지만 attribute값을 주었다고해서 url이 바로 나오진않았고, split('"')을 사용하여 사이사이에 "을 넣어주고 index를 사용하여 원하는 url값의 위치를 넣어 img값을 얻을수있었다.

다른 rank, song_title, artist의 값은 찾기쉬웠지만,
img의 url값을 얻기위해 2~3일을 삽질한거같다. 하지만, 이 삽질을 통해 다양한 방법을 사용해보았다.
예를들어
정규식표현법(re)를 사용하여

for i in total_list:
    rank = i.find("span", {"class" : re.compile("chart~~~)~~

이런식으로 find와 re.compile을 이용한 값을 추출해보았고,
zip()을 이용하여 미리 select(selector)로 받은 값들을 zip(a, b, c) 로 묶어

for i in zip(a, b, c):
    rank = i[0].text
    .
    .  

i의 인덱스로 접근하는 방식을 사용해보았다. 결국 img를 얻기위해 많은 삽질을 하였지만, 다양한 접근방식을 활용하여 해본결과 많은 검색도 하게되었고, 그 경험이 있었기때문에 "스타벅스 웹크롤링" 과제를 쉽게 풀수있었다. 아직 사용못해본 방식들이 많고 정규식표현법은 더욱더 다양하기때문에 좀더 작성해보고 이해해보려 한다.

profile
backend

0개의 댓글