これらの関数を使用するには 標準モジュール urllib.parse のインポートが必要です。
import urllib.parse
# quote関数を使用
result = urllib.parse.quote('日本語')
print(result) # 結果 = %E6%97%A5%E6%9C%AC%E8%AA%9E
# quote_plus関数を使用
result = urllib.parse.quote_plus('日本語')
print(result) # 結果 = %E6%97%A5%E6%9C%AC%E8%AA%9E
URLデコード
import urllib.parse
# unquote関数を使用
result = urllib.parse.unquote('%E6%97%A5%E6%9C%AC%E8%AA%9E')
print(result) # 結果 = '日本語'
# unquote_plus関数を使用
result = urllib.parse.unquote_plus('%E6%97%A5%E6%9C%AC%E8%AA%9E')
print(result) # 結果 = '日本語'
URLエンコーディング
URLエンコード を行うには、quote() または quote_plus() 関数を使用します。 quote()関数 は URL中 の パス をエンコードするのに適しており、quote_plus()関数 は クエリストリング(クエリ文字列) をエンコードするのに適しています。文字 | quoteのエンコード結果 | quote_plusのエンコード結果 |
---|---|---|
スラッシュ(/) | 変換されない | %2F |
スペース | %20 | + |
パス と クエリストリング(クエリ文字列)
例えば次のような URL があるとき、 パス は /search、クエリストリング は URL+エンコード方法 です。この URL は Google の 検索結果ページ を表示します。/search は検索結果ページを指し、 q=URL+エンコード方法 は「URL エンコード方法」を検索することを指示しています。https://www.google.com/search?q=URL+エンコード方法
クエリストリング中の スラッシュ(/) は ディレクトリ階層 と誤認するため、quote_plus()関数 では %2F に変換します。また、クエリストリングではスペースの代わりに + または %20 を使用できます。そのため、quote_plus()関数 では スペース を + に変換します。
スペース を + ではなく、%20 に 変換したい場合は quote()関数 を使用し、次のように 引数 safe に 空文字列 を渡します。
import urllib.parse
# quote関数を使用し、+ を %20 にエンコード
result = urllib.parse.quote(' ', safe='')
print(result) # 結果 = '%20'
# safe='' を指定することで、スラッシュ(/) も変換される。
result = urllib.parse.quote('/', safe='')
print(result) # 結果 = '%2F'
通常、quote()関数 は スラッシュ(/) を変換しません。しかし、引数 safe に空文字列を指定すると、スラッシュ(/) も変換対象となります。これは、引数 safe に渡した文字が変換対象から除外されるためです。デフォルトでは、safe引数 の値は '/' です。
quote_plus()関数 も、quote()関数 と同じように、エンコーディング対象から除外する文字を指定できる safe引数 を持っています。ただし、この関数では safe のデフォルト値は 空文字列('') のため、スラッシュ(/) は %2F に変換されます。
quote()関数 と quote_plus()関数 でエンコードされない文字
quote()関数 は URLのエンコードを目的としているため、引数 safe が 空文字列 の場合でも、次の文字は エンコードされません。文字 | 読み / 説明 | 文字コード(10進) | 文字コード(16進) |
---|---|---|---|
ー | ハイフンマイナス(hyphen-minus) | 45 | 0x2D |
. | ピリオド(period) | 46 | 0x2E |
0 ~ 9 | 数字 | 48 ~ 57 | 0x30 ~ 0x39 |
A ~ Z | 大文字 アルファベット | 65 ~ 90 | 0x41 ~ 0x5A |
_ | アンダースコア(underscore) | 95 | 0x5F |
a ~ z | 小文字 アルファベット | 97 ~ 122 | 0x61 ~ 0x7A |
~ | チルダ(tilde) | 126 | 0x7E |
quote()関数 と quote_plus()関数 の違いまとめ
quote()関数 と quote_plus()関数 の違いをまとめると、次のようになります。quote関数 | quote_plus関数 | |
---|---|---|
スペース の変換結果 | %20 | + |
引数 safe の規定値 | '/' | '' |
URLデコーディング
URLデコード を行うには、unquote() または unquote_plus() 関数を使用します。 unquote()関数 は URL中 の パス をデコードするのに適しており、unquote_plus()関数 は クエリストリング(クエリ文字列) をデコードするのに適しています。unquote()関数 と unquote_plus()関数 の違いは、+ 記号の変換結果だけです。
文字 | unquoteのデコード結果 | unquote_plusのデコード結果 |
---|---|---|
+ | +(変換されない) | スペース |
エンコーディング(文字コード)の指定
quote() および quote_plus()関数、unquote() および unquote_plus()関数 では、引数 encoding で エンコーディング を指定できます。引数 encoding を省略した場合の規定値は、'UTF-8'です。エンコードとデコードのエンコーディングが一致していないと、エラーや文字化けを引き起こします。次に、エンコーディング を指定して エンコード と デコード を行う例を示します。
# shift-jis で エンコード
result = urllib.parse.quote('日本語', encoding='shift-jis')
print(result) # 結果 = %93%FA%96%7B%8C%EA
# UTF-8 で エンコード
result = urllib.parse.quote('日本語')
print(result) # 結果 = %E6%97%A5%E6%9C%AC%E8%AA%9E
# shift-jis で デコード
result = urllib.parse.unquote('%93%FA%96%7B%8C%EA', encoding='shift-jis')
print(result) # 結果 = 日本語
# UTF-8 で デコード
result = urllib.parse.unquote('%E6%97%A5%E6%9C%AC%E8%AA%9E')
print(result) # 結果 = 日本語
エラー処理
エンコーディングできない場合の動作
quote() および quote_plus()関数 の errors引数を使用すると、エンコーディングが失敗したときの動作を変更できます。 デフォルトは 'strict' で、エンコーディング失敗時には UnicodeEncodeError エラーが発生します。次に、エラーの発生例を示します。絵文字 ♫ は shift-jis に変換できないため、UnicodeEncodeError エラーが発生します。
try:
urllib.parse.quote('♫', encoding='shift-jis', errors='strict')
except UnicodeEncodeError as err:
print(err) # 'shift_jis' codec can't encode character '\u266b' in position 0: illegal multibyte sequence
quote および quote_plus()関数 の errors引数 に指定できるパラメーター
errors引数を指定することで、エンコード失敗時に強制的にエンコードが可能なケースがあります。しかし、エンコード後の結果は、相手方サーバーにとってほとんど意味のないものです。 基本的にはエンコードできない場合は処理を中断し、別の手段を行うことが第一選択となります。-
errors='strict' (errors を 略時した場合のデフォルト値)
UnicodeEncodeError エラーが発生します。try - except で例外をキャッチしない場合、標準エラー(stderr)にエラーメッセージが出力され、プログラムは停止します。
-
errors='ignore'
変換できない文字を 空文字 に置き換えます。
-
errors='replace'
変換できない文字を 文字 '?' に置き換えます。
-
errors='backslashreplace'
変換できない文字を \uXXXX 形式のコードポイント文字列に置き換えます。
例えば 絵文字 ♫ の コードポイントは \u266b のため、%5Cu266b に変換されます。これを unquote()関数 でデコードすると、\u266b を返します。
-
errors='backslashreplace'
UNICODE に 変換できない文字を U+DC80 から U+DCFF の範囲に置き換えます。 unquote()関数 でデコードする際にも errors='backslashreplace' を指定することで、エンコード前の状態を復元します。ただしセキュリティを確保するため、一部の文字は変換されません。
-
errors='xmlcharrefreplace'
変換できない文字を HTMLやXML で使用される &#XXXX; 形式の文字参照(数値文字参照)に置き換えます。
例えば 絵文字 ♫ の コードポイントは \u266b のため、%26%239835%3B に変換されます。これを unquote()関数 でデコードすると、♫ を返します。
-
errors='namereplace'
変換できない文字を \N{Name property} 形式に置き換えます。Name property には、Unicode Character Database で定義されている名前が入ります。
例えば 絵文字 ♫ の場合、%5CN%7BBEAMED%20EIGHTH%20NOTES%7D に変換されます。これを unquote()関数 でデコードすると、\N{BEAMED EIGHTH NOTES} を返します。BEAMED EIGHTH NOTES は、連符の8分音符 を意味します。
デコーディングできない場合の動作
unquote() および unquote_plus()関数 も errors引数を持ちます。デフォルトは 'replace' で、エンコード失敗時に、エンコードできない文字を REPLACEMENT CHARACTER(U+FFFD �) に置きかえます。これは UNINODE で特殊な意味を持つ文字で、不明な文字 や 認識できない文字 を表します。次にエンコード失敗時の例を示します。文字列 '%99' は デコードできないため、\ufffd(REPLACEMENT CHARACTER) を返します。
result = urllib.parse.unquote('%99', errors='replace')
print(result) # 結果 = '�'(\ufffd “REPLACEMENT CHARACTER”)
unquote および unquote_plus()関数 の errors引数 に指定できるパラメーター
quote()関数 と比較すると、'xmlcharrefreplace' と 'namereplace' が使用できません。また、'replace' を指定すると quote()関数 では '?' を返しますが、unquote()関数 では 置換文字(REPLACEMENT CHARACTER) を返します。'strict' を指定すると例外が発生しますが、quote()関数 が「UnicodeEncodeError」であるのに対し、unquote()関数 では「UnicodeDecodeError」です。-
errors='replace' (errors を 略時した場合のデフォルト値)
変換できない文字を 置換文字(REPLACEMENT CHARACTER) に置き換えます。
-
errors='strict'
UnicodeDecodeError エラーが発生します。try - except で例外をキャッチしない場合、標準エラー(stderr)にエラーメッセージが出力され、プログラムは停止します。
-
errors='ignore'
変換できない文字を 空文字 に置き換えます。
-
errors='backslashreplace'
変換できない文字を \xXX 形式の文字列に置き換えます。
たとえば %99 の場合、 \x99 を返します。
-
errors='backslashreplace'
quote時に quote(xxx, errors='backslashreplace') とすると、UNICODE に 変換できない文字を U+DC80 から U+DCFF の範囲に置き換えてエンコードされます。同様に unquote 時にも 'backslashreplace' を指定することで、エンコード前の状態を復元します。
バイト列(bytes型)の エンコード と デコード
Python では 文字列(str型) の代わりに、バイト列(bytes型) を使用しても 文字 を扱うことができます。 quote() および quote_plus()関数、unquote() および unquote_plus()関数 では、bytes型 もサポートしています。バイト列 を エンコード または デコード するには、文字列(str型) の代わりに バイト列(bytes型) を渡すだけです。
次に バイト列 の エンコード と デコード を行う例を示します。
import urllib.parse
# str型 を bytes型 に変換
bytesValue = '日本語'.encode()
print(bytesValue) # 結果 = b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e'
# bytes列を URLエンコード
result = urllib.parse.quote(bytesValue)
print(result) # 結果 = %E6%97%A5%E6%9C%AC%E8%AA%9E
# URLエンコード結果(str型) を bytes型 に変換
bytesValue = result.encode()
print(bytesValue) # 結果 = b'%E6%97%A5%E6%9C%AC%E8%AA%9E'
# bytes列を URLデコード
result = urllib.parse.unquote(bytesValue)
print(result) # 結果 = 日本語
unquote_to_bytes()関数
unquote()関数 では 引数に バイト列を渡しても、デコード結果は 文字列型 で返されます。 一方、unquote_to_bytes()関数 を使用すると、引数の型に関わらず、デコード結果は バイト列 で返されます。なお、quote_plus()関数 に相当する関数は存在しません。
参考資料
- Python公式ドキュメント - urllib.parse.quote
- Python公式ドキュメント - urllib.parse.quote_plus
- Python公式ドキュメント - urllib.parse.unquote
- Python公式ドキュメント - urllib.parse.unquote_plus
- Python公式ドキュメント - urllib.parse.unquote_to_bytes
- Python公式ドキュメント - エラーハンドラ -- codecs
- Unicode Character Database
検証環境
- Python 3.11.3 (tags/v3.11.3:f3909b8, Apr 4 2023, 23:49:59) [MSC v.1934 64 bit (AMD64)] on win32
- Microsoft Windows 10 Enterprise Version 22H2 OS Build 19045.3930 Experience: Windows Feature Experience Pack 1000.19053.1000.0