멜론 차트를 파싱하여 JSON 형식 API로 만들기

이 글은 TISTORY에서 발행되어 이전된 글 입니다.

나는 멜론 차트를 꽤나 자주 확인하는 편이다. 오늘은 어떤 가수가 있는지, 어떤 노래가 어떤 순위인지 차트를 보기 위해 멜론 앱을 실행하면 멜론을 결제하라는 알림, 각종 광고들을 뚫고 차트를 봐야한다.

그리고 차트에는 검색 기능과 필터가 없으며 아티스트 별로 분리해서 볼 수 없다는 점이 꽤나 불편하게 느껴졌다. 그래서 결국 직접 멜론 차트를 파싱하여 멜론 차트를 내 맘대로 모아볼 수 있는 사이트를 만들기로 하였다.

파싱하기

내가 파싱할 사이트인 멜론 차트 페이지를 개발자 도구로 뜯어보게 되면, <table> 안에 50위까지는 lst50이라는 <tr>이, 50위부터 100위까지는 lst100이라는 <tr>이 계속 반복되는 형식이다. 이 tr 안에 span, img들이 다 들어가 있다. 그렇다면 그냥 table 안에 있는 span들을 모두 가져오면 된다.

foreach($tables as $table){
    foreach($classes as $class){
        $trs = $xpath->query(".//tr[contains(@class,'$class')]", $table);
        foreach($trs as $tr){
            $wraps = $xpath->query(".//td//div[contains(@class,'wrap_song_info')]", $tr);
            foreach($wraps as $wrap){
                $artistNodes = $xpath->query(".//div[contains(@class,'wrap_artist')]", $wrap);
                foreach($artistNodes as $artistNode){
                    $artistNode->parentNode->removeChild($artistNode);
                }
                $buttonNodes = $xpath->query(".//button", $wrap);
                foreach($buttonNodes as $btn){
                    $btn->parentNode->removeChild($btn);
                }

                $spans = $xpath->query(".//span", $wrap);
                $info = [];
                foreach($spans as $span){
                    $text = trim($span->nodeValue);
                    if($text !== "더보기" && $text !== ""){
                        $info[] = $text;
                    }
                }

                $imgNode = $xpath->query(".//img", $tr);
                $imgSrc = $imgNode->length > 0 ? $imgNode[0]->getAttribute('src') : "";

                if(!empty($info)){
                    $chartData[] = [
                        'rank' => $rank,
                        'songs' => isset($info[0]) ? $info[0] : "",
                        'artist' => isset($info[1]) ? $info[1] : "",
                        'image' => $imgSrc
                    ];
                    $rank++;
                }
            }
        }
    }
}

그래서 table 안쪽에 있는 tr 태그들을 돌면서, lst50이나 lst100이 포함된 tr만 선택한다. 그 후 wrap_song_info에서 span만 파싱한다. (여기서 불필요한 버튼이 자꾸 딸려오길래 제외시켰다.) 앨범 커버는 img 태그 안에 있는 src를 파싱해왔다.

파싱 결과

{
"rank": 1,
"songs": "Golden",
"artist": "HUNTR/X, EJAE, AUDREY NUNA, REI AMI, KPop Demon Hunters Cast",
"image": "https://cdnimg.melon.co.kr/cm2/album/images/118/59/863/11859863_20250620104512_500.jpg/melon/resize/120/quality/80/optimize"
}

사이트 만들기

사이트는 뭐 내가 만들기 귀찮으니 요즘 유행한다는 바이브코딩으로 Cluade가 열심히 잘 예쁘게 만들어줬다. 필터 기능도 Cluade에게 시켰다. 내가 원하는 아티스트별로 필터링이 되는 기능도 들어갔고, 검색 기능까지 들어갔으니 얼추 내가 원하던 차트를 바로 볼 수 있게 완성이 된 듯 하다.