티스토리 백업을 돌리면 XML파일 한 덩어리로 나온다 ㅎㄷㄷㄷㄷㄷ 좀 무서운듯. 첨부파일까지도 뭔가 알 수 없는(?) 것으로 변형되어서 한덩어리로 합체되어 있다.
필자가 원하는건 그림과 글의 제목만 알아내면 되는 것이다. 다른 블로그로 딱히 이사할 것은 아니라서. 아, 글 분류도. 글 내용 알아내기야 뭐 별로 어렵진 않으니까... 노력을 더 하면 HTML로 포장해서 만들어 줄 수도 있겠으나 그건 귀찮다.
글이 있으면, <post></post>에 갇혀있는데, 그 중 제목와 attachment, category를 적절히 읽어서,
분류/파일이름+확장자
로 저장해주는 정도면 만족. 분류는 폴더에 대응되기 때문에 폴더가 없으면 생성해서 그 안에다가 파일을 저장한다. 파일 이름은, 블로그에 업로드 하는순간 막 SFSDGEARDHGDHd 이런걸로 변하게 되어서 못 쓰고, 글 제목에서 적당히 변형해서 만든다: 다만 윈도우에서 인정하지 않는 특수문자는 공백이나 "-" 로 바꿔서.
그림은 XML파일에 어떻게 들어갔는고 하니 base64인코딩을 해서 들어가있다. 바이너리 파일 위치에 뭔가 ASCII로 된 이상한 외계어가 들어가있으면 거의 base64로 찍으면 맞다. -_-;; 그거 해독하는거는 Python에 있으니 문제 없음.
원하는 바를 쉽게 이루기 위해 파이썬 HTML parser를 이용하기로 결정!, 완제품(?)의 코드는 아래와 같다.
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
import os
import sys
import re
import urllib.request
from base64 import decodestring
from html.parser import HTMLParser, HTMLParseError
class State :
NONE = 0
POST = 1
TITLE = 2
ATTACHMENT = 3
ATTACHMENT_NAME = 4
ATTACHMENT_CONTENT = 5
CATEGORY = 6
class Xtractor( HTMLParser ) :
def init( self ) :
self.state = State.NONE
self.ext = "" # file extension of the attached file
self.cat = "" # category of the post
self.title = "" # file name, constructed from post title!
def handle_starttag( self, tag, attrs ) :
if self.state == State.NONE and tag == "post" :
print( "post start" )
self.state = State.POST
#for attr in attrs :
# print( attr )
elif self.state == State.POST :
if tag == "title" :
self.state = State.TITLE
elif tag == "attachment" :
self.state = State.ATTACHMENT
elif tag == "category" :
self.state = State.CATEGORY
elif self.state == State.ATTACHMENT :
if tag == "name" :
self.state = State.ATTACHMENT_NAME
elif tag == "content" :
self.state = State.ATTACHMENT_CONTENT
def handle_endtag( self, tag ) :
if self.state == State.POST and tag == "post" :
self.state = State.NONE
print( "post end" )
print()
elif self.state == State.TITLE and tag == "title" :
self.state = State.POST
elif self.state == State.ATTACHMENT and tag == "attachment" :
self.state = State.POST
elif self.state == State.ATTACHMENT_NAME and tag == "name" :
self.state = State.ATTACHMENT
elif self.state == State.ATTACHMENT_CONTENT and tag == "content" :
self.state = State.POST
elif self.state == State.CATEGORY and tag == "category" :
self.state = State.POST
def handle_data( self, data ) :
if self.state == State.TITLE :
print( "\ttitle:", data )
self.title = data
elif self.state == State.ATTACHMENT_NAME :
print( "\tattachment_fname:", data )
fileName, fileExtension = os.path.splitext( data )
self.ext = fileExtension
assert fileExtension != ""
elif self.state == State.ATTACHMENT_CONTENT :
print( "\tattach_data:", data[0:15] )
fname = self.calc_fname()
self.save_as( fname, data )
elif self.state == State.CATEGORY :
print( "\tcategory:", data )
# turn this on if you need to!
os.system( "mkdir -p \"" + data + "\"" )
self.cat = data
def calc_fname( self ) :
fname = self.rectify_fname( self.title )
#self.ext # file extension of the attached file
#self.cat # category of the post
full_fname = self.cat + "/" + fname
# Give file extension, if not given.
fileName, fileExtension = os.path.splitext( full_fname )
if fileExtension == "" :
full_fname += self.ext
return full_fname
def save_as( self, fname, data ) :
print( " writing to:", fname )
# saves base64 encoded data to fname
f = open( fname, "wb" )
f.write( decodestring( data.encode('ascii') ) )
f.close()
# makes a valid file name from da post title.
def rectify_fname( self, title ) :
# Windows file name refuses the following chars:
# \ / : * ? " < > |
title = title.replace( "\\", "-" )
title = title.replace( "/", "-" )
title = title.replace( ":", "-" )
title = title.replace( "*", "-" )
title = title.replace( "?", " " )
title = title.replace( "\"", " " )
title = title.replace( "<", "(" )
title = title.replace( ">", ")" )
title = title.replace( "|", "-" )
return title
###
### main
###
p = Xtractor()
p.init()
f = open( "./Tistory-Backup-20131221.xml" )
for line in f :
p.feed( line )
p.close()
ㅋㅋㅋㅋ