はじめに
例えば、自分の中ではあるあるなのですが、静的HTML*1のサイトのデータについてある要素を一括書き換えする...みたいなニーズがあります。
CMSやなんらかの仕掛けによりあっさり完了ということも多いでしょうが、一方、そうでないこともやはり少なくない気がします。
仮にCMS管理されていても、フィールド管理されているデータならまだしも、フリーテキストの中に埋もれているような要素だとすると結構やっかいです。
また、書き換えたい内容が、htmlの形にしたもので初めて条件が決まる場合もあり、この場合は出力内容のhtmlのテキストで物事を見る必要があるため、もっと厄介でしょう。
いずれにせよ、最終的には機械的な置換で対応できるとしても、取りうる手法の中でもっとも妥当な方法を見出す前に、いくつかデータ調査を行う必要もあるでしょう。
スゴ腕の人は最短距離で進めることもできるのでしょうし、本格アプリ・機能として実現するならそれなりのフレームワークや準備が可能です。
一方、私のようなそうではないヒトは、まずはその際に許される環境やその時期に自分の手に馴染んでいる言語などで、安心して実験できるアドホックで、かつナイーブゆえに取り回しやすい、スキャフォールドがあると便利だと感じています。
コピーして書き直して...
大層なことを言いましたが、前項の目的にしたがった一例として、あるディレクトリを再帰的に巡回して、ひとまずメモリに読み込んで、ターゲットディレクトリに階層をそのまま吐き出すPythonプログラムの例です。
import glob import os import sys import codecs # コピー先のディレクトリと既存でそのディレクトリが存在しても上書きするかのチェック # コマンド起動時引数で制御した方がよさそうだが今回はそうはしていない FORCE = True EXPDIR = 'foo' # syncディレクトリの拡張子がhtmlのファイルを一括で読み込む # ※ファイル数がある程度限られること、ツール扱いであることを前提として次の処理とした。 file_names = [i for i in glob.glob('**',recursive=True) if i.startswith('sync/') and i.endswith('.html') ] files = [] for fn in file_names: print(fn,file=sys.stderr) with codecs.open(fn, 'r', 'utf-8') as f: files.append({'fn':fn, 'data': f.read()}) # 出力ディレクトリを生成して、そのディレクトリに移動 try: if FORCE: os.makedirs(EXPDIR,exist_ok=True) else: os.makedirs(EXPDIR) except FileExistError: print('出力用ディレクトリが存在します。', file=sys.stderr) sys.exit() try: os.chdir(EXPDIR) except: print('出力用ディレクトリに移動できませんでした。', file=sys.stderr) sys.exit() for f in files: fn = f['fn'] fdata = f['data'] """ ここでfdataに対して、リンクの変換などを実験する。 """ os.makedirs(os.path.dirname(fn), exist_ok=True) outputdata = fdata with codecs.open(fn, 'w', 'utf-8') as f: f.write(outputdata)
まとめ
もともとこのブログの対象読者ターゲットは私自身なのですが、今回はいつも以上かも。
この類のスニペットは厳格に管理するものでもないので、こんな感じでリマインダにしておくのが都合が良いのです。
追伸
Pythonに限らないが、複数階層のディレクトリ作成は標準のライブラリの中でもベーシックな関数では作成できなくて、応用型の関数に位置付けられる気がする。
一方、ツールの類ではディレクトリ名を与えるとサクッとディレクトリを掘って欲しいことも多い*2のだけど、Pythonの場合は、makedirsがそれにあたるので、上記のサンプルプログラムでもそれを使っている。
なお、自分は慣れていないので使っていないが、pathlibのPath.mkdirは、複数階層に対応してそう。
参考
ここまで読んでくれた方なら興味があるかもしれない他記事↓