[XML] Python으로 xml 데이터 추출해서 다운받기 (easy!)

2022. 3. 2. 00:03Programming

아주 오래전... 초등학생이던 나는 매 저녁 10시에 타블로의 꿈꾸는 라디오를 듣곤 했었는데... 그 기억이 나서 2016년에 다운받을 수 있는 방법을 찾아봤더랬다. 이것도 벌써 6년전이 되어버렸다니 말이 안되는데 ^^; 그 때 어떤 블로그(https://upb-vol1.tistory.com/)에 재생파일이 올라왔던 "흔적"을 찾았고 어찌저찌 html를 어떻게 해서 페이지 소스를 xml로 다운을 받았는데 (이건 어떻게 했는지 뭔 짓을 해도 기억이 안남 - 내가 노가다로 다 복붙했을 것 같진 않고 누군가 xml 파일을 모아둔 걸 찾았었나?) 대강 이런 식으로 되어있는 xml 파일이었다.

 

 

이걸 이제 2016년에는 location 태그의 innertext를 일일히 긁어 복사해서 크롬창에 붙여넣기...를 했더랬다. 아예 코딩을 할 줄 모르던 인문계 학생에게는 이것마저도 '와... 난 진짜 너무 똑똑해...'의 경지였다고.... 그러나 수백개의 xml파일의 압박에 시달려 며칠간 새벽잠을 아껴가며 복붙을 하던 나는... 이것을 때려치게 된다. 왠지 언젠가 내가 이걸 더 똑똑한 방법으로 할 수 있을거라는 생각이 너무 컸기 때문이다. ㅋㅋㅋ 그대로 하드디스크에 보관...

 

한편 이것을 코딩을 배운 2022년의 내가 하드디스크를 정리하다가 발견하게 되는데... (예언적중) 약 6년에 걸친 숙원사업을 이렇게 완료하게 되었다. 개요는 xml파일에 접근하여 location 태그의 innertext 부분만 추출하여 크롬에 접속하게 해야 한다는 것. 주언어인 파이썬을 사용하였다.

 

그래서 처음에는 'python open in browser' 이렇게 검색을 해서 알아봤는데, 내가 간과한 것이 있었다. 내가 얻은 링크주소를 크롬창에서 열면 이런 페이지가 뜨고 (아마 크롬 자체에서 mp3를 지원하는 웹 플레이어일 듯)  

 

 

다운로드를 위해 클릭을 두번이나 해야 하는 아주 번거로운 과정이 있었던 것. 그래서 다시 검색어를 수정해서 'python download file with browser' 등으로 검색을 했다. 다행히 블로그 한 두곳을 보고 어떻게 하는지 감이 왔다.

너무나 익숙한 wget...

 

결론: 간단한 python 코드 + wget + xml 파싱으로 해결할 수 있었다.

즉, xml에 들어있는 데이터를 파싱해서 <location> 태그에 접근하여 innertext를 추출하고, 추출한 데이터를 통해 파일을 원하는 경로에 다운받는 것이다.

 

단계 1. xml 파일에 접근

import os
file_names = os.listdir('./xmls')

 

단계 2. xml 파일 파싱 (http://egloos.zum.com/sweeper/v/3045370, https://newly0513.tistory.com/178)

import xml.etree.ElementTree as ET

for file_name in file_names:
    tree = ET.parse(f'./xmls/{file_name}')
    root = tree.getroot()

 

단계 3. 태그 안 데이터에 접근, 파일 다운로드하여 지정경로에 저장 (저장명을 저렇게 저장해서 나중에 다시 바꿔야 했다. ㅎㅎ;)

import wget

# mp3링크가 최대 6개이므로 range: 6
for i in range(6):
    try:
    	# 최상위태그에서 location으로 하위탐색하여 text추출
        url = root[0][i][2].text
        # mp3s폴더에 저장
        wget.download(url, f'./mp3s/{file_name}_{i+1}.mp3')
	
    # 오래된 링크이다보니 403 forbidden이 뜨는 경우가 있었다. 403이 뜨면 다운로드할 수 없으므로 continue
    except:
        continue

 

 

이게 끝인데 단계 2가 생각보다 까다로웠다.  파싱은 처음 해봤기 때문에 ... 구글링해서 '파이썬 xml 파싱'에서 가장 먼저 걸린 파이썬의 자체 파싱 라이브러리 'xml.etree.ElementTree'(https://docs.python.org/ko/3/library/xml.etree.elementtree.html)를 썼는데

잘 되다가 갑자기 파싱오류가 나면서 멈추더랬다. 그런데 어디서 났는지 알려줘야지... 그런것도 없고 그냥 뭐라더라 ... 

xml.etree.ElementTree.ParseError: unclosed token: line 41, column 1 (찾아옴)

 

이렇게 뜨는데 뭔가 안 닫힌 태그가 있는 것 같았다. xml파일이 수십개도 아니고 수백개인데 파일명을 알려주지도 않고 ㅠ 이걸 어떻게 찾나... 싶었다. 구글링 끝에 다른 라이브러리인 lxml을 발견하였다!

 

##### * pip install lxml 해야합니다.

from lxml import etree

for file_name in file_names:
    tree = etree.parse(f'./xmls/{file_name}')
    root = tree.getroot()

 

lxml은 오류난 파일 이름과 라인 위치를 알려주었는데 알고보니 이유는 내 xml파일 중 <태그> 이렇게 되어있어야 할 것들이 </태 이렇게 된 채로 저장되어있었던 것. 아마 2016년에 복붙한다고 몇 개 건드리다가 일부를 지워버린듯하다. ^^; 그래도 몇개 안돼서 금방 고쳤다. 이외에도 xml파일 안에 문자열로 "초대가수 <빅마마>" 이렇게 되어있는 부분들 때문에 ParseError가 몇 번 정도 더 났다. 약 5-6번의 다운 시도 끝에 모두 다운완료! 이렇게 2008년 4월 7일 첫날부터 2008년 12월 11일까지의 라디오 방송분을 모두 들을 수 있다 ㅎ-ㅎ 중간에 부분부분 없는 파일도 있지만 당시의 추억을 떠올리기엔 충분한듯하다.

 

전체 코드

from lxml import etree
import os
import wget

file_names = os.listdir('./xmls')

for file_name in file_names:
    tree = etree.parse(f'./xmls/{file_name}')
    root = tree.getroot()

    for i in range(6):
        try:
            url = root[0][i][2].text
            wget.download(url, f'./mp3s/{file_name}_{i+1}.mp3')

        except:
            continue

 

 

P.S.

파이썬 파일명 코딩으로 변경하기

import os
# 절대경로, 상대경로 모두 가능
files_path = "./new"
files = os.listdir(files_path)

for file in files:
    old_name = files_path + file
    # 원래 이름에서 부분부분 가져오고 내가 원하는 형식을 갖다 붙이고 등등 str작업 하면 된다
    new_name = files_path + file[6:12] + '_타블로와_꿈꾸는_라디오_' + file[13] + '-' + file[14] + '부_' + file[20] + '.mp3'
    os.rename(old_name, new_name)
    
'''
대충
080808_xml_12_1.mp3 -> 080808_타블로와_꿈꾸는_라디오_1-2부_1.mp3

이렇게 변경됨
'''