note.nkmk.me

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

Date: 2018-05-16 / tags: Python

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になっている。

この%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エンコードができる。

基本的な使い方

第一引数に文字列(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

複数の文字を指定する場合は''の中にすべての文字を記述すればOK。

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=':/'とすればOK。デフォルトではコロン:も変換されてしまうので注意。

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()メソッドで空白をアンダースコアに置換しておけばOK。

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でもリダイレクトされる。

クエリ文字列

例えばGoogleの検索結果のURLは以下のようになっている。

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

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

urllib.parse.unquote()

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

基本的な使い方

第一引数に文字列(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'))
# 日本語

urllib.parse.unquote_plus()

urllib.parse.unquote_plus()+を空白に置き換える。

それ以外はurllib.parse.unquote()と同じ。

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'))
# 日本語
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事