데이터 엔지니어링 과정/python

[13일차] 웹 스크레이핑

오리는짹짹 2023. 1. 6. 16:40
목차
1. 웹 브라우저로 웹 사이트 접속하기
2. 웹 스크레이핑을 위한 기본 지식
3. 웹 사이트에서 데이터 가져오기

 

1. 웹 브라우저로 웹 사이트 접속하기

1. 하나의 웹 사이트에 접속하기

(1) 웹 브라우저를 열어서 사이트에 접속하기

import webbrowser

url = 'www.naver.com'
webbrowser.open(url)
>>> True

➡ 네이버 창이 열렸다!

(2) 웹 브라우저에 검색어 입력하여 오픈하기

  • 네이버에서 파이썬 검색한 걸 열어보겠습니다☺
import webbrowser

naver_search_url = "http://search.naver.com/search.naver?query="
search_word = "파이썬"
url = naver_search_url + search_word

webbrowser.open(url)
>>> True

➡ 파이썬을 검색한 창이 열렸다!

  • 구글에서 검색어 입력하여 오픈해볼까? 
import webbrowser

google_url = "www.google.com/#q="
search_word = 'python'
url = google_url + search_word

webbrowser.open(url)
>>> True

➡ 🤔 True라고 뜨지만, 구글 첫 화면이 뜨고 검색어 입력된 창은 열리지 않는다. 

import webbrowser

google_url = "www.google.com/search?q="
search_word = 'python'
url = google_url + search_word

webbrowser.open(url)
>>> True

➡ 구글에 python이 검색된 창이 열렸다.

👀 위 두 예시만 보더라도, 네이버는 search.naver?query= 였고 구글은 search?q= 이다. 각 포털마다 검색어를 입력받는 형식이 다르다는 걸 알 수 있다.

2. 여러 개의 웹 사이트에 접속하기

🐰 여러 개?! 그러면 for문을 돌리겠군

import webbrowser

urls = ['www.naver.com', 'www.daum.net', 'www.google.com']

for url in urls:
    webbrowser.open_new(url)

➡ open_new() 를 사용하면, 새로운 창을 불러와준다🤍

(1) 여러 개의 검색어 입력하기

import webbrowser

google_url = 'www.google.com/search?q='
search_words = ['통영 네컷사진', '러브캐쳐']

for search_word in search_words:
    webbrowser.open_new(google_url + search_word)

🐰 내일 통영 가는데 네컷 사진 찍고 싶어요.... 통영 가는 길에 러브캐쳐 봐야쥐 우하하

 

2. 웹 스크레이핑을 위한 기본 지식

1. 데이터의 요청과 응답 과정

 

2. HTML의 기본 구조

(1) HTML 코드를 작업 폴더 (C:/myPyCode)에 저장

%%writefile C:\myPyCode\HTML_example.html
<!doctype html>
<html>
    <head>
    	<meta charset="utf-8">
        <title>이것은 HTML 예제</title>
    </head>
    <body>
        <h1>출간된 책 정보</h1>
        <p id = "book_title"> 내일은 실험왕 39: 영양소와 소화 </p>
        <p id = "author">스토리a.</p>
        <p id = "publisher">미래엔아이세움</p>
        <p id = "year">2017</p>
    </body>
</html>

>>> Overwriting C:\myPyCode\HTML_example.html

🐰 내가 좋아했던 만화책..ㅎㅎㅎ 이게 벌써 시즌2까지 나왔다고 하네유...... 우리 조카 사줘야겠다

  • p 부분 수정
%%writefile C:\myPyCode\HTML_example2.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>이것은 HTML 예제</title>
    </head>
    <body>
        <h1>출간된 책 정보</h1>
        <p>내일은 실험왕 39: 영양소와 소화 </p>
        <p>스토리a.</p>
        <p>미래엔아이세움</p>
        <p>2017</p>
    </body>
</html>

➡ 결과는 같다. 그럼 왜 아이디를 입력한걸까?

🐰 같아보여도 다를 수 있으니까!! 늘 주의하고 다시 살펴봐야해

3. 웹 페이지의 HTML 소스 갖고 오기

(1) request를 이용하여 구글 페이지 가져오기

import requests

r = requests.get("https://google.co.kr")

r
>>> <Response [200]>

👀 <Response [200]>이면 잘 접속됐다는 것! 

