【メモ】【コピペでOK】PythonでURLやJSONを安全に扱う方法

ネットを見ていて、以下の情報を見つけました。入力情報などでURLがあった場合にURL.canParse()メソッドを使用して、その妥当性を判定できます。アクセス前にURLの妥当性を確かめられるのはとても便利です😊

azukiazusa.dev

私は、JavaScriptではなくPythonを使用する事が多いので、同じ処理をPythonでも出来ないかなと思って調べてみました。また、LLMを使用する中で、APIを使用した際、データの受信途中でJSONデータができなくなることがあるので、それについてもチェック方法を調べてみたいなと思います。

PythonでURL文字列の妥当性を判定する

PythonでもJavaScriptのURLコンストラクターのようにURLの妥当性を判定する方法があります。その方法の一つはurllib.parseモジュールを使用することです。以下のように、URLをパースして判定します。

妥当性のチェックコード

from urllib.parse import urlparse
from typing import Union

def is_valid_url(url: str) -> bool:
    """
    URLが有効な形式かどうかを検証します。

    Args:
        url (str): 検証するURL文字列

    Returns:
        bool: URLが有効な場合はTrue、無効な場合はFalse

    Examples:
        >>> is_valid_url("https://example.com")
        True
        >>> is_valid_url("invalid-url")
        False
    """
    try:
        result = urlparse(url)
        return all([result.scheme, result.netloc])
    except ValueError:
        return False

# 実行例
print(is_valid_url("https://example.com"))  # Trueを返す
print(is_valid_url("invalid-url"))          # Falseを返す

Pythonでも無事にURL文字列の形式チェックができるようになりました。

JSON文字列の妥当性のチェック

では、LLMAPIから使用した場合に応答で得たJSON形式のデータの妥当性を検証するにはどうしたら良いでしょうか。APIを使用していると稀にデータの欠損などで不完全なデータの受信もありえるので、この確認も事前にできる助かることが多いです。

この場合には標準のjsonモジュールを使用して確認を行います。json.loads()メソッドはこれまでも単純な変換に使用していましたが、tryを使うことでチェック用にもできるようです。exceptionjson.JSONDecodeErrorを用いるのがポイントですね。

妥当性のチェックコード

import json
from typing import Union

def is_valid_json(json_string: str) -> bool:
    """
    JSON文字列が有効なフォーマットかどうかを検証します。

    Args:
        json_string (str): 検証するJSON形式の文字列

    Returns:
        bool: JSON文字列が有効な場合はTrue、無効な場合はFalse

    Examples:
        >>> is_valid_json('{"name": "Alice", "age": 30}')
        True
        >>> is_valid_json('{name: Alice, age: 30}')
        False
    """
    try:
        json.loads(json_string)
        return True
    except json.JSONDecodeError:
        return False

# 使用例
print(is_valid_json('{"name": "Alice", "age": 30}'))  # Trueを返す
print(is_valid_json('{name: Alice, age: 30}'))        # Falseを返す

APIなどでJSON形式のデータを受信する際には一度チェックすると安定すると思います。

YAMLの妥当性のチェック

Docker ComposeGitHub ActionsKubernetesなどでも使用されるYAML形式のデータも確認できるといいですね。PythonYAML形式のデータの妥当性を確認するにはPyYAMLというモジュールを使用します。

モジュールのインストール

以下でインストールを行います。必要に応じて仮想環境を使用してください。

$ pip install PyYAML

妥当性のチェックコード

import yaml
from typing import Union

def is_valid_yaml(yaml_string: str) -> bool:
    """
    YAMLフォーマットの文字列が有効かどうかを検証します。

    Args:
        yaml_string (str): 検証するYAML形式の文字列

    Returns:
        bool: YAML文字列が有効な場合はTrue、無効な場合はFalse

    Examples:
        >>> is_valid_yaml("name: Alice\\nage: 30")
        True
        >>> is_valid_yaml("name: Alice\\nage:")
        False
    """
    try:
        yaml.safe_load(yaml_string)
        return True
    except yaml.YAMLError:
        return False

# 使用例
print(is_valid_yaml("name: Alice\nage: 30"))  # Trueを返す
print(is_valid_yaml("name: Alice\nage:"))     # Falseを返す

こちらもデータの確認が行えました。

おまけ

おまけとしてreモジュールを使用してメールアドレス電話番号の妥当性のコードも追記しておきます。

おまけ:メールアドレスの妥当性検証

import re
from typing import Union

def is_valid_email(email: str) -> bool:
    """
    メールアドレスが有効な形式かどうかを検証します。

    Args:
        email (str): 検証するメールアドレス文字列

    Returns:
        bool: メールアドレスが有効な場合はTrue、無効な場合はFalse

    Examples:
        >>> is_valid_email("example@example.com")
        True
        >>> is_valid_email("invalid-email")
        False
    """
    pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
    return re.match(pattern, email) is not None

# 使用例
print(is_valid_email("example@example.com"))  # Trueを返す
print(is_valid_email("invalid-email"))        # Falseを返す

おまけ:電話番号の妥当性検証

import re
from typing import Union

def is_valid_phone_number(phone: str) -> bool:
    """
    日本の電話番号が有効な形式かどうかを検証します。

    Args:
        phone (str): 検証する電話番号文字列(xx-xxxx-xxxx形式)

    Returns:
        bool: 電話番号が有効な場合はTrue、無効な場合はFalse

    Examples:
        >>> is_valid_phone_number("03-1234-5678")
        True
        >>> is_valid_phone_number("123-456-7890")
        False
    """
    pattern = r'^\d{2,4}-\d{2,4}-\d{4}$'
    return re.match(pattern, phone) is not None

# 使用例
print(is_valid_phone_number("03-1234-5678"))  # Trueを返す
print(is_valid_phone_number("123-456-7890"))  # Falseを返す

おわりに

Pythonを使ったデータ検証の基本的な方法を調べてみました。URLJSONYAML、さらにはメールアドレス電話番号まで、プログラミングでよく扱うデータの形式チェックが簡単にできます。メールアドレス電話番号は既知のものですけど🙃

これらの方法を活用することで、外部からのデータを扱う際のエラーを未然に防ぎ、より安定したプログラムを作ることができます。特にAPIを使用する場合、Webアプリケーションを開発する場合には大きな効果があると思います。

/* -----codeの行番号----- */