見出し画像

pythonプログラム初歩(の初歩)3

pythonプログラム初歩(の初歩)3
URLアドレスの正当性確認

こんにちはmakokonです。
今日は初歩 (の初歩)です。基本的だけど入門ではないかな。

プログラムを書いていて、URLを参照するプログラムを書くことがあると思います。その時、ちょっとしたミスで指定したアドレスが間違っていただけで、プログラムが止まるのは辛いものです。
「なんで自分は、エラーチェックしていなかったんだ」とか考えるものです。

せめて、文字列がURLとして正しい形かどうかくらい確認してみましょう。
ついでに、文字列が画像(イメージ)を示しているかどうかを2つの方法で試してみましょう。


検証

検証用コード

まず、今回のコード全体を示します。

# lesson03.py
from urllib.parse import urlparse
import os
def is_valid_url(url):
    try:
        result = urlparse(url)
        # スキーマがhttpまたはhttpsであることも確認
        return all([result.scheme in ['http', 'https'], result.netloc])
    except ValueError:
        return False

def is_image_url(url):
    IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp']
    # URLが正当であることを確認
    if not is_valid_url(url):
        return False
    # URLのパスからファイルの拡張子を取得
    path = urlparse(url).path
    ext = os.path.splitext(path)[1]
    # 拡張子が画像のものであるかを確認
    return ext.lower() in IMAGE_EXTENSIONS

import requests
def is_image_url_c(url):
    """
    Check if the URL points to an image file by checking the beginning of the Content-Type header
    """
    # URLが正当であることを確認
    if not is_valid_url(url):
        return False

    # Send a HTTP HEAD request
    response = requests.head(url)
    # Check if "content-type" header exists and starts with "image"
    if "content-type" in response.headers and response.headers["content-type"].startswith("image"):
        return True
    else:
        return False


# テスト
url = input('確認するURLを入力してください: ')

if is_valid_url(url):
    print("与えられた文字列はURLとして正当です")
else:
    print("与えられた文字列はURLではありません。")
print("\n画像かどうかを拡張子でチェックする")
if is_image_url(url):
    print("与えられた文字列は画像を示すURLです")
else:
    print("与えられた文字列は画像を示すURLではありません。")
print("\n画像かどうかをcontent-typでチェックする")
if is_image_url_c(url):
    print("与えられた文字列は画像を示すURLです")
else:
    print("与えられた文字列は画像を示すURLではありません。")

is_valid_url(url)

入力されたURLの構造を調べてその正当性を返します。
is_image_url_c(url)関数を使ってURLに含まれる情報を取得しています。
今回はスキーマが存在し、httpまたはhttpsで6つのコンポーネント(情報)を取得します。
その中で、スキーマがhttpまたはhttpsであることをチェックします。
また、ネットロケーション(ドメイン)が存在することをチェックします。
ただし、実際に入力されたURLが存在しているかどうかはわからないことに注意しましょう。

is_image_url(url)

URLの構造の正当性をチェックしたあと、手っ取り早く名前だけでチェックします。具体的には画像の情報は拡張子が、`.jpg`、`.png`、`.gif`などでおあわるので、その拡張子の文字列をチェックします。
今回対象とした拡張子は、['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp']です。
拡張子の取得は、
path = urlparse(url).path
ext = os.path.splitext(path)[1]
です。
ただし、この方法ではURLが実際に画像を示しているかは確認できません。URLが存在し、その拡張子が画像のものであっても、そのURLが実際に画像を返すとは限りません。

is_image_url_c(url)

requestsコマンドを使って、HTTPヘッダを取得してcontent-typeを取得しています。これがimage始まるなら画像ということになります。これは、なかなかに便利な方法で画像以外のチェックにも使いやすいので、重宝します。

画像判定の使い分け

