Python/2.7 for fun.

네이버 블로그에서 최근에 올라온 음악들 다운받기 2 코딩, xml다루기

qkqhxla1 2015. 3. 15. 16:04

이전글. http://qkqhxla1.tistory.com/311

코딩한 결과. 나중에도 필요할 거 같으므로 주석은 최대한 자세히 써놓았다.


xml파싱하는 라이브러리는 lxml을 썼다. 다운로드는 콘솔에서 wget으로 처리했다.


공식 홈페이지 : http://lxml.de/

다운로드 : https://pypi.python.org/pypi/lxml/

튜토리얼 : http://lxml.de/tutorial.html


아래쪽에 개선한 코딩이 있습니다 이건 그냥 뼈대

# -*- encoding: cp949 -*-
import urllib2,re,os
import codecs
import subprocess
from lxml import etree

outer = urllib2.urlopen(urllib2.Request('http://blog.naver.com/diamonds8/220032249606')).read() #블로그에 들어가서 페이지 소스를 가져온다.
xml = re.findall('"application/rss\+xml"\s+href="(.*?)"',outer)[0] #그중에서 xml파일의 경로를 찾는다.
page = urllib2.urlopen(urllib2.Request(xml)).read().split('\r\n') #xml페이지의 소스를 가져와서 줄내림을 기준으로 나눈다.
f = open('note.xml','w') #note.xml이라는 파일에 utf-8로 디코딩해서 저장한다. xml에서 소스를 보면 utf-8로 쓰여졌다는걸 알 수 있다. 나는 cp949가 기본이므로 디코딩을 해 줘야 한다.
for l in page:
    try: f.write( l.decode('utf-8')+'\n' ) #굳이 try,except구문으로 한 이유는, 일본어같은것도 있는데 utf-8로 디코딩이 안되고 에러가 뜨는 경우가 있기 때문이다. 일본어는 버리고 그냥 영어+한글만 디코딩해서 저장.
    except: pass
f.close()

parser = etree.XMLParser(remove_blank_text=True,recover=True) #xml파서를 만듬. lxml 튜토리 페이지에서 그대로 가져옴.
root = etree.XML(open('note.xml','r').read().decode('cp949').encode('utf-8'),parser) #note.xml파일을 열어서 올바르게 유니코드 변경 후 인자로 집어넣음. 
#이 부분은 본인의 인코딩 방식에 따라서 알아서 바꿀것. 최종적으로 utf-8로 인코딩해야 제대로 들어간다.
linklist = [] #xml내부의 내가 필요한 링크들을 저장할 linklist 리스트.
for element in root.iter("*"): #lxml 튜토리얼에서 그대로 가져옴.
    if element.tag=='category' and element.text=='Be-music script': before = element.text #태그가 카테고리이면서 Be-music script이면 before에 Be-music script 저장.
    elif element.tag=='title': pass #태그가 title이면 그냥 넘어감. 굳이 이렇게 구현한 이유는 category아래에 title태그 아래에 link태그가 있기 때문이다
    elif element.tag!='link': before = '' #link라는 태그가 아니면 초기화.
    if before == 'Be-music script' and element.tag=='link': #카테고리가 Be-music script이면서 태그가 링크이면 내가 원하는 태그가 맞음.
        linklist.append( re.findall('/diamonds8/(\d+)',element.text)[0] ) #정규표현식으로 linklist에 저장해둠.

cmd = subprocess.Popen('mkdir music', shell=True, stderr=subprocess.PIPE) #현재 파이썬 디렉토리 내부에 music폴더를 만들건데 이미 있는지 확인용.
for l in cmd.stderr:
    if l.strip()=='하위 디렉터리 또는 파일 music이(가) 이미 있습니다.':
        print '이미 music이라는 디렉터리가 있습니다. 새로 music폴더를 만들지 않습니다.'

for i in linklist: #링크 리스트에서 링크들을 가져와 앞장에서 말한 '진짜' 페이지로 들어감.
    page = urllib2.urlopen( urllib2.Request('http://blog.naver.com/PostView.nhn?blogId=diamonds8&logNo='+i+'&redirect=Dlog&widgetTypeCall=true') ).read() #진짜 페이지의 소스를 가져옴.
    down_path = re.findall("'encodedAttachFileUrl': '(.*?)'",page)[0] #앞장에서 말한 다운로드 경로를 정규식으로 가져옴.
    file_name = re.findall("'encodedAttachFileName': '(.*?)'",page)[0].replace(' ','+') #파일 이름을 가져오는데 다운시 공백이 +로 변환되므로 변환해서 저장함.
    os.system('wget '+down_path) #wget으로 음악을 다운로드받음.
    os.system('move '+file_name+' music') #다운로드받은 음악을 music폴더로 옮김.


일단 주석은 자세히 달아놓았고 최소한의 기능만 하는 스크립트이다. 실행 화면.



이렇게 wget의 진행상황이 보이고 music폴더에 들어가면...


이런식으로 저장이 되었음을 확인할 수 있다.



최소한의 기능만 수행하며, 업데이트시 글에 추가 예정. xml을 기본적으로 다루는 방법과,


