관련: https://konahn.tistory.com/entry/DAUMNews

 

QuerySelector를 이용한 다음(DAUM) 뉴스 검색

모바일 다음에서 뉴스기사를 검색하면 아래와 같은 URL로 접속됩니다.https://m.search.daum.net/search?w=news&q=인공지능최대한 간단히 줄인 주소입니다.PC웹에서 검색해도 비슷한데 효율성을 위해서 모바

konahn.tistory.com

 

 

이번에는 멜론 사이트의 노래 순위, 제목, 가수, 앨범 아트 정보를 가져옵니다.

 

일단 상황은 미리 멜론, 벅스, 스포티파이 등 음악사이트에서 다운 받아놓은 mp3 등의 파일의 파일명을  

내가 원하는 스타일로 일괄로 바꾸고 싶은 경우입니다.

 

001.mp3  ▶️▶️ 001. IVE (아이브) - BANG BANG.mp3 

 

위와 같이 바꾸고 싶습니다.

 

한 두개가 아니라 100여곡이 된다면 일일이 바꾸는 것이 만만치 않습니다.

 

멜론 사이트에서 곡 정보를 받아와서 엑셀에 정리하고

지난 번 파일명 변경 매크로로 일괄 변경하는 것이 목표입니다.

 

 

멜론의 곡 순위는 아래와 같은 주소에서 가져올 수 있습니다.

    ' url = "https://www.melon.com/chart/search/list.htm?chartType=WE&age=2020&year=2026&mon=01&day=20260126%5E20260201&classCd=GN0000&startDay=20260126&endDay=20260201&moved=Y"
    ' url = "https://www.melon.com/chart/week/index.htm?classCd=GN0000&moved=Y&startDay=20260126&endDay=20260201"
     'url = "https://www.melon.com/chart/week/index.htm?classCd=DM0000&moved=Y&startDay=20260126&endDay=20260201"
    ' url = "https://www.melon.com/chart/day/index.htm?classCd=GN0000"
    ' url = "https://www.melon.com/chart/search/list.htm?chartType=WE&classCd=GN0000&startDay=20260126&endDay=20260201&moved=Y"

 

 

index.htm은 TOP100 등의 순위를 가져오고

차트 파인더로 과거 정보를 검색해 올 때는 list.htm 으로 가져옵니다.

list.htm 은 단순히 테이블 형태의 자료입니다.

50위까지는 보이는데 나머지 50개는 display:none 으로 숨긴 채로 가져옵니다.

 

여기서는 일간 TOP100 을 기준으로 하겠습니다.

 

 노래 한 곡의 정보는 Class 이름이 lst50 이거나 lst100 이라는 TR 요소 안에 들어 있습니다.

더보기
<tr class="lst50" id="lst50"  data-song-no="601237102">

	<td><div class="wrap t_right"><input type="checkbox" title="BANG BANG 곡 선택" class="input_check "  name="input_check" value="601237102"></div></td>
	<td><div class="wrap t_center"><span class="rank ">1</span><span class="none">위</span></div></td>

		<!-- 차트순위 추가 -->
		<td><div class="wrap">순위...</div></td>

	<td><div class="wrap">
		<a href="/album/detail.htm?albumId=12845274" title="REVIVE+" class="image_typeAll">
			<img onerror="WEBPOCIMG.defaultAlbumImg(this);" width="60" height="60" src="https://cdnimg.melon.co.kr/cm2/album/images/128/45/274/12845274_20260223113048_500.jpg/melon/resize/120/quality/80/optimize" alt="REVIVE+ - 페이지 이동"/>
			<span class="bg_album_frame"></span>
		</a>
	</div></td>
	<td><div class="wrap">
		<a href="/song/detail.htm?songId=601237102" title="BANG BANG 곡정보" class="btn button_icons type03 song_info"><span class="none">곡정보</span></a>
	</div></td>
	<td><div class="wrap">
		<div class="wrap_song_info">
			<div class="ellipsis rank01"><span>
				<a href="javascript:melon.play.playSong('1000002721',601237102);" title="BANG BANG 재생">BANG BANG</a>
			</span></div><br>
			<div class="ellipsis rank02">
				<a href="/artist/timeline.htm?artistId=3055146" title="IVE (아이브) - 페이지 이동">IVE (아이브)</a><span class="checkEllipsis" style="display:none"><a href="/artist/timeline.htm?artistId=3055146" title="IVE (아이브) - 페이지 이동">IVE (아이브)</a></span>
			</div>
			
		</div>
	</div></td>
	<td><div class="wrap">
		<div class="wrap_song_info">
			<div class="ellipsis rank03">
				<a href="/album/detail.htm?albumId=12845274" title="REVIVE+ - 페이지 이동">REVIVE+</a>
			</div>
		</div>
	</div></td>
	<td><div class="wrap">
		<button type="button" class="button_etc like" title="BANG BANG 좋아요" data-song-no="601237102" data-song-menuid="1000002721">
			<span class="odd_span">좋아요</span>
			<span class="cnt">
				<span class="none">총건수</span>
				0
			</span>
		</button>
	</div></td>
	<td><div class="wrap t_center"> 버튼들...</div></td>
