はじめに
はてなブログからエクスポートされる記事は、MovableType形式のテキストファイルとしてダウンロードされますが、GoogleのBloggerにインポートする際にはXML形式が必要です。このブログ記事では、MovableType形式の.txtファイルをBlogger用のXML形式に変換するためのPythonスクリプトを紹介します。
注意: 本スクリプトは、MovableType形式のファイルをBlogger用XMLに変換することを目的としていますが、MovableType形式やBloggerの仕様変更、特定のエクスポートファイルの形式によっては正常に動作しない場合があります。万が一のエラーや問題についてはご了承ください。
スクリプトの概要
このスクリプトは、MovableType形式の.txtファイルを読み込み、記事を解析し、Bloggerに適した形式に変換します。最終的にXMLファイルとして出力され、これをBloggerにインポートすることで簡単に記事を移行できます。
作成したコード
import re
from datetime import datetime
from xml.etree.ElementTree import Element, SubElement, ElementTree, tostring
# MovableType形式の.txtファイルを読み込む
def read_mt_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
# MT形式のテキストから記事ごとに分割
def split_entries(mt_text):
return re.split(r'--------\n', mt_text)
# MT形式の各フィールドをパースして辞書にする
def parse_entry(entry_text):
entry = {}
patterns = {
'author': r'AUTHOR:\s*(.*)',
'title': r'TITLE:\s*(.*)',
'date': r'DATE:\s*(\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2})',
'body': r'BODY:\n(.*?)(?=\n-----|\Z)',
}
for key, pattern in patterns.items():
match = re.search(pattern, entry_text, re.DOTALL)
if match:
entry[key] = match.group(1).strip()
# 日付をBlogger用にフォーマット変更
if 'date' in entry:
entry['date'] = format_date(entry['date'])
return entry
# 日付のフォーマットをBlogger用に変換
def format_date(date_str):
try:
date_str = date_str.strip()
date_obj = datetime.strptime(date_str, '%m/%d/%Y %H:%M:%S')
return date_obj.strftime('%Y-%m-%dT%H:%M:%S') + '+09:00'
except ValueError as e:
print(f"Error parsing date, attempting alternative formats: {date_str}")
try:
date_obj = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
return date_obj.strftime('%Y-%m-%dT%H:%M:%S') + '+09:00'
except ValueError:
raise e
# XMLの構築
def create_xml(entries):
root = Element('feed', xmlns="http://www.w3.org/2005/Atom")
for entry in entries:
entry_elem = SubElement(root, 'entry')
author_elem = SubElement(entry_elem, 'author')
name_elem = SubElement(author_elem, 'name')
name_elem.text = entry.get('author', 'Unknown')
title_elem = SubElement(entry_elem, 'title')
title_elem.text = entry.get('title', 'No Title')
published_elem = SubElement(entry_elem, 'published')
published_elem.text = entry.get('date', '')
content_elem = SubElement(entry_elem, 'content', type="html")
content_elem.text = entry.get('body', '')
return root
# XMLをファイルに保存
def save_xml_file(root, output_path):
tree = ElementTree(root)
tree.write(output_path, encoding='utf-8', xml_declaration=True)
# メイン処理
def main(mt_file_path, output_xml_path):
mt_text = read_mt_file(mt_file_path)
entry_texts = split_entries(mt_text)
entries = []
for entry_text in entry_texts:
if entry_text.strip():
entries.append(parse_entry(entry_text))
xml_root = create_xml(entries)
save_xml_file(xml_root, output_xml_path)
print(f"XMLファイルが生成されました: {output_xml_path}")
# 使用例
mt_file_path = 'input/xxx.hatenablog.com.export.txt'
output_xml_path = 'output/output_blogger.xml'
main(mt_file_path, output_xml_path)
スクリプトの説明
以下は、スクリプト全体の説明です。
最初に、必要なライブラリをインポートします。reは正規表現を使って記事を解析し、datetimeは日付のフォーマット変換、ElementTreeはXMLを生成するために使用します。
import re
from datetime import datetime
from xml.etree.ElementTree import Element, SubElement, ElementTree, tostring
MovableType形式の.txtファイルを読み込む
この関数は、MovableType形式の.txtファイルをUTF-8で読み込み、その内容を文字列として返します。
def read_mt_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
記事の分割と解析
記事は「--------」で区切られているので、この正規表現を使用して記事を分割します。
def split_entries(mt_text):
return re.split(r'--------\n', mt_text)
この記事を解析し、author(著者)、title(タイトル)、date(日付)、body(本文)のフィールドを抽出します。
def parse_entry(entry_text):
entry = {}
patterns = {
'author': r'AUTHOR:\s*(.*)',
'title': r'TITLE:\s*(.*)',
'date': r'DATE:\s*(\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2})',
'body': r'BODY:\n(.*?)(?=\n-----|\Z)',
}
for key, pattern in patterns.items():
match = re.search(pattern, entry_text, re.DOTALL)
if match:
entry[key] = match.group(1).strip()
if 'date' in entry:
entry['date'] = format_date(entry['date'])
return entry
日付フォーマットの変換
MovableType形式の日付をBlogger用に変換するため、この関数を使用します。もし異なる日付形式が検出された場合には、バックアップフォーマットで再度試行します。
def format_date(date_str):
try:
date_str = date_str.strip()
date_obj = datetime.strptime(date_str, '%m/%d/%Y %H:%M:%S')
return date_obj.strftime('%Y-%m-%dT%H:%M:%S') + '+09:00'
except ValueError as e:
print(f"Error parsing date, attempting alternative formats: {date_str}")
try:
date_obj = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
return date_obj.strftime('%Y-%m-%dT%H:%M:%S') + '+09:00'
except ValueError:
raise e
XMLの生成
この関数では、Bloggerに対応するXML形式を生成します。それぞれの記事の著者、タイトル、本文などをXMLの要素として追加します。
def create_xml(entries):
root = Element('feed', xmlns="http://www.w3.org/2005/Atom")
for entry in entries:
entry_elem = SubElement(root, 'entry')
author_elem = SubElement(entry_elem, 'author')
name_elem = SubElement(author_elem, 'name')
name_elem.text = entry.get('author', 'Unknown')
title_elem = SubElement(entry_elem, 'title')
title_elem.text = entry.get('title', 'No Title')
published_elem = SubElement(entry_elem, 'published')
published_elem.text = entry.get('date', '')
content_elem = SubElement(entry_elem, 'content', type="html")
content_elem.text = entry.get('body', '')
return root
XMLファイルの保存
生成されたXMLをファイルとして保存します。
def save_xml_file(root, output_path):
tree = ElementTree(root)
tree.write(output_path, encoding='utf-8', xml_declaration=True)
実行方法
最後に、メインの処理です。
main
関数では、MovableType形式のファイルを読み込み、記事ごとに解析し、XMLファイルを生成します。
def main(mt_file_path, output_xml_path):
mt_text = read_mt_file(mt_file_path)
entry_texts = split_entries(mt_text)
entries = []
for entry_text in entry_texts:
if entry_text.strip():
entries.append(parse_entry(entry_text))
xml_root = create_xml(entries)
save_xml_file(xml_root, output_xml_path)
print(f"XMLファイルが生成されました: {output_xml_path}")
使用例
はてなブログからエクスポートしたMovableType形式の.txtファイルをBlogger用のXMLファイルに変換し、output/output_blogger.xmlに保存します。
mt_file_path = 'input/xxx.hatenablog.com.export.txt' # はてなブログからエクスポートした.txtファイルのパス
output_xml_path = 'output/output_blogger.xml' # 変換後のXMLファイルの保存先
main(mt_file_path, output_xml_path)