# -*- coding: cp949 -*- from bs4 import BeautifulSoup def get_html(): with open('melon_weekly.html', 'r') as f: html = f.read() return html def extract_chart(): html = get_html() # 저장된 파일을 사용합니다. # BeautifulSoup 로 파싱 soup = BeautifulSoup(html) # 이번에는 BeautifulSoup의 CSS를 통해 선택하는 기능을 사용합니다. # 모든 태그 중 boardListWhite CSS 클래스 속성을 가진 태그들을 필터합니다. # 이 CSS 클래스 속성은 차트의 표가 시작되는 table 태그에만 사용되고 있습니다. # 그러므로 tables는 길이 2인 BeautifulSoup의 객체가 담긴 리스트가 됩니다. # 각 객체의 최상위 태그는 html이 아닌 table입니다. tables = soup.select('.boardListWhite') # 1~50위의 각 행과 51위~100위 각 행을 추려냅니다. # top50에는 1~50위 각 tr 태그가 최상위인 BeautifulSoup 객체의 리스트, # top100에는 51~100위 각 tr태그가 최상위인 BeautifulSoup 객체의 리스트가 저장됩니다. top50 = tables[0].tbody.find_all('tr', recursive=False) top100 = tables[1].tbody.find_all('tr', recursive=False) chart = extract_row(top50) chart += extract_row(top100) # chart를 튜플 형태로 (수정불가) 리턴합니다. return tuple(chart) def extract_row(trs): items = [] for tr in trs: # 모든 tr에서 td 항목을 추출해냅니다. tds = tr.find_all('td', recursive=False) # 첫번째 td는 건너뜁니다. # 두번째 td는 랭크 정보인데, 랭크 정보가 숫자가 아니라면 차트 맨 처음의 # 추천곡일 것입니다. 건너뜁니다. alt = tds[1].img['alt'] rank = 0 if alt.isnumeric() == False: continue else: rank = int(alt) # 세번째 td는 순위등락폭입니다. # 순위 등락폭을 +/- 문자로 표시하고, 나머지는 그대로 씁니다. updn = tds[2].span['class'][0] delta = tds[2].span.text if updn == u'up2': delta = u'+' + delta elif updn == u'down2': delta = u'-' + delta # 네번째 td는 곡명, 아티스트명, 앨범명입니다. # 여러 아티스트가 나열되어 있는지를 파악해야 합니다. # td 태그 내부의 title이란 속성을 가진 a 태그만을 추출합니다. links = tds[3].find_all('a', title=True) # overlist라는 클래스 속성을 가진 span 태그를 찾습니다. morelist = tds[3].find('span', class_='overList') # overlist라는 클래스 속성을 가진 span 태그가 발견되면 # 아티스트 이름은 쉼표로 모아 합칩니다. if morelist: song = links[0]['title'] artist = ', '.join([a.text for a in morelist.find_all('a')]) album = links[-1]['title'] else: song = links[0]['title'] artist = links[1]['title'] album = links[2]['title'] # 랭크 하나의 정보가 완료되었습니다. 튜플로 기록합니다. items.append((rank, delta, song, artist, album)) return items if __name__ == '__main__': print extract_chart()