(2) 가져온 페이지 내용 확인하기

r.text[0:100]
>>> '<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ko"><head><meta content'

.➡ 100 미만까지 보여드려용

⬇ 🐰위에 코드랑 같이 붙이면 이렇게 코드를 짤 수 있다! 

import requests

html = requests.get("https://www.google.co.kr").text

html[0:100]
>>> '<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ko"><head><meta content'

4. HTML 소스코드를 분석하고 처리하기

(1) 데이터 찾고 추출하기

👨🏻‍💻파싱(Parsing) = HTML의 코드 구문을 이용하고 요소별로 HTML을 분류하는 것

  • BeautifulSoup 파싱을 더 수월하게 해주는 라이브러리
from bs4 import BeautifulSoup

# 테스트용 html 코드
html = """<html><body><div><span>\
        <a href=https://www.naver.com>naver</a>\
        <a href=https://www.google.com>google</a>\
        <a href=https://www.daum.net/>daum</a>\
        </span></div></body></html>"""

# BeautifuSoup를 이용해 HTML 소스를 파싱
soup = BeautifulSoup(html, 'lxml')

soup
>>> <html><body><div><span> <a href="https://www.naver.com">naver</a> <a href="https://www.google.com">google</a> <a href="https://www.daum.net/">daum</a> </span></div></body></html>

👀 차이가 크게 두드러 보이지는 않지만, 분명 차이가 존재한다!! \가 사라진 것도 차이지 암 그렇고 말고 

  • prettify 메서드 피싱 결과를 보기 좋게 HTML의 구조의 형태로 확인
print(soup.prettify())

>>> <html>
     <body>
      <div>
       <span>
        <a href="https://www.naver.com">
         naver
        </a>
        <a href="https://www.google.com">
         google
        </a>
        <a href="https://www.daum.net/">
         daum
        </a>
       </span>
      </div>
     </body>
    </html>
  • .find() 첫번째 a 태그 찾은 후 a 태그 요소 전체를 반환
soup.find('a')

>>> <a href="https://www.naver.com">naver</a>
  • .find().get_text() 태그와 속성을 제거하고 텍스트 문자열만 반환
soup.find("a").get_text()
>>> 'naver'
  • .find_all() 첫 번째 a 태그를 찾은 후 모든 a 태그를 찾아서 반환
soup.find_all('a')

>>> [<a href="https://www.naver.com">naver</a>,
     <a href="https://www.google.com">google</a>,
     <a href="https://www.daum.net/">daum</a>]
  • 혼합해서 사용하기
site_names = soup.find_all('a')
for site_name in site_names:
    print(site_name.get_text())
    
>>> naver
    google
    daum

😎 테스트용 예제 2

from bs4 import BeautifulStoneSoup

# 테스트용 HTML 코드
html2 = """
<html>
 <head>
  <title>작품과 작가 모임</title>
 </head>
 <body>
  <h1> 책 정보</h1>
  <p id = "book_title">토지</p>
  <p id = "author">박경리</p>
  
  <p id = "book_title">태백산맥</p>
  <p id = "author">조정래</p>
  
  <p id = "book_title">감옥으로부터의 사색</p>
  <p id = "author">신영복</p>
 </body>
</html>"""

# BeautifuSoup를 이용해 HTML 소스를 파싱
soup2 = BeautifulSoup(html2, 'lxml')
  • tilte title 추출하기
soup2.title
>>> <title>작품과 작가 모임</title>
  • body body 추출하기
soup2.body
>>> <body>
    <h1> 책 정보</h1>
    <p id="book_title">토지</p>
    <p id="author">박경리</p>
    <p id="book_title">태백산맥</p>
    <p id="author">조정래</p>
    <p id="book_title">감옥으로부터의 사색</p>
    <p id="author">신영복</p>
    </body>
  • h1 추출하기
soup2.body.h1
>>> <h1> 책 정보</h1>
  • p태그 가져오기
soup2.find_all("p")
>>> [<p id="book_title">토지</p>,
     <p id="author">박경리</p>,
     <p id="book_title">태백산맥</p>,
     <p id="author">조정래</p>,
     <p id="book_title">감옥으로부터의 사색</p>,
     <p id="author">신영복</p>]