</tr>

 우리가 필요한 것은 순위, 노래제목, 가수, 앨범아트 입니다.

 

먼저  winhttp 나 xmlhttp등의 http로 접속해서 HTML문서인 htmlDoc을 받아옵니다.

 

getelementsbyClassname 도 가능하지만 여기서는 querySelector를 이용해보겠습니다.

 

querySelectorAll(".lst50, .lst100") 으로 가져오면 클래스 이름이 lst50이거나 lst100 인 모든 요소를 가져올 수 있습니다.

.lst50 라고 쓰면 클래스 이름이고 #lst50 이면 ID, 그냥 lst50 이라고 쓰면 태그로 인식합니다.

이렇게 하면 lst50이나 lst100인 TR 하위 요소 전체를 한 덩어리로 가져올 수 있습니다.

 

여기서 다시  .querySelector("rank").innerText 를 이용해서 rank 라는 클래스 이름에서 순위를 구합니다.

 .querySelector("rank01").innerText 를 이용해서 rank01 라는 클래스 이름에서 노래제목을 구합니다.

 .querySelector("rank02").innerText 를 이용하면 가수이름이 2번 나오기 때문에

 .querySelector("rank02 > a").innerText 를 이용해서 첫번째  a 태그 안의 가수이름을 한 번만 가져옵니다.

rank03은 앨범 정보이므로 넘어가도록 합니다.

앨범아트 이미지는 .querySelector("img").src 로 가져올 수 있습니다.

앨범아트를 클릭했을 때 이동할 노래 정보 페이지는 .getAttribute("data-song-no") 로 601237102 과 같은 노래의 고유 아이디를 가져올 수 있습니다.  https://www.melon.com/song/detail.htm?songId= 이 뒤에 노래 아이디를 붙여서 링크시키면 됩니다.

 

마지막으로 새로운 파일명 규칙이 순위. 가수 - 노래 제목.mp3 와 같은 식이라면

오른쪽 셀에 = Format(A2, "000") & ". " & C2 & " - "  & B2 와 같은 함수식을 추가하도록 합니다.

 

아래는 현재 시트에 멜론 TOP100 정보를 가져오는 전체 코드입니다.

주) 사이트가 변경되면 언제라도 아래 코드는 작동하지 않습니다.

더보기
Option Explicit

