PythonでURLエンコード・デコード(urllib.parse.quote, unquote)

Pythonの標準ライブラリのurllib.parseモジュールを使うと、文字列のURLエンコード(パーセントエンコーディング)、および、そのデコードを行うことができます。日本語を含むURLを処理するのに便利です。 urllib.parseモジュールをインポートします。標準ライブラリなので追加でインストールする必要はない。 import urllib.parse

urllib.parseモジュールはPython2ではurlparseモジュールという名前だった。 ここではPython3の場合について以下の内容を説明します。

URLエンコード(パーセントエンコーディング)とは URLエンコード: urllib.parse.quote()など urllib.parse.quote() 基本的な使い方 バイト列をURLエンコード エンコーディングを指定: 引数encoding 変換しない文字を指定: 引数safe urllib.parse.quote_plus() URLエンコードの活用法 URLデコード: urllib.parse.unquote()など urllib.parse.unquote() 基本的な使い方 エンコーディングを指定: 引数encoding urllib.parse.unquote_plus() urllib.parse.unquote_to_bytes()

URLエンコード(パーセントエンコーディング)とは

URLエンコードは、URLで使用できない日本語(全角文字)やスペースなどの記号を使う際に行われる符号化(エンコード)。%xxの形に変換されるのでパーセントエンコーディングとも呼ばれる。 例えば、Wikipediaの「日本語」のページは以下のようなURLになっています。

https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E8%AA%9E

この%E6%97%A5%E6%9C%AC%E8%AA%9Eの部分が「日本語」をURLエンコードした文字列。 %E6%97%A5%E6%9C%AC%E8%AA%9Eを「日本語」に戻すことをURLデコードという。ブラウザのアドレスバーではURLデコードされて表示されています。

URLエンコード: urllib.parse.quote()など

urllib.parse.quote()

urllib.parse.quote()でURLエンコードができます。

21.8. urllib.parse.quote() — URL を解析して構成要素にする — Python 3.6.5 ドキュメント

基本的な使い方

第一引数に文字列(str型)を渡すとURLエンコードされた文字列が返されます。

s = '日本語'

s_quote = urllib.parse.quote(s)

print(s_quote)
# %E6%97%A5%E6%9C%AC%E8%AA%9E

print(type(s_quote))
# <class 'str'>

バイト列をURLエンコード

第一引数にはバイト列(bytes型)を渡すこともできます。 encode()メソッドでエンコードしたバイト列を例とします。デフォルトではutf-8でエンコードされます。

b = s.encode()

print(b)
# b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e'

print(type(b))
# <class 'bytes'>

urllib.parse.quote()の第一引数にバイト列をそのまま渡します。URLエンコードされた文字列が返ってきます。

print(urllib.parse.quote(b))
# %E6%97%A5%E6%9C%AC%E8%AA%9E

エンコーディングを指定: 引数encoding

第一引数に文字列を指定したとき、引数encodingで非ASCII文字をバイト列にエンコードする際に使われるエンコーディングを指定できます。デフォルトは'utf-8'。 文字コードを指定してURLエンコードしたい場合は、この引数encodingを使います。

s_quote_sj = urllib.parse.quote(s, encoding='shift-jis')

print(s_quote_sj)
# %93%FA%96%7B%8C%EA

元の文字列をencode()メソッドで該当のエンコーディングでエンコードしたバイト列を第一引数に指定するのと等価。

b_sj_quote = urllib.parse.quote(s.encode('shift-jis'))

print(b_sj_quote)
# %93%FA%96%7B%8C%EA

print(s_quote_sj == b_sj_quote)
# True

変換しない文字を指定: 引数safe

デフォルトでは半角文字、数字、および-, _, .と/は変換されません。

print(urllib.parse.quote('http://x-y_z.com'))
# http%3A//x-y_z.com

引数safeを指定することで変換されない文字を指定できます。 デフォルトで/が変換されないのは、引数safeのデフォルト値が'/'だから。空文字列''を指定するとバックスラッシュ/も変換されるようになります。 半角文字、数字、および-, _, .はsafeによらず常に変換されません。

print(urllib.parse.quote('http://x-y_z.com', safe=''))
# http%3A%2F%2Fx-y_z.com

複数の文字を指定する場合は''の中にすべての文字を記述すれば問題ありません。

print(urllib.parse.quote('http://x-y_z.com', safe='/:'))
# http://x-y_z.com

urllib.parse.quote_plus()

urllib.parse.quote()とurllib.parse.quote_plus()は共通の引数を持ち、どちらもURLエンコードされた文字列を返します。 違いは空白(スペース)の処理と引数safeのデフォルト値。 urllib.parse.quote()は空白(スペース)を%20に変換し、引数safeのデフォルト値は'/'、urllib.parse.quote_plus()は空白(スペース)を+に変換し、引数safeのデフォルト値は''(空文字列)。