🐰 리스트화해서 모든 p 들을 불러모았군!!

  • 구분해서 가져오기 위해서는 속성도 함께 지정해 줄 수 있다.
    BeautifulSoup.find_all('태크', '속성')
    BeautifulSoup.find('태크', '속성')
soup2.find('p', ({'id':'book_title'}))
>>> <p id="book_title">토지</p>

soup2.find('p', ({'id':'author'}))
>>> <p id="author">박경리</p>

soup2.find_all('p',({'id':'book_title'}))
>>> [<p id="book_title">토지</p>,
     <p id="book_title">태백산맥</p>,
     <p id="book_title">감옥으로부터의 사색</p>]
     
soup2.find_all('p',({'id':'author'}))
>>> [<p id="author">박경리</p>, <p id="author">조정래</p>, <p id="author">신영복</p>]
  • 텍스트만 뽑아서 묶어보기
from bs4 import BeautifulSoup

soup2 = BeautifulSoup(html2, "lxml")

book_titles = soup2.find_all('p', {'id':'book_title'})
authors = soup2.find_all('p', {'id':'author'})

for book_title, author in zip(book_titles, authors):
    print(book_title.get_text() + '/' + author.get_text())
    
>>> 토지/박경리
>>> 태백산맥/조정래
>>> 감옥으로부터의 사색/신영복
  • css (Cascading Style Sheets) 선택자를 이용하기
    select('태그 및 속성') 입력하여 사용한다.
soup2.select('body h1')
>>> [<h1> 책 정보</h1>]

# p 태그를 포함한 요소를 모두 갖고 오기
soup2.select('body p')
>>> [<p id="book_title">토지</p>,
     <p id="author">박경리</p>,
     <p id="book_title">태백산맥</p>,
     <p id="author">조정래</p>,
     <p id="book_title">감옥으로부터의 사색</p>,
     <p id="author">신영복</p>]
     
# 위 소스의 경우 p는 body에만 있으므로 생략해도 같은 값을 얻을 수 있다.
soup2.select('p')
>>> [<p id="book_title">토지</p>,
     <p id="author">박경리</p>,
     <p id="book_title">태백산맥</p>,
     <p id="author">조정래</p>,
     <p id="book_title">감옥으로부터의 사색</p>,
     <p id="author">신영복</p>]
  • 태그 안의 속성과 속성 값을 이용해 세밀하게 추출하기
    태그.Class_속성값 태그 #id_속성값
soup2.select('p#book_title')
>>> [<p id="book_title">토지</p>,
     <p id="book_title">태백산맥</p>,
     <p id="book_title">감옥으로부터의 사색</p>]
     
soup2.select('p#author')
>>> [<p id="author">박경리</p>, <p id="author">조정래</p>, <p id="author">신영복</p>]

😎 Class 속성이 있는 HTML 예제

%%writefile C:\myPyCode\HTML_example_my_site.html
<!doctype html>
<html>
 <head>
    <head>
        <meta charset="utf-8">
        <title>사이트 모음</title>
    </head>
    <body>
        <p id="title"><b>자주 가는 사이트 모음</b></p>
        <p id="contents">이곳은 자주 가는 사이트를 모아둔 곳입니다.</p>
        <a href="http://naver.com" class "portal" id="naver">네이버</a> <br>
        <a href="http://google.com" class "search" id="google">구글</a> <br>
        <a href="http://daum.net" class "portal" id="daum">다음</a> <br>
        <a href="http://nl.go.kr" class "government" id="nl">국립중앙도서관</a><br>
    </body>
</html>

>>> Writing C:\myPyCode\HTML_example_my_site.html
  • 위에서 작성한 html 저장하기
f = open('C:/myPyCode/HTML_example_my_site.html', encoding='utf-8')

html3 = f.read()
f.close()

soup3 = BeautifulSoup(html3, "lxml")
  • a 요소 모두 가져오기
soup3.select('a')

>>> [<a class="portal" href="http://naver.com" id="naver">네이버</a>,
     <a class="search" href="http://google.com" id="google">구글</a>,
     <a class="portal" href="http://daum.net" id="daum">다음</a>,
     <a class="government" href="http://nl.go.kr" id="nl">국립중앙도서관</a>]
  • a이면서 class가 portal인 요소만 가져오기
soup3.select('a.portal')
>>> [<a class="portal" href="http://naver.com" id="naver">네이버</a>,
     <a class="portal" href="http://daum.net" id="daum">다음</a>]