Sub getTop100()
    
    Dim wb As Workbook
    Dim htmlContent As String
    Dim htmlDoc As New MSHTML.HTMLDocument
    Dim rowItems As IHTMLDOMChildrenCollection  'Object
    Dim item As Object  'IHTMLElement    'Object
    Dim i As Long
    
    '   'HTML 파일로 읽을 경우
    '    Dim filePath As String, fileNo As Integer, lineText As String
    '    filePath = ThisWorkbook.Path & "\1.html"
    '    fileNo = FreeFile
    '    Open filePath For Input As #fileNo
    '        Do Until EOF(fileNo)
    '            Line Input #fileNo, lineText
    '            htmlContent = htmlContent & Trim(lineText) & vbCrLf
    '        Loop
    '    Close #fileNo
    
    Dim http As Object
    Dim url As String, slink As String
    
   ' 1. 대상 URL 설정
    ' url = "https://www.melon.com/chart/search/list.htm?chartType=WE&age=2020&year=2026&mon=01&day=20260126%5E20260201&classCd=GN0000&startDay=20260126&endDay=20260201&moved=Y"
    ' url = "https://www.melon.com/chart/week/index.htm?classCd=GN0000&moved=Y&startDay=20260126&endDay=20260201"
     'url = "https://www.melon.com/chart/week/index.htm?classCd=DM0000&moved=Y&startDay=20260126&endDay=20260201"
    url = "https://www.melon.com/chart/day/index.htm?classCd=GN0000"
    ' url = "https://www.melon.com/chart/search/list.htm?chartType=WE&classCd=GN0000&startDay=20260126&endDay=20260201&moved=Y"
    slink = "https://www.melon.com/song/detail.htm?songId="
    
    ' 2. ServerXMLHTTP 객체 생성 및 요청
    Set http = CreateObject("MSXML2.ServerXMLHTTP")
    
    With http
        .Open "GET", url, False
        .setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
        '.setRequestHeader "accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
        '.setRequestHeader "Host", "www.melon.com"
        .send
        
        If .Status <> 200 Then MsgBox "페이지 접속에 실패했습니다. 에러 코드: " & .Status: Exit Sub
    ' 3. HTML 파싱 (Microsoft HTML Object Library 참조 필요)
        htmlDoc.body.innerHTML = .responseText
    End With
    
    ' 4. querySelectorAll로 .lst50 탐색
    Set rowItems = htmlDoc.querySelectorAll(".lst50, .lst100 ")
    If rowItems Is Nothing Then MsgBox ".lst50 or .lst100 fetching failed": Exit Sub
    'MsgBox rowItems.Length
    
    ' 5. 결과 출력
    Dim ws As Worksheet: Set ws = ActiveSheet: Set wb = ws.Parent
    ws.Cells.Clear: ws.Hyperlinks.Delete
    For i = ws.Shapes.Count To 1 Step -1: If ws.Shapes(i).Name Like "Img_*" Then ws.Shapes(i).Delete
    Next i
    ws.Range("A1:E1").Value = Array("Rank", "제목", "가수", "파일명", "앨범아트")
    
    'i = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1
    'On Error Resume Next
    'For each item in rowItems 는 순환 후 강제종료 오류발생
    For i = 0 To rowItems.Length - 1
        
        ' 각 항목 하위의 rank01, rank02 텍스트 추출
        ws.Cells(i + 2, 1).Value = i + 1
        If Not rowItems(i).querySelector(".rank01") Is Nothing Then
            ws.Cells(i + 2, 2).Value = rowItems(i).querySelector(".rank01").innerText
        End If
        
        If Not rowItems(i).querySelector(".rank02 a") Is Nothing Then
            ws.Cells(i + 2, 3).Value = rowItems(i).querySelector(".rank02 > a").innerText
        End If
        '파일명
        ws.Cells(i + 2, 4).Formula = "=TEXT(A" & i + 2 & ",""000"") & "". "" & C" & i + 2 & " & "" - "" & B" & i + 2
                
        '앨범이미지
        If Not rowItems(i).querySelector("img") Is Nothing Then
            'Debug.Print rowItems(i).querySelector(".input_check").Value, rowItems(i).getAttribute("data-song-no")
            With ws.Cells(i + 2, 5)
                Dim shp As Shape
                .EntireRow.RowHeight = 45
                .EntireColumn.ColumnWidth = 8
                Set shp = ws.Shapes.AddPicture(rowItems(i).querySelector("img").src, msoFalse, msoTrue, .Left, .Top, .Width, .Height)
                shp.Name = "Img_" & ws.Cells(i + 2, 4).Value
                ws.Hyperlinks.Add Anchor:=shp, Address:=slink & rowItems(i).getAttribute("data-song-no") 'querySelector(".input_check").Value
            End With
        End If
        
        If i = 99 Then wb.Save

    Next i
 
    Cells.Columns.AutoFit
    Set htmlDoc = Nothing
    Set http = Nothing
    
    'MsgBox "완료!"
End Sub

 

위 매크로 실행 결과 아래와 같이 나만의 방식대로 각 노래의 파일명이 완성되었습니다.

참고로 앨범 아트도 보여주고 클릭하면 구체적인 노래 정보 사이트로 연결됩니다.

 

 

이제 파일명 변경 매크로를 이용합니다.

 

이전 파일명이 001.mp3 였는데  폴더의 mp3 파일들을 불러와서 C열에 = Sheet2!D2  와 같은 함수식을 써주고

Rename Files 를 실행하면 일괄로 "001. IVE (아이브) - BANG BANG.mp3" 로 바뀌게 됩니다.

 

 

샘플 매크로 파일 첨부합니다.

 

Sheet2에서 멜론 노래 정보를 가져오고

(멜론의 어떤 순위인지에 따라 url 주소를 미리 변경해야 합니다.)

Sheet1에서 기존 파일 목록을 불러와서 C열에 =Sheet2.D2와 같은 함수식을 적용하고 

RenameFiles를 누르면 파일명을 일괄 변경합니다.

 

RenameFiles_Melon1.xlsm
0.49MB

 

 

파일명에 쓸 수 없는 문자를 검사하는 부분을 추가할 수도 있겠습니다.

더보기
' 파일명으로 쓸 수 없는 문자 (\ / : * ? " < > |) 제거 함수
Function CleanFileName(str As String) As String
    Dim i As Integer
    Dim illegalChars As String
    illegalChars = "\/:*?""<>|"
    CleanFileName = str
    For i = 1 To Len(illegalChars)
        CleanFileName = Replace(CleanFileName, Mid(illegalChars, i, 1), "")
    Next i
End Function

 

Image by Gemini