HTML In JSON
음악앱을 만들때 가사로도 검색을 하고 싶어서 찾아보는데 이전에 사용한 Maniadb에서는 가사로 검색은 지원하지 않았다. 그래서 노래 가사 검색 api를 찾아보는데 다른 곳은 유료거나 특수한 조건을 만족해야 사용할 수 있었다. 그런데 아래의 블로그에서는 네이버 가사 검색 기능을 이용해서 가사검색 기능을 만들었다.
https://cheongpark.tistory.com/2
네이버의 가사 검색 API 가져오기
주의 전문적인 지식이 없이 진행하기 때문에 이 내용은 확실하지 않을 수 있습니다!네이버엔 가사를 입력해 음악을 찾을 수 있는 서비스가 있다. 일단 왜 이것을 하게 되었는지 부터...저번에
cheongpark.tistory.com
naver에서 정식으로 제공하는 api가 아닌 검색사이트에서 받는 데이터 구조를 뜯어서 가사 부분의 JSON만을 불러오게 구성을 한것이다. 다른 방법이 없어서 블로그에서 알려주는 방식을 사용하기로 했다.
API 연결하기
우선 통신을 위한 URL을 찾아봤다. 공식적으로 제공하지 않아서 직접 찾는다면 어려웠겠지만 블로그에서 정리가 되어있어서 금방 찾았다.
https://m.search.naver.com/p/csearch/content/qapirender.nhn?where=nexearch&key=LyricsSearchResult&q=가사검색$query
원하는 가사를 query에 넣어주기만 하면 정보가 넘어온다.
어떤 형식으로 정보가 넘어오는지 확인하기 위해서 URL에 위잉위잉의 가사("차라리듣지못한편이")를 넣어봤다.
{
"q": "차라리듣지못한편이",
"resultTitle": "'차라리듣지못한편이'가 포함 된 노래",
"affordanceLink": "https://vibe.naver.com/search/lyrics?query=%EC%B0%A8%EB%9D%BC%EB%A6%AC%EB%93%A3%EC%A7%80%EB%AA%BB%ED%95%9C%ED%8E%B8%EC%9D%B4",
"start": "1",
"display": "5",
"totalCount": "1",
"current": {
"html": "<ul class=\"result_list_box _music_list\"> <li class=\"_li last_list\"> <div class=\"body\"> <div class=\"thumb_area\"> <a nocr onclick=\"return goOtherCR(this, 'a=nco_xfc*1.album&r=1&i=801980af_00000099223C&u=' + urlencode(this.href));\" href=\"https://vibe.naver.com/album/452900\" target=\"_blank\"> <div class=\"thumb_box\"> <div class=\"thumb\"> <img src=\"https://musicmeta-phinf.pstatic.net/album/000/452/452900.jpg?type=r204Fll&v=20230331120820\" width=\"38\" height=\"38\" alt=\"20\"> <\/div> <\/div> <\/a> <\/div> <div class=\"info_area\"> <strong class=\"music_title\"> <a nocr onclick=\"return goOtherCR(this, 'a=nco_xfc*1.title&r=1&i=801980af_00000099223C&u=' + urlencode(this.href));\" href=\"https://vibe.naver.com/track/4435786\" target=\"_blank\">위잉위잉<\/a> <\/strong> <span class=\"sub_text\">혁오(HYUKOH)<\/span> <\/div> <button class=\"link_btn _toggle\" type=\"button\">가사<\/button> <\/div> <div class=\"body_content\"> <div class=\"content_box _content_box \"> <p class=\"lyrics\"> 비틀비틀 걸어가는 나의 다리<br>오늘도 의미없는 또 하루가 흘러가죠<br>사랑도 끼리끼리 하는거라 믿는 나는<br>좀처럼 두근두근 거릴일이 전혀없죠<br><br>위잉위잉 하루살이도<br>처량한 나를 비웃듯이 멀리 날아가죠<br>비잉비잉 돌아가는<br>세상도 나를 비웃듯이 계속 꿈틀대죠<br><br>Tell me Tell me, Please don't tell<br>차라리 듣지 못한 편이 내겐 좋을거야<br>Tell me Tell me, Please don't tell<br>차라리 보지 못한 편이 내겐 좋을거야<br><br>ai ai ai ai ai<br><br>사람들 북적대는 출근길의 지하철엔<br>좀처럼 카드찍고 타볼일이 전혀없죠<br>집에서 뒹굴뒹굴 할 일없어 빈둥대는<br>내 모습 너무 초라해서 정말 죄송하죠<br><br>위잉위잉 하루살이도<br>처량한 나를 비웃듯이 멀리 날아가죠<br>비잉비잉 돌아가는<br>세상도 나를 비웃듯이 계속 꿈틀대죠<br><br>쌔앵 쌔앵 칼바람도<br>상처난 내 마음을 어쩌지는 못할거야<br>뚜욱 뚜욱 떨어지는<br>눈물이 언젠가는 이세상을 덮을거야<br><br>Tell me Tell me, Please don't tell<br>차라리 듣지 못한 편이 내겐 좋을거야<br>Tell me Tell me, Please don't tell<br>차라리 보지 못한 편이 내겐 좋을거야<br>Tell me Tell me, Please don't tell<br>차라리 느껴보지 못한 편이 좋을거야<br>Tell me Tell me, Please don't tell<br>차라리 살아보지 못한 편이 좋을거야<br><br>비틀비틀 걸어가는 나의 다리<br>오늘도 의미없는 또 하루가 흘러가죠<br>사랑도 끼리끼리 하는거라 믿는 나는<br>좀처럼 두근두근 거릴일이 전혀없죠<br><br>위잉위잉 하루살이도<br>처량한 나를 비웃듯이 멀리 날아가죠<br>비잉비잉 돌아가는<br>세상도 나를 비웃듯이 계속 꿈틀대죠. <\/p> <\/div> <div class=\"more_box\"> <a href=\"#\" class=\"more_btn _more\"><span>펼쳐보기<\/span><i class=\"more_icon\"><\/i><\/a> <\/div> <\/div> <\/li> <\/ul>",
"pageNo": 1,
"total": 1
}
}
보면 current 안에 html에 html 형식으로 정보가 들어가있는 것을 확인할 수 있다. 저 안을 보면 감싸져있는 제목, 가수, 가사가 html로 감싸져서 제공되고 있다.
저번에 사용했던 html 태그 제거를 사용하려고 생각을 해보았다. 그 때는 html, pageNo 처럼 각각의 key에 해당하는 값에 태그가 있어서 태그만 제거한면 정보를 잘 사용할 수 있엇다. 그런데 이번에는 그럴 경우 노래 제목, 가수, 가사가 구분없이 한번에 보여지는 문제가 발생하게 된다.
그래서 이번에는 html코드 속에서 태그를 통해서 정보를 추출하는 과정이 더 필요했다.
Future<List<NaverSearchDto>> fetchNaver(String query) async {
final client = Client();
try {
final response = await client.get(
Uri.parse(
'https://m.search.naver.com/p/csearch/content/qapirender.nhn?where=nexearch&key=LyricsSearchResult&q=가사검색$query',
),
);
if (response.statusCode == 200) {
// Response body 디코딩
final Map<String, dynamic> map = jsonDecode(response.body);
// 데이터에서 필요한 필드 추출
final htmlContent = map['current']['html'].toString();
// HTML 파싱 및 필요한 데이터 추출
final parsedData = parseHtml(htmlContent);
return parsedData;
} else {
// 실패한 경우 빈 리스트 반환
return [];
}
} catch (e) {
// 오류 처리 (네트워크 에러 등)
print('Error fetching data: $e');
return [];
} finally {
client.close();
}
우선 HTTP 통신으로 가사정보를 불러는 코드를 짰다. html 코드만 사용할 것이기 때문에 ['current']['html']로 html의 정보만 가져온다. 이때 통으로 가져와서 String 형을 저장을 해야한다. 그래야 html태그를 인식하고 정보를 따로 추출 할 수 있다. 그리고 함수를 통해서 정보를 추출한다.
HTML 정보 추출
List<NaverSearchDto> parseHtml(String html) {
final document = parse(html);
// 각 노래 데이터를 파싱하여 리스트 생성
final elements = document.querySelectorAll('.result_list_box ._li');
return elements.map((element) {
final title = element.querySelector('.music_title a')?.text ?? '제목 없음';
final artist = element.querySelector('.sub_text')?.text ?? '아티스트 없음';
final lyrics = element.querySelector('.lyrics')?.text ?? '가사 없음';
final link = element.querySelector('.music_title a')?.attributes['href'] ?? '';
return NaverSearchDto(
title: title,
artist: artist,
lyrics: lyrics,
link: link,
);
}).toList();
}
html 코드 속에서 정보를 추출하는 함수이다.
elements에 'result_list_box'가 감싸고 있는 모든 정보를 넣는다. 그리고 각각의 정보를 title, artist, lyrics, link에 파싱하여 리스트를 생성한다. 그리고 이를 첫번째 함수에서 리턴하면 가사를 검색했을 때 노래 제목, 가수, 가사 정보를 사용할 수 있게 된다.
마무리
api를 통해서 정보를 불러오는 과정은 해볼 수록 변수가 참 많다는 것을 알게 되는 것 같습니다. xml이냐 json이냐 안에 어떤 내용이 있냐 쉽다고 생각 할때마다 변수가 튀어나와서 무엇하나 쉽게쉽게 가는 법이 없는것같습니다. 그래서 더 재밌는 것 같기도하고 하나나 하면서 실력이 느는 것 같아 좋기도 합니다. 앞으로도 어떤 문제도 해결 할 수 있을 것 같습니다.
'Flutter > 캠프' 카테고리의 다른 글
XML to JSON 사용하기 (0) | 2025.01.21 |
---|---|
Flutter 숙련_개인프로젝트: 지역 검색 앱 (1) | 2024.12.09 |
24.12.02 Today Error (0) | 2024.12.02 |
24.11.29 오늘 있었던 오류들 (1) | 2024.11.29 |
flutter(기초 팀프로젝트) : 화면 전환시 추가된 정보 바로 적용하기 (0) | 2024.11.28 |