2021/04/06

[Python]BeautifulSoup4でhtmlの解析

python

概要

特定のURLを入力値にとり、そのURLのHTMLコンテンツを取得し、タイトル・説明文・アイコン画像のURLなどを取得したかったため実装しました。

beautifulsoup4というものを利用させてもらいました。

実装

インストール

% poetry add beautifulsoup4
# 4.9.3をインストールして使用しました

実装内容

import requests
from bs4 import BeautifulSoup


url = "https://stackoverflow.com/questions/24688479/size-of-raw-response-in-bytes/24688721"

# see https://stackoverflow.com/questions/24688479/size-of-raw-response-in-bytes/24688721
with requests.get(url=url, stream=True) as response:  # 一気に取得すると大きいサイズのものだと困るので、 steam=True としてコンテンツを取得します。
    if response.status_code != 200:
        return False
    if "text/html;" not in response.headers.get("Content-Type"):  # htmlじゃないコンテンツは弾きます。(動画とか画像とか)
        return False
    size = 0
    content_bytes = bytearray(b'')
    for chunk in response.iter_content(8196):                     # 8196バイト毎に読み込みます。
        size += len(chunk)
        if size > 10 * 1024 * 1024:                               # 一定サイズを超えていたら、処理を終了します。今回は10MB
            # the content is too large to continue...
            return False
        content_bytes.extend(chunk)
    encoding = response.encoding if response.encoding else response.apparent_encoding
    text = str(content_bytes, encoding, errors='replace')
    soup = BeautifulSoup(text, features="html.parser")

    # headタグの中身を取得
    title = None
    description = None
    head_info = soup.find("head")
    if head_info:
        meta_title = head_info.find("title")
        if meta_title:
            title = meta_title.getText()
        meta_description = head_info.find("meta", {"name": "description"})
        if meta_description:
            description = meta_description["content"]
    
    print(title)
    print(description)

ポイント

  • コンテンツは一気に取得せず、chunksize毎に読み込み、大きいコンテンツの場合は無視します。
  • URLの中身が悪質なもの(ウィルスの入ったファイル)の可能性もあるので、考慮すべきです。(もしダウンロードして保存したり実行する場合などは特に)
  • このコードを応用すれば、画像ファイルだったら圧縮して保存とかもできそうです。

以上です。