何がやりたかったか?
お付き合いのあるとある公共施設のブログというかWeb日記というかをスクレイピングしてきたものを、RESTでロボットから呼び出してお話させてみたく、とりあえずJSONでスクレイピングしてきた内容を返すだけの簡易サービスを作って置きたかった。
RSSやらAtomやらのフィードがあれば、それを使えばよいのだろうけど、いかんせんそれがなかったので、なんとかしようとしたというのが前提になっている。
簡単にJSONを返すだけのサービスをTornadoで作る
ということで、Tornadoを使ってスクレイピング結果をGetで、かつ、JSONで返せるようにしようと考えた。作成に使った環境は以下の通り。
- OS:Ubuntu15.10
 - Python:3.5.1
 - Tornado:4.3
 - Tornado-JSON:1.2.2
 
Tornadoを使った簡易なWeb API作成で、JSONを返すための方法はいくつかあると思うが、今回はTornado-JSONを利用した。Tornado-JSONのsampleやtutorialを参考にすれば、そんなに迷わないはず。
まずはTornadoでのWebアプリケーション作成と同様
以下のような感じで、WebアプリケーションとしてURLで呼び出せるようにするための部分を書く。
import tornado.ioloop
from tornado_json.routes import get_routes
from tornado_json.application import Application
def main():
    import diarytalker
    routes = get_routes(diarytalker)
    application = Application(routes=routes, settings={})
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
if __name__ == '__main__':
    main()
tornado_json.routesにより、この後記述するAPIのエンドポイント部分のパッケージ名、RequestHandlerから、自動でルートを特定してくれるので、自分でルートの記述を行う必要はない。インポートしているdiarytalkerがRequestHandlerが含まれるAPIの本体。
RequestHandlerを含んだAPI本体のパッケージ
以下のようなディレクトリ構成で作っていく。
ーdiary_talker.py
|
|
ーdiarytalker/
      |
      |ー__init__.py
      |ーapi.py
      |ーdiary.py
インポートされるdiarytalker下で、API本体の実装はapi.pyに記載している。diary.pyはスクレイピングの実装だた、今回の本題とは外れるので、割愛。とにかくWebアクセスしてBeautifulSoup4などを駆使して日記をスクレイピングし、日付、タイトル、本文をdictionary化して返すメソッドが定義されている。
from tornado_json.requesthandlers import APIHandler
from tornado_json import schema
import diary
class DiaryTalkerHandler(APIHandler):
    @schema.validate(
        output_schema={
            "type": "object",
            "properties": {
                "date": {"type": "string"},
                "title": {"type": "string"},
                "body": {"type": "string"}
            }
        }
    )
    def get(self):
        td = diary.Diary()
        diary = td.get_newest_diary()
        return {
            "date": "{}".format(diary["date"]),
            "title": "{}".format(diary["title"]),
            "body": "{}".format(diary["body"])
        }
api.pyのgetメソッドでは、スクレイピングを行っているDiaryのget_newest_diaryメソッドを呼び出し、結果の入ったdictionaryから、schemaにより定義したJSONを返す実装になっている。日記の本体(日付、タイトル、本文)はschema定義のPropertiesでそれぞれ型とともに指定している。
実際に呼び出すときは
http://〜/api/diarytalkerで呼び出せる。結果は
{"data":{
  "date":"20160323",
  "title":"hoge",
  "body":"〜"
 },
 "status": "success"
}
のような感じに返ってくる。