(2) 웹 브라우저의 요소 검사

  • a 태그를 포함하는 요소 중 id 속성이 naver인 요소 선택
soup3.select('a#naver')
>>> [<a class="portal" href="http://naver.com" id="naver">네이버</a>]

(3) 줄 바꿈으로 가독성 높이기

%%writefile C:\myPyCode\br_example_constitution.html
<!doctype html>
<html>
    <head>
    <title>줄 바꿈 테스트 예제</title>
    </head>
    <body>
    <p id="title"><b>대한민국헌법</b></p>
    <p id="content">제1조 <br/> 1. 대한민국은 민주공화국이다.<br/>2. 대한민국의 주권은 모든 국민에게 있고, 모든 권력은 국민으로부터 나온다.</p>
    <p id="content">제2조 <br/> 1. 대한민국의 국민이 되는 요건은 법률로 정한다.<br/> 2. 국가는 법률이 정하는 바에 의하여 재외국민을 보호할 의무를 진다. </p>
    </body>
</html>

>>> Overwriting C:\myPyCode\br_example_constitution.html
  • 텍스트만 추출하여 출력
from bs4 import BeautifulSoup

f = open("C:/myPyCode/br_example_constitution.html",encoding='utf-8')

html_source = f.read()
f.close()

soup = BeautifulSoup(html_source,"lxml")

title = soup.find('p',{'id' : 'title'})
contents = soup.find_all('p',{'id' : 'content'})

print(title.get_text())

for content in contents:
    print(content.get_text())
    
>>> 대한민국헌법
>>> 제1조  1. 대한민국은 민주공화국이다.
            2. 대한민국의 주권은 모든 국민에게 있고, 모든 권력은 국민으로부터 나온다.
>>> 제2조  1. 대한민국의 국민이 되는 요건은 법률로 정한다.
             2. 국가는 법률이 정하는 바에 의하여 재외국민을 보호할 의무를 진다.
  • br 태그를 찾아 파이썬의 줄바꿈 문자 (\n)로 바꾸기
    find_result = BeautifulSoup.find('태그')
    find_result.replace_with('새 태그나 문자열')
html1 = '<p id="content">제1조 <br/> 1. 대한민국은 민주공화국이다. <br/>2. 대한민국의 주권은 모든 국민에게 있고, 모든 권력은 국민으로부터 나온다.</p>'

soup1 =BeautifulSoup(html1, "lxml")

print("==> 태그 p로 찾은 요소들")
content1= soup1.find('p', {"id" : "content"})
print(content1)

br_content = content1.find("br")
print("==> 결과에서 태그 br로 찾은 요소:", br_content)

br_content.replace_with("\n")
print("==> 태그 br을 개행문자로 바꾼 결과")
print(content1)

>>> ==> 태그 p로 찾은 요소들
    <p id="content">제1조 <br/> 1. 대한민국은 민주공화국이다. <br/>2. 대한민국의 주권은 모든 국민에게 있고, 모든 권력은 국민으로부터 나온다.</p>
    ==> 결과에서 태그 br로 찾은 요소: <br/>
    ==> 태그 br을 개행문자로 바꾼 결과
    <p id="content">제1조 
     1. 대한민국은 민주공화국이다. <br/>2. 대한민국의 주권은 모든 국민에게 있고, 모든 권력은 국민으로부터 나온다.</p>
  • 전체 태그에 반영하기
soup2 = BeautifulSoup(html1, "lxml")
content2 = soup2.find('p', {'id' : 'content'})

br_contents = content2.find_all("br")
for br_content in br_contents:
    br_content.replace_with("\n")
print(content2)

>>> <p id="content">제1조 
     1. 대한민국은 민주공화국이다. 
    2. 대한민국의 주권은 모든 국민에게 있고, 모든 권력은 국민으로부터 나온다.</p>
  • 해당 기능을 함수로 만들기
def replace_newline(soup_html):
    br_to_newlines = soup_html.find_all("br")
    for br_to_newline in br_to_newlines:
        br_to_newline.replace_with("\n")
    return soup_html
  • 함수와 get_text()를 이용하여 완성하기
soup2 = BeautifulSoup(html1, "lxml")
content2 = soup2.find('p',{'id':"content"})
content3 = replace_newline(content2)

