Pukiwiki を html 化する修行
Wiki を html に落としたい。バックアップ目的だったり、Wiki をオーサリングツールとして使ったり、とそんな要求もあるだろう。とにかく、そんなことがしたかったので、Python で書いてみた。
- Wiki エンジンは PukiWiki 1.4.7
- サイトには BASIC 認証をかけてある
- リンクはおおむね張れていればいいこととする
- 単語検索結果のページとか、静的に作っておくのが難しいリンクは張れていなくてもあきらめる
- 添付ファイルはあきらめる
# wiki2html.py for python3 import urllib.request import hashlib import codecs import re import sys import functools username = 'user' password = 'secret' base_url = 'http://pukiwiki.example.com/' charset = 'EUC-JP' realm = 'PukiWiki Area' base_dir = '/home/takeyuki/pukiwiki/' pattern = r'<a' +\ r'(?P<pre> (?: \s+ \w+="[^"]+")* )' +\ r'\s+ href="' + base_url + r'\?(?P<query>[^"]+)"' +\ r'(?P<post> (?: \s+ \w+="[^"]+")* \s*)' +\ r'>' ro = re.compile(pattern, re.VERBOSE) auth_handler = urllib.request.HTTPBasicAuthHandler() auth_handler.add_password(realm, base_url, username, password) opener = urllib.request.build_opener(auth_handler) urllib.request.install_opener(opener) ro2 = re.compile(r'cmd=read&page=') def get_file_name(query): table = { 'Top' : 'index.html', 'cmd=list' : 'list.html' } query = ro2.sub('', query) return table[query] if query in table \ else hashlib.sha1(query.encode()).hexdigest() + '.html' def convert(listup, match): query = match.group('query') path = get_file_name(query) if listup: if not query in pages: pages[query] = Page(query) return '<a{} href="{}"{}>'.format(match.group('pre'), path, match.group('post')) class Page: def __init__(self, query): self.query = query def download(self): file = get_file_name(self.query) sys.stderr.write("{} -> {}\n".format(self.query, file)) url = base_url + '?' + self.query res = urllib.request.urlopen(url) content = '' for line in res.readlines(): try: content = content + line.decode(charset) except UnicodeDecodeError as e: pass res.close() func = functools.partial(convert, self.query == 'cmd=list') str = ro.sub(func, content) f = codecs.open(base_dir + file, 'w', 'EUC-JP') f.write(str) f.close() list_page = Page('cmd=list') pages = {} list_page.download() for page in pages.values(): page.download()
いろいろと苦心している様が見て取れるコード。美しくない。
メモ。
- Query String を sha1 で 16 進表記したファイル名にしている
- 「?cmd=read&page=X」と「?X」は同じ結果になるっぽいので一応対処している
- 最初に「?cmd=list」で得られるページ一覧を取得する
- HTML 内のリンクを書き換えつつ、辞書に保管しておく
- 辞書に保管された Query String でページを取得していく
- このときは HTML 内のリンクを書き換えても辞書を更新しない
- デコードエラーのときはそのバイト列を破棄する
- この辺、投げやり