フリーランス 技術調査ブログ

フリーランス/エンジニア Ruby Python Nodejs Vuejs React Dockerなどの調査技術調査の備忘録

python/BeautifulSoupを利用して複数HTMLファイルを一括置換する

はじめに

  • 直近で某サイトのヘッダーやサイドナビが各ページに記述されており、ヘッダーやサイドナビが変更が発生するたびに対象ページをgrep 置換している運用しているサイトがあり、ヘッダーやサイドナビを共通化してほしいというお題を頂いたので、手作業で修正するよりプログラムで一括できないか調査してみた。

HTMLタグを置換するプログラム (その①)

  • BeautifulSoupを利用して置換対象のタグを取得し、取得した箇所の文字列を置換処理で対応をしようとしたところ、BeautifulSoupでHTMLを読み込むとパーサーがHTMLのフォーマットを勝手に置換してしまい、修正する必要がない箇所も修正してしまっていました。 またPHPソースコードエスケープしていまい、今回の作業には向かなかったので、違う方法を検討する。
import os
from html.parser import HTMLParser
from bs4 import BeautifulSoup

ROOT_PATH = '/code'
def find_all_files(directory):
    for cur_dir, dirs, files in os.walk(directory):
        for file in files:
            yield os.path.join(cur_dir, file)

## 共通ヘッダー変換
def header_change(): 
    for file in find_all_files(ROOT_PATH):
        if ('.htm' in file or '.php' in file):
            f = open(file, 'r+', encoding='UTF-8', errors='ignore')
            data = f.read()
            soup = BeautifulSoup(data, 'html.parser')
            new_tag = soup.new_tag('b')
            new_tag.string = "一時的に挿入する文字列です。その後置換する文字列に切り替わります。"
            nav = soup.find("nav")
            if nav is None:
                print(f'ヘッダーがないページ,{file}')
            else:                 
                soup.nav.insert_before(new_tag)
                soup.nav.extract()
                f.seek(0)
                new_html = soup.prettify(formatter=None)
                if ('en/' in file):
                    print(f'英語ページ,{file}')
                    f.write(new_html.replace('<b>一時的に挿入する文字列です。その後置換する文字列に切り替わります。</b>', "<?php include($_SERVER['DOCUMENT_ROOT'].'/common/html/global_navi_en.html'); ?>"))
                    f.write(data.replace(str(nav), "<?php include($_SERVER['DOCUMENT_ROOT'].'/common/html/global_navi_en.html'); ?>"))
                else:
                    print(f'日本語ページ,{file}')
                    f.write(new_html.replace('<b>一時的に挿入する文字列です。その後置換する文字列に切り替わります。</b>', "<?php include($_SERVER['DOCUMENT_ROOT'].'/common/html/global_navi.html'); ?>"))
                f.truncate()
                f.close()    
            f.close()

header_change()

HTMLタグを置換するプログラム (その②)

  • 下記のプログラムは対象ディレクトにあるHTMLファイルおよびPHPファイルの中に記述されている特定のタグの開始位置と終了位置を取得し、取得した位置の範囲あるタグを共通ヘッダーを読み込む処理のコードに置換する処理となっております。 下記の記述にすることで特に問題なく置換することができました。
import os

ROOT_PATH = '/code'

def find_all_files(directory):
    for cur_dir, dirs, files in os.walk(directory):
        for file in files:
            yield os.path.join(cur_dir, file)


## 共通ヘッダー変換
def header_change(): 
    for file in find_all_files(ROOT_PATH):
        if ('.htm' in file or '.php' in file):
            f = open(file, 'r+', encoding='UTF-8', errors='ignore')
            data = f.read()
            start = data.find('<nav id="globalNav">', 0)
            end = data.find('</nav>', start)
            if start == -1:
                print(f'ヘッダーがないページ,{file}')
            else:
                if ('common/html' not in file):
                    f.seek(0)
                    if ('en/' in file):
                        print(f'Englishページ,{file}')
                        f.write(data.replace(data[start:end+6], "<?php include($_SERVER['DOCUMENT_ROOT'].'/hoge_navi_en.html'); ?>"))
                    else:
                        print(f'日本語ページ,{file}')
                        f.write(data.replace(data[start:end+6], "<?php include($_SERVER['DOCUMENT_ROOT'].'/hoge_navi.html'); ?>"))
                    f.truncate()
            f.close()

header_change()

上記の件を動かしていた環境

docker-compose.yml

version: '3'
services:
  python:
    build: .
    volumes:
      - ../htdocs:/code
    tty: true

Dockerfile

FROM python:3.10-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt

requirements.txt

beautifulsoup4