Unix

티스토리 백업 내용 추출하기

ForceCore 2014. 2. 27. 00:09

티스토리 백업을 돌리면 XML파일 한 덩어리로 나온다 ㅎㄷㄷㄷㄷㄷ 좀 무서운듯. 첨부파일까지도 뭔가 알 수 없는(?) 것으로 변형되어서 한덩어리로 합체되어 있다.


필자가 원하는건 그림과 글의 제목만 알아내면 되는 것이다. 다른 블로그로 딱히 이사할 것은 아니라서. 아, 글 분류도. 글 내용 알아내기야 뭐 별로 어렵진 않으니까... 노력을 더 하면 HTML로 포장해서 만들어 줄 수도 있겠으나 그건 귀찮다.


글이 있으면, <post></post>에 갇혀있는데, 그 중 제목와 attachment, category를 적절히 읽어서,

분류/파일이름+확장자

로 저장해주는 정도면 만족. 분류는 폴더에 대응되기 때문에 폴더가 없으면 생성해서 그 안에다가 파일을 저장한다. 파일 이름은, 블로그에 업로드 하는순간 막 SFSDGEARDHGDHd 이런걸로 변하게 되어서 못 쓰고, 글 제목에서 적당히 변형해서 만든다: 다만 윈도우에서 인정하지 않는 특수문자는 공백이나 "-" 로 바꿔서.


그림은 XML파일에 어떻게 들어갔는고 하니 base64인코딩을 해서 들어가있다. 바이너리 파일 위치에 뭔가 ASCII로 된 이상한 외계어가 들어가있으면 거의 base64로 찍으면 맞다. -_-;; 그거 해독하는거는 Python에 있으니 문제 없음.


원하는 바를 쉽게 이루기 위해 파이썬 HTML parser를 이용하기로 결정!, 완제품(?)의 코드는 아래와 같다.



xtract.py


#!/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()



ㅋㅋㅋㅋ