2018年2月19日月曜日

【Googleクラウド・機械学習編】日報解析バッチ作成中3~リクエスト送信~

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

最近は機械学習について勉強中です。
現在はGoogleの機械学習API「CLOUD NATURAL LANGUAGE API」の検証と、Pythonの勉強を並行して進行しています。

初心者の勉強として、簡単なバッチを作っている最中です。
大した内容はありませんが、お付き合いください。


リクエスト送信

前回の作業にて、ファイルを読み込むところまでは確認出来ました。
今度はこれをAPIに送り込まなければなりません。

最難関となるリクエスト送信処理そのものはもっと前に検証して解決しているので、今回行うのは簡単なテキスト加工ですね。

テキスト

私の日報は必ず以下のような形式になっています。


Delivered-To: endo@genesis-net.co.jp
Received: by 10.60.116.6 with SMTP id js6csp2150228oeb;
        Tue, 28 Jul 2015 06:16:25 -0700 (PDT)
X-Received: by 10.60.142.234 with SMTP id rz10mr33362752oeb.4.1438089385353;
        Tue, 28 Jul 2015 06:16:25 -0700 (PDT)
Return-Path: <3qIC3VRMJBDsdbkbpfp-dXb-pbosfZbdjXfi.Zljbkaldbkbpfp-kbq.Zl.gm@2uix4h7xygsz66weerlq.apphosting.bounces.google.com>
Received: from mail-pd0-f197.google.com (mail-pd0-f197.google.com. [209.85.192.197])
        by mx.google.com with ESMTPS id ma3si53036429pdb.163.2015.07.28.06.16.24
        for <endo@genesis-net.co.jp>
        (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
        Tue, 28 Jul 2015 06:16:25 -0700 (PDT)
Received-SPF: pass (google.com: domain of 3qIC3VRMJBDsdbkbpfp-dXb-pbosfZbdjXfi.Zljbkaldbkbpfp-kbq.Zl.gm@2uix4h7xygsz66weerlq.apphosting.bounces.google.com designates 209.85.192.197 as permitted sender) client-ip=209.85.192.197;
Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of 3qIC3VRMJBDsdbkbpfp-dXb-pbosfZbdjXfi.Zljbkaldbkbpfp-kbq.Zl.gm@2uix4h7xygsz66weerlq.apphosting.bounces.google.com designates 209.85.192.197 as permitted sender) smtp.mail=3qIC3VRMJBDsdbkbpfp-dXb-pbosfZbdjXfi.Zljbkaldbkbpfp-kbq.Zl.gm@2uix4h7xygsz66weerlq.apphosting.bounces.google.com
Received: by pdbpo3 with SMTP id po3so221230738pdb.1
        for <endo@genesis-net.co.jp>; Tue, 28 Jul 2015 06:16:24 -0700 (PDT)
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20130820;
        h=mime-version:reply-to:message-id:date:subject:from:to:content-type
         :content-transfer-encoding;
        bh=449+r7RRDqf7+TpVrGlImqmP3nYBDuppv9kcCar1VM8=;
        b=Ex7Z3fWrUdO//VwmvJl4tECF79NZGChauQzCEd5f4uCZ3YIC6m02Damyzwxg+W1pmO
         96vdBP56t3on+zNqYbjXdE50MnZlbq41s+rhfmpN3744ow7ce/ocruBueluTNlMQuHZO
         Ct0+vALQ7aTtyC0UNE+RnNU1oGDcA0hTUueL8e93SFbJVcCPtgg+bvn8zx3zhj0l5Da0
         axnU9Figlz+M/Vazvy95mppTOlBzCQobqXZkeobBupWkFaYLxny0/bKXjkiq16sa5EZ1
         Vp2BYtR/7lc5eHQcg3NHK+dtiR6QU4UsM98P1B8b1jQrWm8MfVJKEcUDP6ls6YROZMDk
         pSoQ==
MIME-Version: 1.0
X-Received: by 10.66.146.227 with SMTP id tf3mr36223044pab.21.1438089384636;
 Tue, 28 Jul 2015 06:16:24 -0700 (PDT)