print(content3.get_text())
>>> 제1조 
     1. 대한민국은 민주공화국이다. 
    2. 대한민국의 주권은 모든 국민에게 있고, 모든 권력은 국민으로부터 나온다.
  • 소스코드에 파이썬 코드를 적용하여 최종 완성하기
from bs4 import BeautifulSoup

soup = BeautifulSoup(html_source, "lxml")

title = soup.find('p', {'id' : "title"})
contents = soup.find_all('p', ({'id' : "content"}))

print(title.get_text(), "\n")

for content in contents:
    content1 = replace_newline(content)
    print(content1.get_text(),"\n")
    
    
>>> 대한민국헌법 

>>> 제1조 
    1. 대한민국은 민주공화국이다.   
    2. 대한민국의 주권은 모든 국민에게 있고, 모든 권력은 국민으로부터 나온다. 

>>> 제2조 
     1. 대한민국의 국민이 되는 요건은 법률로 정한다.       
     2. 국가는 법률이 정하는 바에 의하여 재외국민을 보호할 의무를 진다.

3. 웹 사이트에서 데이터 가져오기

1. 웹 스크레이핑 시 주의 사항

  • 쉬운 스크레이핑을 위해 데이터를 얻기 위한 규칙을 발견할 수 있어야 한다.
  • 웹 사이트에 너무 빈번하게 접근하면 안된다. 제한 시간인나 차단이 있을 수 있다.
  • 코드는 변경 될 수 있으므로 필요한 경우 지속 관리 해야 한다.
  • 저작권이 있을 수 있으니 조심해야 한다.

2. 순위 데이터를 가져오기

(1) 영화 순위 : 한국 사용자들의 방문 정보를 바탕으로 웹 사이트의 순위를 알려준다.

import requests
from bs4 import BeautifulSoup

base_url = 'https://movie.naver.com/movie/sdb/rank/rmovie.naver'
date = '20230106'
url = base_url + '?sel=cnt&tg=0&date='+date # 날짜를 지정해 URL 생성

html = requests.get(url).text
soup = BeautifulSoup(html, 'lxml')

print(url)
>>> https://movie.naver.com/movie/sdb/rank/rmovie.naver?sel=cnt&tg=0&date=20230106
  • 랭킹 출력
movies = soup.select('div.tit3')
movies[0:5] # 전체 중 일부만 출력

>>> [<div class="tit3">
 <a href="/movie/bi/mi/basic.naver?code=74977" title="아바타: 물의 길">아바타: 물의 길</a>
 </div>,
 <div class="tit3">
 <a href="/movie/bi/mi/basic.naver?code=184509" title="영웅">영웅</a>
 </div>,
 <div class="tit3">
 <a href="/movie/bi/mi/basic.naver?code=223800" title="더 퍼스트 슬램덩크">더 퍼스트 슬램덩크</a>
 </div>,
 <div class="tit3">
 <a href="/movie/bi/mi/basic.naver?code=208508" title="젠틀맨">젠틀맨</a>
 </div>,
 <div class="tit3">
 <a href="/movie/bi/mi/basic.naver?code=201642" title="스위치">스위치</a>
 </div>]
  • 텍스트만 추출하기
movies[0].find('a')
>>> <a href="/movie/bi/mi/basic.naver?code=74977" title="아바타: 물의 길">아바타: 물의 길</a>
  • 영화 제목과 주소만 뽑아내기
ranking_title = movies[0].find('a')['title'] # 태그 a의 요소 추출 후 title 속성 추출
ranking_href = movies[0].find('a')['href'] # 태그 a의 요소 추출 후 href 속성 추출

[ranking_title, ranking_href]
>>> ['아바타: 물의 길', '/movie/bi/mi/basic.naver?code=74977']
  • 코드 통합하기
import pandas as pd

title_hrefs = [] # 빈 리스트 생성
base_url = 'https://movie.naver.com'
for movie in movies:
    ranking_title = movie.find('a')['title'] # 태그 a의 요소 추출 후 title 속성 추출
    ranking_href = movie.find('a')['href'] # 태그 a의 요소 추출 후 href 속성 추출
    
    title_hrefs.append([ranking_title, base_url + ranking_href]) # 리스트의 항목 추가
    
# 리스트를 이용해 DataFrame 데이터 생성 (영화 순위를 index로 지정)
ranking = range(1, len(movies)+1) # 영화 순위 생성
df_movie = pd.DataFrame(title_hrefs, index = ranking, columns = ['영화 제목', '링크'])

