JSONとAPIを触ってみる(Using Python to Access Web Data: Week 6)
引き続き、ミシガン大学がCoursera上で開講しているPython for Everybody Specializationの第3コース、Using Python to Access Web Dataを受講した記録です。前回のWeek 5では、XMLとPythonでの処理方法を学びました。
Week 6では、JSONと呼ばれる構造言語とツイッター等で用いられるAPIを学んでいきます。第3コースもいよいよ最後の週ですので、ボリュームも盛りだくさんです。
<テキストの範囲>
Chapter 13: Using Web Servicesのつづき
1.JavaScript Object Notation (JSON)
XMLはタグの属性をAttributeなどで定義することができる点は有用ですが、その分複雑であり、データをタグで囲んでいくためファイルサイズは大きくなる傾向にあります。一方、JSONは比較的シンプルなことからWebサービスでよく使われるようになってきています。
JSONはAttributeを持たず、階層化したディクショナリ形式のようなイメージになります。前回の講義で扱ったコードをJSONに書き換えてみます。インポートするライブラリはjsonとなります。
import json
data = '''{
"lastname" : "Suzuki",
"age" : "32",
"dob" : "1987-10-06",
"email" : {
"hide" : "yes"
}
}''' #...[1]
info = json.loads(data) #...[2]
print('Name:', info["lastname"]) #...[3]
print('Email:', info["email"]["hide"]) #...[4]
[1]のように、階層化の識別には{ }カッコを用います。上記で述べたように、attributeを持つことはできないので"email"要素において階層を作り、キーを"hide"、値を"yes"というように組み直します。
JSONの文字列をツリー構造の変数に取り込むには、[2]のようにjson.loads()を用います。
Pythonではツリーの階層を[3]や[4]のように掘り下げていき、データを表示することができます。[3]では1階層目、[4]では2階層目のデータを読み取っていますね。表示結果は、以下のようになります。
Name: Suzuki
Email: yes
JSONは機能面でXMLと比べリッチではないものの、シンプルであり様々な言語に直接取り込みやすいというメリットを持っています。
次に、JSONの構造がディクショナリを持つリスト形式で表されている例を見ていきましょう。前回の講義の最後で触れたコードを少し改良します。
import json
input = '''[
{ "x" : "2",
"id" : "001",
"name" : "Goro"
},
{ "x" : "7",
"id" : "009",
"name" : "Hanako"
}
]''' #...[1]
lst = json.loads(input)
print('Number of users:', len(lst)) #...[2]
for item in lst:
print('Name:', item['name'])
print('Id:', item['id'])
print('Attr:', item['x'])
[1]のように、全体を[ ]カッコで括ると、全体がリスト形式であることを意味します。その中の構造がディクショナリ形式の構造になっているので、[2]におけるNumber of usersは2になります。
for文でユーザーの数だけ繰り返し、それぞれの要素をitem[ ]で取り出していく命令になっています。したがって、表示結果は、
Number of users: 2
Name: Goro
Id: 001
Attr: 2
Name: Hanako
Id: 009
Attr: 7
となります。
講義の最後に、JSONの発明者であるDouglas Crockford氏のインタビュー動画がありますので、是非見てみてください。
2.Service Oriented Architectures
例えば、私たちが航空会社で飛行機の予約をすると、その予約情報をもとにレンタカーやホテルは一緒にどうか、といった提案が表示されることがあります。これは、飛行機の予約システムとレンタカーやホテルの予約システムが相互にデータを融通することで可能になります。ホテルを予約したお客さんは飛行機を予約するでしょうし、飛行機を予約したお客さんはホテルを予約するでしょう。それぞれが別々の予約システムがある中で、相互にデータのやり取りを行う、それがサービス指向アーキテクチャ(Service Oriented Architecture)と呼ばれるものです。
以下の動画がイラストレーティブで分かりやすく解説されています。
3.Application Programming Interfaces (API)
次に、APIについて見ていきましょう。プログラミング初心者では、APIという単語はよく聞くものの、内容自体はあまり知らない……という方も多いかと思います。
APIは、ざっくり言うと、自分のアプリケーションから他のコンピューターやネットワークで利用可能なアプリケーションを実行する接点を意味します。つまり、APIの仕様を公開または共有することで、Pythonのプログラムから他のコンピューターのサービスや機能を利用することが可能となるわけです。
この講義では、GoogleのGeocoding APIについて触れていきます。
Geocoding APIにおいては、以下の命令を受け付けます。
https://maps.googleapis.com/maps/api/geocode/json?address=
ここで、address以降に検索したい住所を検索すると、GPS上の緯度や経度などを知ることができる、というサービスです。このAPIは公開されているので、回数範囲内で利用規約のもとで自身のプログラミングにて利用することができます。ただし、Google Cloud Platformへの登録および支払い情報の登録が必要となります。
登録やトラブルシューティングは、このサイトを参照にしました。
さすがに、登録をしなければサービスを使うことができなくなったので、講義で紹介されているプログラムを一部アレンジし、APIキーを含むURLを指定しなければならないようです。
import urllib.request, urllib.parse, urllib.error
import json
serviceurl = 'https://maps.googleapis.com/maps/api/geocode/json?'
serviceurl = serviceurl + 'key=なんちゃらかんちゃら&' #...[1]
while True:
address = input('Enter location:') #...[2]
if len(address) < 1: break
url = serviceurl + urllib.parse.urlencode({'address': address}) #...[3]
print('Retrieving:', url)
uh = urllib.request.urlopen(url) #...[4]
data = uh.read().decode() #...[5]
# print(data)
try: #...[6]
js = json.loads(data)
except:
js = None
if not js or 'status' not in js or js['status'] != 'OK':
print('Failure')
continue
print(json.dumps(js, indent=4)) #...[7]
lat = js["results"][0]["geometry"]["location"]["lat"] #...[8]
lng = js["results"][0]["geometry"]["location"]["lng"]
print('lat', lat)
print('lng', lng)
location = js["results"][0]["formatted_address"]
print(location)
サンプルのプログラムも非常に長く、解読するのに時間を要しますが、一つ一つ解説していきます。
まずは、[1]でGoogle Map APIを使うためのURLの準備をします。以前はjson?の後にそのままaddresss=とすればよかったのですが、APIキーが必要になったのでその部分を追加し、&で繋げる形としています。
次に、インプットの方式ですが、ここで住所を入力します。プログラムを終了させる場合は、そのまま何も入力せずにエンターキーを押すと終了するようになっています。
[3]は、実際にブラウザに入力するようなURLをエンコードし、生成する行です。urlencode({address}: address)で、address=(エンコード済みの住所)という形式に変換しています。
[4]はURLをオープンし、[5]は受信したデータをdecodeしています。直後のdataを表示させるコメントアウトは、エラーが発生した時に何が起きているかを確認するための予備的なものです。このコードを書いていたときに何度もエラーが発生したので、その名残です。(笑)
[6]は復習となりますが、エラーが発生したときの例外処理をまとめています。エラーとなった場合は、下のif文でループ処理の最初に戻るようcontinueとするように指示しています。
[7]以降は、結果を表示する段階になります。json.dumps(js, indent=4)では、取得したJSON形式のデータを空白4文字のインデントありで表示します。いわゆる生データですので、Google Geocode APIからどのような情報を取得しているかを見ることができます。
[8]で、JSONの構造を掘り下げ、実際に緯度と経度の情報を取得し、その下のprintで表示しています。
なかなか大変な作業で、プログラミング初心者としてはかなり実用的な講義内容になってきたな?と思っています。ぜひ、時間をかけて一行一行を解読してみてください。途中でprintをして、どの変数がどのような値を取っているかを見てみるのも楽しいです。
4.Twitter APIを使ってみる
Google Maps APIのように、APIは自分のプログラムから相手のWebサーバにあるプログラムを実行し、結果を取得するような機能を可能とするため、APIには価値があります。そのため、登録が必要であったり、無料で使用できる量が制限されていたり、有料であったりします。
さて、Twitter APIについて見ていきましょう。Twitter APIの利用については以下のページをご参照ください。
この講義でのサンプルプログラムを試すには、Twitterのアカウントでアプリケーションを登録し、認証をする必要があります。認証の方法については、以下のページが詳しいのでご参考にしてください。
講義で触れられていたoauthライブラリを使う方法ではどうにもOAuth認証の接続がうまくいかず、このあたりはライブラリやAPIの仕様が変わったりすると途端に使えなくなってしまうので、常に新しい情報にアップデートする必要がありますね……。
(なお、このコードは2020年3月8日現在利用可能です。)
import urllib.request, urllib.parse, urllib.error
from requests_oauthlib import OAuth1Session
import json
TWITTER_URL = 'https://api.twitter.com/1.1/statuses/user_timeline.json'
CONSUMER_KEY = "*******" #...[1]
CONSUMER_SECRET = "*******"
ACCESS_KEY = "*******"
ACCESS_SECRET = "*******"
twitter = OAuth1Session(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_KEY, ACCESS_SECRET) #...[2]
tl_counts = {'count': 10}
data = twitter.get(TWITTER_URL, params=tl_counts) #...[3]
if data.status_code == 200: #...[4]
tl = json.loads(data.text)
for timeline in tl:
print(timeline['user'])
print(timeline['name'])
print(timeline['text'])
Twitterの認証には、consumer keyとsecret、access keyとsecretの2つの対の情報が必要になります。Twitter開発者として登録し、APIが使用可能であれば取得することができます。[1]からの4行は、ユーザー独自のコードが入力されているはずです。
[2]で、OAuth認証を行っており、[3]でTwitterからタイムラインの情報を取得しています。
[4]では、Twitterからの認証がうまくいっており、正常にデータが取得できる状態であるかを表しています。
どうやら、Anaconda3にはOAuth1Sessionライブラリが標準装備されていないようなので、別途インストールが必要でした。以下のHPにあるconda~~というコマンドをPowershellで打ち込むと、インストールができます(Windows利用者は、管理者権限が必要です)。
これで、ようやく、第3コースを修了しました!
最後のTwitterへのアクセスは本当に試行錯誤で大変でした。でも、少し最近のWebのことに詳しくなれた気がします。これからも適宜noteを振り返りながら、プログラミングを楽しんでいけたらいいなと思います。
ではでは、次回のエントリもお楽しみに!
この記事が気に入ったらサポートをしてみませんか?