[Beautiful Soup] HTMLの好きな範囲をコメントアウトする方法

Beautiful Soupで扱うHTMLの任意の場所に、コメントアウトの開始 `<!--` と終了 `-->` を挿入する方法です。

検索しても出てこないから一応公開してみるけど…たぶん需要はない！
ほとんどネタです。


# 環境
Python 3.11.9
Beautiful Soup 4 (4.11.1)


# HTMLの好きな範囲をコメントアウトする

## 扱うHTMLサンプル
以下のようなHTMLを扱うことにします。
```html:tanuki.html
<html>
<head>
    <title>暗号文</title>
</head>
<body>
    <h1>ヒント：たぬき＆にわとり</h1>
    <p>
        <span class="gomi start">わ</span>
        <span class="gomi">た</span>
        <span class="gomi">わ</span>
        <span class="gomi">に</span>
        <span class="gomi end">た</span>
        <span class="important">ぱ</span>
        <span class="gomi start">わ</span>
        <span class="gomi">わ</span>
        <span class="gomi">た</span>
        <span class="gomi">に</span>
        <span class="gomi end">わ</span>
        <span class="important">ん</span>
        <span class="gomi start"></span>
        <span class="gomi">た</span>
        <span class="gomi">に</span>
        <span class="gomi">わ</span>
        <span class="gomi end"></span>
        <span class="important">だ</span>
    </p>
</body>
</html>

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652113/86cc4bbc-e8a1-633b-5f08-dfebf678fe94.png)

`<span class="gomi start">` ～ `<span class="gomi end">...</span>` までをコメントアウトしたい！

## コメントアウトするPythonコード

```python
import bs4

# HTMLを読み込み
with open("tanuki.html", encoding="utf-8") as f:
    html = f.read()
soup = bs4.BeautifulSoup(html, "html.parser")

# コメントアウトの開始を挿入する
for gomi_start in soup.select("span.gomi.start"):
    comment_out_start = soup.new_tag("!-- ")  # <!-- > ～ </!-- >
    gomi_start.insert_before(comment_out_start)

# コメントアウトの終了を挿入する
for gomi_end in soup.select("span.gomi.end"):
    comment_out_end = soup.new_tag("--", _="")  # <-- _=""> ～ </-->
    gomi_end.insert_after(comment_out_end)

# 結果をHTMLに出力
with open("out.html", "w", encoding="utf-8") as f:
    f.write(str(soup))  # だいたい意図した感じにコメントアウトされる！
```

これを実行すると以下のようなHTMLが出力されます。

```html:out.html
<html>
<head>
<title>暗号文</title>
</head>
<body>
<h1>ヒント：たぬき＆にわとり</h1>
<p>
<!-- ></!-- ><span class="gomi start">わ</span>
<span class="gomi">た</span>
<span class="gomi">わ</span>
<span class="gomi">に</span>
<span class="gomi end">た</span><-- _=""></-->
<span class="important">ぱ</span>
<!-- ></!-- ><span class="gomi start">わ</span>
<span class="gomi">わ</span>
<span class="gomi">た</span>
<span class="gomi">に</span>
<span class="gomi end">わ</span><-- _=""></-->
<span class="important">ん</span>
<!-- ></!-- ><span class="gomi start"></span>
<span class="gomi">た</span>
<span class="gomi">に</span>
<span class="gomi">わ</span>
<span class="gomi end"></span><-- _=""></-->
<span class="important">だ</span>
</p>
</body>
</html>

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652113/fbe8928e-4302-0b9d-ae6a-a5134d2df52c.png)

ちゃんとコメントアウトされてる！
そして、き、汚い！！！


## からくり

### コメントアウトの開始 `<!--` の挿入
```py
# コメントアウトの開始を挿入する
for gomi_start in soup.select("span.gomi.start"):
    comment_out_start = soup.new_tag("!-- ")  # <!-- > ～ </!-- >
    gomi_start.insert_before(comment_out_start)
```
ここのコードでは、`span.gomi.start` の直前に `<!-- >` タグを挿入しています。
ダブルハイフンの後に空白を入れることで、閉じタグが `</!-->` ではなく `</!-- >` になります。
`-->` が切り離されるため、コメントアウトの終了と扱われなくなります。

### コメントアウトの終了 `-->` の挿入
```py
# コメントアウトの終了を挿入する
for gomi_end in soup.select("span.gomi.end"):
    comment_out_end = soup.new_tag("--", _="")  # <-- _=""> ～ </-->
    gomi_end.insert_after(comment_out_end)
```
ここでは、`span.gomi.end` の直前に `<-->` タグを挿入しています。
`-->` が目的なのですが、そのままだと開始タグの `<-->` でコメントアウトが終了してしまう！

そこで、タグに属性 `_` を追加することで、開始タグが`<-->`ではなく`</!-- _="">`になります。
`-->`が切り離されるため、開始タグがコメントアウトの終了と扱われなくなり、ゴミが描画されなくなります。

# おまけ：コメントを追加する方法
「コメントアウト」でなくて、シンプルにコメントタグを追加したいだけなら真っ当な方法があります。
```python
html_comment = bs4.Comment("コメントだよ")
soup.append(html_comment)
print(soup)
```

# 感想
変なバッドノウハウをQiitaにアップロードするんじゃないよ！！