# head()를 이용해 일부만 출력 (링크 열 너비 지정)
df_movie.head(10).style.set_properties(subset=['링크'], **{'width' : '400px'})

#df_movie # 전체 출력

(2) 주간 음악 순위 : 벅스 music에서 종합 음악 순위 정보 출력하기

import requests 
from bs4 import BeautifulSoup

url = "https://music.bugs.co.kr/chart/track/week/total?chartdate=20221223" #주간 뮤직
# url = "https://music.bugs.co.kr/chart/track/realtime/total" # 실시간 뮤직 차트
# url = "https://music.bugs.co.kr/chart/track/day/total" # 일간 뮤직 차트
# url = "https://music.bugs.co.kr/chart/track/week/total" # 주간 뮤직 차트

html_music = requests.get(url).text
soup_music = BeautifulSoup(html_music, "lxml")

# p 태그의 요소 중에서 calss 속성 값이 "title" 인 것을 찾고
# 그 안에서 a 태그의 요소를 추출
titles = soup_music.select('p.title a')
titles[0:7]

>>> [<a adultcheckval="1" aria-label="새창" href="javascript:;" onclick="bugs.wiselog.area('list_tr_09_chart');bugs.music.listen('6184997',true);
 " title="Ditto">Ditto</a>,
 <a adultcheckval="1" aria-label="새창" href="javascript:;" onclick="bugs.wiselog.area('list_tr_09_chart');bugs.music.listen('32732271',true);
 " title="NOT SORRY (Feat. pH-1) (Prod. by Slom)">NOT SORRY (Feat. pH-1) (Prod. by Slom)</a>,
 <a adultcheckval="1" aria-label="새창" href="javascript:;" onclick="bugs.wiselog.area('list_tr_09_chart');bugs.music.listen('32731774',true);
 " title="Candy">Candy</a>,
 <a adultcheckval="1" aria-label="새창" href="javascript:;" onclick="bugs.wiselog.area('list_tr_09_chart');bugs.music.listen('6170217',true);
 " title="Hype Boy">Hype Boy</a>,
 <a adultcheckval="1" aria-label="새창" href="javascript:;" onclick="bugs.wiselog.area('list_tr_09_chart');bugs.music.listen('6155092',true);
 " title="사건의 지평선">사건의 지평선</a>,
 <a adultcheckval="1" aria-label="새창" href="javascript:;" onclick="bugs.wiselog.area('list_tr_09_chart');bugs.music.listen('6179181',true);
 " title="ANTIFRAGILE">ANTIFRAGILE</a>,
 <a adultcheckval="1" aria-label="새창" href="javascript:;" onclick="bugs.wiselog.area('list_tr_09_chart');bugs.music.listen('32714302',true);
 " title="WHEN I MOVE">WHEN I MOVE</a>]
  • 타이틀만 추출 후 보기
music_titles = [title.get_text() for title in titles]
music_titles[0:7]
>>> ['Ditto',
     'NOT SORRY (Feat. pH-1) (Prod. by Slom)',
     'Candy',
     'Hype Boy',
     '사건의 지평선',
     'ANTIFRAGILE',
     'WHEN I MOVE']
  • 아티스트 추출하기
# p 태그의 요소 중에서 class 속서 값이 "artist" 인 것을 찾고
# 그 안에서 a 태그의 요소를 추출

artists = soup_music.select('p.artist a')
artists[0:7]

>>> [<a href="https://music.bugs.co.kr/artist/20164333?wl_ref=list_tr_10_chart" onclick="
 " title="NewJeans">NewJeans</a>,
 <a href="https://music.bugs.co.kr/artist/20079471?wl_ref=list_tr_10_chart" onclick="
 " title="이영지">이영지</a>,
 <a href="https://music.bugs.co.kr/artist/80266679?wl_ref=list_tr_10_chart" onclick="
 " title="NCT DREAM">NCT DREAM</a>,
 <a href="https://music.bugs.co.kr/artist/20164333?wl_ref=list_tr_10_chart" onclick="
 " title="NewJeans">NewJeans</a>,
 <a href="https://music.bugs.co.kr/artist/80010025?wl_ref=list_tr_10_chart" onclick="
 " title="윤하(Younha/ユンナ)">윤하(Younha/ユンナ)</a>,
 <a href="https://music.bugs.co.kr/artist/20158908?wl_ref=list_tr_10_chart" onclick="
 " title="LE SSERAFIM (르세라핌)">LE SSERAFIM (르세라핌)</a>,
 <a href="https://music.bugs.co.kr/artist/80023353?wl_ref=list_tr_10_chart" onclick="
 " title="카라(Kara)">카라(Kara)</a>]
music_artists = [artist.get_text() for artist in artists]

🐰혹시 모르니까 알아둬야 하는 것.. ⬇

artists = soup_music.select('p.artist a:not(.more)')
music_artists[0:7]

>>> 'NewJeans',
     '이영지',
     'NCT DREAM',
     'NewJeans',
     '윤하(Younha/ユンナ)',
     'LE SSERAFIM (르세라핌)',
     '카라(Kara)']
  • 종합하여 차트 히스토리에서 곡명과 아티스트 데이터를 추출하고 출력하는 코드
import requests
from bs4 import BeautifulSoup

url = "https://music.bugs.co.kr/chart/track/week/total?chartdate=20221223" #주간 뮤직

html_music = requests.get(url).text
soup_music = BeautifulSoup(html_music, "lxml")

titles = soup_music.select('p.title a')
artists = soup_music.select('p.artist')

music_titles = [title.get_text() for title in titles]
music_artists = [artist.get_text().strip() for artist in artists]

for k in range(10):
    print(f"{k+1}: {music_tiltes[k]} / {music_artists[k]}")
    
>>> 1: Ditto / NewJeans
    2: NOT SORRY (Feat. pH-1) (Prod. by Slom) / 이영지
    3: Candy / NCT DREAM
    4: Hype Boy / NewJeans
    5: 사건의 지평선 / 윤하(Younha/ユンナ)
    6: ANTIFRAGILE / LE SSERAFIM (르세라핌)
    7: WHEN I MOVE / 카라(Kara)
    8: Attention / NewJeans
    9: All I Want for Christmas Is You / Mariah Carey(머라이어 캐리)
    10: After LIKE / IVE (아이브)
  • 곡명과 아티스트를 묶어서 순위별로 할당하기
music_titles_artists = {}
order = 0

for (music_title, music_artist) in zip (music_titles, music_artists):
    order = order + 1
    music_titles_artists[order] = [music_title, music_artist]
music_titles_artists[1]
>>> ['Ditto', 'NewJeans']

music_titles_artists[2]
>>> ['NOT SORRY (Feat. pH-1) (Prod. by Slom)', '이영지']
  • 함수로 묶기
import requests
from bs4 import BeautifulSoup

# 날짜를 입력하면 벅스 차트에서 주간 음악 순위(1~100)의 곡명과 아티스트를 반환
def bugs_music_week_top100 (year, month, day):
    
    #월과 일의 경우는 항상 두 자리로 맞춤
    month = "{0:02d}".format(month)
    day = "{0:02d}".format(day)
    
    base_url = 'https://music.bugs.co.kr/chart/track/week/total?'
    url = base_url + 'chartdate={0}{1}{2}'.format(year, month, day)
    
    html_music = requests.get(url).text
    soup_music = BeautifulSoup(html_music,"lxml")
    
    titles = soup_music.select('p.title a')
    artists = soup_music.select('p.artist a:not(.more)')

    music_titles = [title.get_text() for title in titles]
    music_artists = [artist.get_text().strip() for artist in artists]
    
    return music_titles, music_aritsts
  • 자료 저장하기
import glob

# 날짜를 지정해 bugs_music_week_top100() 함수 호출
bugs_music_titles, bugs_music_artists = bugs_music_week_top100(2023,1,9)

# 곡명과 아티스트를 저장할 파일 이름을 폴더와 함께 지정
file_name = 'C:/myPyCode/data/bugs_week_top100.txt'

f = open(file_name, 'w') # 파일 열기

# 추출된 노래 제목과 아티스트를 파일에 저장
for k in range(len(bugs_music_titles)):
    f.write("{0:2d}: {1}/{2}\n".format(k+1, bugs_music_titles[k], bugs_music_artists[k]))
    
f.close() # 파일 닫기

glob.glob(file_name) # 생성된 파일 확인

>>> ['C:/myPyCode/data/bugs_week_top100.txt']