네이버 블로그의 구조 분석이 공부에 도움됬던것같다.

ico 그림

music.ico




15.07.11 추가.

확장자 mp3까지 추가. 더 추가할 확장자는 extension변수에서 변경.

15.11.08 추가.

음악 전부 다운로드 후 캐나다 환율 주소 띄우는거 추가.


최종 코드.(17년 1월 27일 재수정)

# -*- encoding: cp949 -*-
import urllib2,re,os
import codecs
import subprocess
import itertools
from lxml import etree
import sys
import webbrowser
 
reload(sys) 
if hasattr(sys,"setdefaultencoding"):
    sys.setdefaultencoding("cp949")
   
def download_photo(url, filename):
    file_path = "%s" % (filename)
    print file_path+'에 다운로드중...'
    downloaded_image = file(file_path, "wb")
    req = urllib2.Request(url)
    image_on_web = urllib2.urlopen(req)
    while True:
        buf = image_on_web.read()
        if len(buf) == 0:
            break
        downloaded_image.write(buf)
       
    downloaded_image.close()
    image_on_web.close()
    print '다운로드 완료!\n'

in_dir = raw_input('음악들을 저장시킬 폴더를 드래그하세요.\n아무것도 입력 안할시 \'C:\\Users\\Ko\\Desktop\\음악\'이라는 폴더 내부로 들어갑니다.\n폴더 경로 : ')
if in_dir=='':
    in_dir = 'C:\\Users\\Ko\\Desktop\\음악'
if in_dir!='C:\\Users\\Ko\\Desktop\\음악' and not os.path.isdir(in_dir):
    print '\n\n경로를 잘못 입력하셨습니다 프로그램을 종료합니다!!'
    exit(1)
cmd = subprocess.Popen('mkdir '+in_dir, shell=True, stderr=subprocess.PIPE) 
for l in cmd.stderr:
    if l.strip()=='하위 디렉터리 또는 파일 '+in_dir+'이(가) 이미 있습니다.':
        print '\n이미 '+in_dir+'이라는 디렉터리가 있습니다. \n새로 '+in_dir+'폴더를 만들지 않고, 원래의 '+in_dir+'폴더에 음악을 받습니다.\n'
        break
          
outer = urllib2.urlopen(urllib2.Request('http://blog.naver.com/diamonds8/220032249606')).read() 
xml = re.findall('"application/rss\+xml"\s+href="(.*?)"',outer)[0] 
page = urllib2.urlopen(urllib2.Request(xml)).read().split('\r\n') 
   
f = open('note.xml','w')
for l in page:
    try: 
        f.write( l.decode('utf-8')+'\n' ) 
    except: pass
f.close()
           
parser = etree.XMLParser(remove_blank_text=True,recover=True) 
root = etree.XML(open('note.xml','r').read().encode('utf-8'),parser) 
linklist = [] 
for element in root.iter("*"): 
    if element.tag=='category' and element.text=='Be-music script': before = element.text 
    elif element.tag=='title': pass
    elif element.tag!='link': before = '' 
    if before == 'Be-music script' and element.tag=='link': 
        linklist.append( re.findall('/diamonds8/(\d+)',element.text)[0] ) 
         
os.remove("note.xml"); flag = 0
for i in linklist:
    page = urllib2.urlopen( urllib2.Request('http://blog.naver.com/PostView.nhn?blogId=diamonds8&logNo='+i+'&redirect=Dlog&widgetTypeCall=true') ).read()
    try: #글은 있는데 첨부파일이 없을경우 그냥 지나감.
        down_path = re.findall("'encodedAttachFileUrl': '(.*?)'",page)
        extension = ['.wma','.WMA','.mp3']
        if len(down_path) > 1: #첨부파일이 여러개일경우 .wma나 .WMA확장자가 있는 파일 다운로드
            for j in down_path:
                for k in extension:
                    if j.find(k)!=-1 or j.find(k)!=-1:
                        down_path = j
        else: down_path = down_path[0]
        file_name = re.findall("'encodedAttachFileName': '(.*?)','encodedAttachFileNameByTruncate'",page)#.replace(' ','+') 
 
        if len(file_name) > 1: 
            for j in file_name:
                for k in extension:
                    if j.find(k)!=-1 or j.find(k)!=-1:
                        file_name = j
        else: file_name = file_name[0]
        file_name = file_name.replace(' ','+').replace('\\','')
    except: continue
    if os.path.isfile(in_dir+'\\'+file_name) and flag==0 or flag==1:
        if flag == 0:
            select = raw_input('이전에 받아서 이미 존재하는 음악파일이 존재합니다. \n받았던 파일은 그냥 건너뜁니까? n입력시 덮어씌우게 됩니다. (y/n)')
        if select=='n' or select=='N':
            flag = 2
        else:
            print '\''+file_name+'\'은 이미 있는 파일입니다. 그냥 무시하고 넘어갑니다.'
            flag = 1; continue
    download_photo(down_path, in_dir+'\\'+file_name)
      
print '\n최근 음악목록 다운로드를 완료하였습니다!!'