Reply-To: "endo@genesis-net.co.jp" <endo@genesis-net.co.jp>
X-Google-Appengine-App-Id: s~genesis-gae-service
X-Google-Appengine-App-Id-Alias: genesis-gae-service
Message-ID: <047d7b6dc768ed3c29051bef4663@google.com>
Date: Tue, 28 Jul 2015 13:16:24 +0000
Subject: =?ISO-2022-JP?B?GyRCIVpGfEpzIVsxc0YjGyhCXzIwMTUwNzI4?=
From: "endo@genesis-net.co.jp" <endo@genesis-net.co.jp>
To: "HIMITSU@genesis-net.co.jp" <HIMITSU@genesis-net.co.jp>
Content-Type: text/plain; charset=ISO-2022-JP; format=flowed; delsp=yes
Content-Transfer-Encoding: 7bit
○○ さん
お疲れ様です。遠藤です。
2015年07月28日の日報を送付します。
【稼働時間】・09:00~18:00 (08:00h)
【概要】・実装:08:00h
【詳細】 報告内容がズラズラっと。
【連絡事項】・7/31(金):帰社
以上、よろしくお願いします。
--
================================================
遠藤 太志郎
株式会社ジェニシス技術開発事業部@春日
Mail:endo@genesis-net.co.jp
歯科医院予約管理システムDentNet facebook
http://www.facebook.com/dentnet.genesis
株式会社ジェニシス技術開発事業部ブログ
http://genesis-tdsg.blogspot.jp/
================================================

解析が必要な部分は赤文字の部分だけです。従って、

  • お疲れ様です。
  • 以上、よろしくお願いします。

この2つのキーワードを「開始」と「終了」の目印として使うことが出来そうです。

まあ、私のメールだからこんなやり方でフィルタリングできますが、もっと形態不明なメールを解析するのであれば、違う目印が必要になるでしょうね。

今はテキストベースでやっていますからこういうやり方ですが、ちゃんと環境を整えれば「ヘッダー」と「ボディ」を見分けるくらい出来ると思います。

その条件で、ファイルの文中から解析したい部分だけを切り取るロジックがこちら。

def read_content(file):
    flg = False;
    content = ''
    for line in open(os.path.join(dirPath, file), 'r', encoding='ISO-2022-JP'):

        if line.find('以上、よろしくお願いします。') == 0:
            flg = False

        if flg:
            content = content + line
        else:
            if line.find("お疲れ様です。") == 0:
                flg = True

    return content

特筆することはありません。

ただ、こういう文字列加工ってチョコチョコチョコチョコ作業するものなんですよね。
Pythonというのは、このチョコチョコ作業に向いている性質があると思います。

言語の向き、不向きを肌感触で知っていることは重要だと思いますね。

文字列が構築出来ましたら、後はそれをJSONに組み込んで送り込むだけです。

def send_request(content, file):
    # 送信先URL
    url = "https://language.googleapis.com/v1/documents:analyzeEntities?key=himitsu"

    # 送信するJSONパラメータ
    body = {
        'document': {
            'type': 'PLAIN_TEXT',
            'content': content
        },
        'encodingType': 'UTF8'
    }

    body = json.dumps(body).encode("utf-8")

    # リクエストヘッダー
    header = {
        "content-type": "application/json"
    }

    # リクエストメソッド
    method = "POST"

    try:
        # 送信実行
        request = urllib.request.Request(url, data=body, headers=header)
        with urllib.request.urlopen(request) as response:
            # 結果を出力
            response_body = response.read().decode("utf-8")
            print("レスポンスを受信しました。")
            print(response_body)

            f = open(os.path.join(exportPath, file + '.json'), 'w')  # 書き込みモードで開く
            f.writelines(response_body)
            f.close()

    except urllib.error.HTTPError as e:
        # エラーだった場合、エラー原因を出力
        print('ERROR!!')
        print(e.code)
        print(e.read())


特筆するべきは、JSONの構築箇所です。

    # 送信するJSONパラメータ
    body = {
        'document': {
            'type': 'PLAIN_TEXT',
            'content': content
        },
        'encodingType': 'UTF8'
    }

これ。
contentが上記で構築した変数ですが、このように、JSONの構造が見える状態で形成することが出来ました。

  • "body = {" + {\'document\': {" + "\'content' + content ……

みたいなエスケープ文字の羅列だと読めないですからね!!
このようにJSONをJSONとして取り扱い出来ることが大変すばらしいです。

後はリクエストを送り、受領したレスポンスをファイルに一時保存すれば終わり。

f = open(os.path.join(exportPath, file + '.json'), 'w')  # 書き込みモードで開く
f.writelines(response_body)
f.close()

ファイルの書き込みはこれでOKです。

終わりに

これでズラーッと解析結果を取得出来ました。


後は、この結果ファイル一覧を読み込んで、どんなデータが入っているか見てみようと思います。

0 件のコメント:

コメントを投稿