まあ、説明を読んでおわかりでしょうが、2つの方法にはそれぞれいいところも悪いところもあります。
content-typeによる方法は、実際にURLが画像を返すかどうか確認することができることを期待できる反面、サーバーによっては、content-typeヘッダを適切に設定しないことがあって、時々空振ります。これを回避しようと、
全部読み込んでみると、通信量がやたら増えることになります。
一方、拡張子による判定は、とても素早く簡単に判定できます。だとすると、プログラムの目的が画像の中身を確認することにあるのならば、coontent-typeによる判定が適していて、とりあえずURL形式をチックするなら拡張子による判定が優れています。

まとめ

いかがでしたか。今日はURLの名前の正当性をチェックしました。URLの構造から、適切な情報を取得することと、その情報が目的にかなったものであることをチェックしました。
いつでも正しく、入力されることが保証されているのなら、チェックなんていらないような問題なのですが、エラーチェックのないプログラムは安心してツケません。URL入力に限らず、LLMの回答が帰ってこないとか、目的サーバーがダウンしているとか、なるべくケアできることはしときたいですね。

付録 今日の重要ライブラリ

urlparse(url)

URLに含まれる6種類の情報を取得することができます。

  • `scheme` URLのスキーマ(例: 'http', 'https', 'ftp'など)。

  • `netloc`: ネットワークロケーション部分で、通常はホスト名とオプションのポート番号を含みます(例: 'www.google.com', 'localhost:8000'など)。

  • `path`: URLのパス部分(例: '/index.html', '/user/profile'など)。

  • `params`: パラメータ部分。これはパスの一部として現れ、セミコロン(';')で区切られます。しかし、現代のWebではほとんど使われません。

  • `query`: クエリ部分。これはクエリパラメータを含み、'?'で始まり、'&'で複数のパラメータを区切ります(例: '?key1=value1&key2=value2'など)。

  • `fragment`: フラグメント部分。これはURL内の特定の部分(例えばWebページ内の特定のセクション)を指すために使われ、'#'で始まります(例: '#section1'など)。

content-type

"content-type"ヘッダはHTTPレスポンスの一部で、そのレスポンスのメディアタイプ(MIMEタイプ)を示します。これにより、クライアントはレスポンスがどのような種類のデータを含んでいるのかを理解することができます。

以下に、よく使われる"content-type"の値を示します:

  • `text/html`: HTML文書

  • `text/plain`: プレーンテキスト

  • `application/json`: JSONデータ

  • `application/xml`: XMLデータ

  • `image/jpeg`, `image/png`, `image/gif`: JPEG、PNG、GIFなどの画像

  • `video/mp4`, `video/mpeg`: MP4, MPEGなどのビデオ

  • `audio/mpeg`, `audio/ogg`: MP3, Oggなどのオーディオ

  • `application/octet-stream`: バイナリデータ

  • `application/pdf`: PDF文書

  • `application/zip`: ZIPアーカイブ

これらの"content-type"の値に基づいて、レスポンスがどのような種類のデータを含んでいるのかを判断することができます。例えば、"content-type"が`image/jpeg`であれば、そのレスポンスはJPEG画像を含んでいるということになります。

ただし、"content-type"ヘッダはサーバーによって設定されるため、サーバーが正しい値を設定していない場合、クライアントは誤った情報を受け取る可能性があります。したがって、"content-type"ヘッダに基づいて重要な処理を行う場合は注意が必要です。

おまけ タイトル画像の説明 by  GPT-4V

画像には、オフィスのデスクで作業している、ストレスを感じているアニメーションされたキャラクターが描かれています。彼は開けたシャツと赤いネクタイを身に着け、頭を掴む姿勢でコンピューターモニターを見つめています。モニターにはプログラミングコードが表示されており、彼の周囲には疑問符と湯気のようなマークが浮かんでおり、困惑やフラストレーションを表現しています。デスクの上には雑多な紙の山があり、彼の仕事の厳しさを示しています。



この記事が気に入ったらサポートをしてみませんか?