print(urllib.parse.quote('+ /'))
# %2B%20/

print(urllib.parse.quote_plus('+ /'))
# %2B+%2F

print(urllib.parse.quote_plus('+ /', safe='+/'))
# ++/

URLエンコードの活用法

はじめに示したように、例えばWikipedia(日本語版)のURLはhttps://ja.wikipedia.org/wiki/<ページ名>となっています。 WikipediaのページのURLはurllib.parse.quote()を使って以下のように作成できます。

page_title = '日本語'

base_ja = 'https://ja.wikipedia.org/wiki/'

print(base_ja + urllib.parse.quote(page_title))
# https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E8%AA%9E

日本語部分(URLエンコードしたい部分)が分割されていないフルのURLの場合は引数safe='😕'とすれば問題ありません。デフォルトではコロン:も変換されてしまうので気をつけてください。

full_url = 'https://ja.wikipedia.org/wiki/日本語'

print(urllib.parse.quote(full_url, safe=':/'))
# https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E8%AA%9E

WikipediaのURLでは、空白(半角スペース)はアンダースコア_で表されています。例えば「OK コンピューター」のページのURLは以下の通り。 https://ja.wikipedia.org/wiki/OK_%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%83%BC

urllib.parse.quote()では、空白(半角スペース)は%20に変換されます。

print(base_ja + urllib.parse.quote('OK コンピューター'))
# https://ja.wikipedia.org/wiki/OK%20%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%83%BC

https://ja.wikipedia.org/wiki/OK%20%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%83%BC

%20を使ったURLでも該当ページにリダイレクトされるので問題はないが、アンダースコアを使ったURLが取得したい場合はreplace()メソッドで空白をアンダースコアに置換しておけば問題ありません。

print(base_ja + urllib.parse.quote('OK コンピューター'.replace(' ', '_')))
# https://ja.wikipedia.org/wiki/OK_%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%83%BC

英語版でも同じ。空白はアンダースコアで表されているが%20でもリダイレクトされます。

https://en.wikipedia.org/wiki/OK_Computer https://en.wikipedia.org/wiki/OK%20Computer

クエリ文字列 例えばGoogleの検索結果のURLは以下のようになっています。

https://www.google.co.jp/search?q=%E6%97%A5%E6%9C%AC%E8%AA%9E

このq=<検索ワード>のような文字列(クエリ文字列)を作成するにはurllib.parse.urlencode()を使うほうが簡単。URLエンコードも処理してくれる。

URLデコード: urllib.parse.unquote()など

urllib.parse.unquote()

urllib.parse.unquote()関数でURLデコードができます。

21.8. urllib.parse.unquote() — URL を解析して構成要素にする — Python 3.6.5 ドキュメント

基本的な使い方

第一引数に文字列(str型)を渡すとURLデコードされた文字列が返されます。

print(s_quote)
# %E6%97%A5%E6%9C%AC%E8%AA%9E

print(urllib.parse.unquote(s_quote))
# 日本語

エンコーディングを指定: 引数encoding

URLデコードされたバイト列から文字列にデコードするときに使われるエンコーディングを引数encodingに指定します。デフォルトは'utf-8'。 元の文字列をバイト列にエンコードするときにutf-8以外のエンコーディングを使っていた場合は、引数encodingを正しく指定しないと文字化けします。

print(s_quote_sj)
# %93%FA%96%7B%8C%EA

print(urllib.parse.unquote(s_quote_sj))
# ���{��

print(urllib.parse.unquote(s_quote_sj, 'shift-jis'))
# 日本語
```python


## urllib.parse.unquote_plus()
urllib.parse.unquote_plus()+を空白に置き換える。
それ以外はurllib.parse.unquote()と同じ。
```python
print(urllib.parse.unquote('a+b'))
# a+b

print(urllib.parse.unquote_plus('a+b'))
# a b

urllib.parse.unquote_to_bytes()

URLデコードされたバイト列はurllib.parse.unquote_to_bytes()で取得できます。 このバイト列をdecode()メソッドでデコードするとurllib.parse.unquote()が返す文字列となります。

b_unquote = urllib.parse.unquote_to_bytes(s_quote)

print(b_unquote)
# b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e'

print(b_unquote.decode())
# 日本語

utf-8以外のエンコーディングの場合はdecode()の引数でエンコーディングを指定します。

b_unquote_sj = urllib.parse.unquote_to_bytes(s_quote_sj)

print(b_unquote_sj)
# b'\x93\xfa\x96{\x8c\xea'

print(b_unquote_sj.decode('shift-jis'))
# 日本語
Last Updated: 6/26/2019, 10:34:03 PM