PythonでURLを操作するために、Request関数やURLのパース関連について解説しています。
標準モジュールを使って操作しているので、他のライブラリを使った方法については説明していません。
この記事で説明しているのは、URLのRequest関数の使い方やURL解析を行うurlparseやurlencodeといった作成についてです。
興味があればぜひご確認ください。
URLを扱う標準のモジュール
PythonでURLを扱うには、urllibのモジュールを使います。
urllibの中には、URLを開いたり読み込んだりするものや、URLをパースするための機能もあります。
モジュール群
- urllib.request
- urllib.error
- urllib.parse
- urllib.robotparser
URLを開くライブラリ
urllib.requestを使えば、基本的な認証やリダイレクション、Cookieなどを使ったURLを開くことができます。
このライブラリを使えば、大体のHTTPに関するURLを開く処理ができるということです。
ほかにも、HTMLのパーサとかと同時に利用することで、自作のカンタンなスクレイピングなども行うことが可能になります。
URLを開いてみる
URLを開くためのもっともカンタンな方法が、urlopenだけを使うことです。
urlopenの引数にURLの文字列を入れることで取得することができます。
今回は、URL先をGoogleの検索ページにしています。
import urllib.request
url = 'https://google.com'
with urllib.request.urlopen(url) as res:
html = res.read()
print(html.decode()
urlopenで開いてreadを使うことで、Bodyレスポンスを取得することができます。
res.infoにすることでヘッダーレスポンスを取得することができます。
Request関数の使い方
URLの部分をリクエスト関数を使うことでパラメータの付与やヘッダーなど追加してリクエストを送ることができます。
from urllib.request import Request, urlopen
url = 'https://google.com'
req = Request(url)
with urlopen(req) as res:
html = res.read()
print(html.decode()
Requestの第2引数にデータを入れるとGETメソッドから自動的にPOSTメソッドに変わります。
そのため、POSTデータを付与して送るには、下記のようにして送ります。
data = {
'q': 'python'
}
qs = urlencode(data)
req = Request(url, qs.encode())
ステータスコードの取得
レスポンスデータからHTTPステータスコードを取得するには、getcodeを利用します。
import urllib.request
url = 'https://google.com'
with urllib.request.urlopen(url) as res:
print(res.getcode() # 結果 200が返ってきた
Contentタイプの取得
ステータスコードの取得と同じように、レスポンスからinfo関数を使ってヘッダー情報を取得します。
header情報の中から、Content-Typeを指定すると取得することができます。
import urllib.request
url = 'https://google.com'
with urllib.request.urlopen(url) as res:
print(res.info()['Content-Type']) # 結果 text/html; charset=ISO-8859-1
Googleの検索ページってUTF8じゃないのにビックリしました!
PUTとDELETEでリクエスト
Request関数でGETとPOSTについて、少しですが説明しました。
PUTやDELETEで投げるにはどうしたら良いの?って思ったので調べると、Request関数でmethod引数をつけるだけっぽいです。
url = 'http://localhost:3000'
data = {
'q': 'python'
}
headers = {
'Content-Type': 'application/json',
}
qs = urlencode(data)
req = Request(url, qs.encode(), headers, method='PUT')
DELETEメソッドでリクエストしたい場合は、PUTの部分をDELETEにするだけです。
URLを解析
PythonでURLを解析(パース)することで、クエリパラメータの値の変換やエンコード・デコードをカンタンに行うことができます。
クエリパラメータとは
クエリパラメータとは、URLの中にある?以降のパラメータのことを指します。
例えば下記のようなURLのq=python+querystringの部分です。
https://www.google.com/search?q=python+querystring
このURLのsearch?のqの部分からがクエリパラメータになります。
書き方はkeyと値をイコールで連結し、複数の値をするには、&(アンパサンド)でさらに連結していきます。
https://[ホスト]/test?キー=値&キー2=値2&キー3=値3
URLからクエリパラメータを取得してみる
urllib.parse.urlparse()を使ってURLからクエリ部分を抽出することができます。
from urllib.parse import urlparse
url = 'https://www.google.com/search?q=python+querystring'
obj = urlparse(url)
print(obj.query) # 結果は q=python+querystring
URLをパースして、パースしたデータにqueryを使うことでクエリ文字列の部分だけを取得することができます。
URLのクエリパラメータを辞書として変換
queryだけだと、複数のパラメータが付与された場合、値を分割するのに苦労します。
しかし、parse_qsを使うことで辞書として変換することができます。
from urllib.parse import urlparse, parse_qs
url = 'https://www.google.com/search?q=python+querystring&test=hoge'
qs = parse_qs(urlparse(url).query)
print(qs) # 結果は {'q': ['python querystring'], 'test': ['hoge']}
parse_qsには文字列のクエリパラメータを入れます。
そうすることで、キーが複数あっても辞書として変換することができます。
クエリパラメータの作成
urlencodeを使うことで、辞書型のデータをクエリパラメータとしてエンコードすることができます。
from urllib.parse import urlencode
q_data = {
'q': 'Pythonでクエリパラメータを作成',
'option': [1, 3, 5],
'lang': 'jp',
}
qs = urlencode(q_data)
print(qs)
urlencodeにそのまま入れるだけでクエリパラエータが作成できるのでカンタンですね。
結果は下記になります。
q=Python%E3%81%A7%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%82%92%E4%BD%9C%E6%88%90&option=%5B1%2C+3%2C+5%5D&lang=jp
日本語に関して%Eや%Aといった文字が含まれていますが、これはURLエンコードされたことによって起きる現象です。
クエリパラメータのエンコードに配列があったら注意が必要
クエリパラメータの作成でエンコードされたクエリを元に戻してみると分かります。
もとに戻すコードは、下記になります。
from urllib.parse import urlencode, parse_qs, unquote
q_data = {
'q': 'Pythonでクエリパラメータを作成',
'option': [1, 3, 5],
'lang': 'jp',
}
qs = urlencode(q_data)
print(qs)
print(unquote(qs))
print(parse_qs(qs)
urlencodeを使って、辞書型のデータをクエリパラメータに変換します。
unquoteでは、%などに変換された値をデコードしています。
parse_qsでは辞書として戻しています。
これらの結果が下記になります。
q=Python%E3%81%A7%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%82%92%E4%BD%9C%E6%88%90&option=%5B1%2C+3%2C+5%5D&lang=jp
q=Pythonでクエリパラメータを作成&option=[1,+3,+5]&lang=jp
{'q': ['Pythonでクエリパラメータを作成'], 'option': ['[1, 3, 5]'], 'lang': ['jp']}
unquoteやparse_qsの結果を見てわかる通り、辞書の値の部分が配列になっていたり、リストの部分が文字列になっていたりとおかしな変換になっています。
まずは、parse_qsで変換すると下記になります。
{'q': '値'} -> {'q': ['値']}
値を取得するには、変数名['q'][0]としないと取得できません。
なぜ値が配列として戻ってくるのかはドキュメントを読んでみたらリストを返すようです。
なのでparse_qsの仕様ですね。
option部分の配列はだったのが文字列に変わっているのも仕様で、文字列から配列に変換する必要があります。
"[1, 2, 3]"このような文字列を配列に変換するには、splitを使うしか無いのか?
evalを使えばカンタンに配列になります。
data = parse_qs(qs)
option = data['option'][0]
l = eval(option)
print(l, l[0]) # 結果は [1, 3, 5] 1
まとめ
PythonでURLを扱う標準モジュールを紹介しました。
URLを開くことでHTMLやFTPといったデータを取得することができるurlopenがあります。
ほかにもURLを解析するurlparseを使えば、カンタンにURLについているパラメータを取得することも可能。
サーバ側の処理は足りないのですが、クライアントとして処理する分には、Requestとurlopenだけで十分です。
カンタンなアプリ作成だったら、検討してみるのもアリですね。
今後の人生を豊かにする為にキャリアアップのステップとして、自分への投資をしてみませんか?