読者です 読者をやめる 読者になる 読者になる

kitak.blog

Kみたいなエンジニアになりたいブログ

Browserify が生成したファイルを webpack で扱おうとしてハマった

webpack で Browserify で生成されたファイル( shim library )を import して生成されたファイルを実行したら、require を呼び出しているところで実行時エラーになった。

ファイルに require が含まれていて、それを webpack がパース(依存関係を解決)しようとしたのが原因のようなので、ドキュメントの https://webpack.js.org/guides/shimming/https://webpack.js.org/configuration/module/#module-noparse に書かれていた module.noParse オプションでパース対象から外して解決した。

Browserify に限らず、他のモジュールバンドラで生成したファイルでも起こりそうな気がする。

WHYから始めよ! を読んだ

読んだ。

WHYから始めよ!―インスパイア型リーダーはここが違う

WHYから始めよ!―インスパイア型リーダーはここが違う

Why から始め、その次に How や What を示すことの重要性を説いた本。 読んでいて気になったところを何点かメモ

  • Why → How → What の流れは、脳の内から外への思考の流れに一致している。この形で伝えると納得や共感を得られやすい
  • How や What だけを訴えかけても成功しない、アーリーアダプターに対して Why を伝えることで共感を求める
  • マイクロソフトやアップルを引き合いに出し、成功した企業には、創業者に Why と How それぞれを担う人物がいると主張する。どちらか片方だけではうまくいかない
  • 創業者が去ったり、企業が急成長し How や What に悩殺されることで Why が失われるケースが有る。Why や共感を扱う脳は言語化ができないから、それを引き継がせることが難しい

VISA デビットカードを使ったら口座残高が通知されるようにした

VISA デビットカードを使ったら口座残高が通知されるようにしたので、個人の技術的な備忘録。

三菱東京UFJダイレクトのページの操作を自動化して、口座残高を調べる - kitak.blog の続きにあたります。ざっくりこんなかんじです。

(あらかじめ、VISA デビッドカードを使ったら Gmail のアドレスにメールが来るようにしておく。これは三菱東京UFJダイレクトのページで設定できる)

  1. IFTTT の Applet で Gmail で指定のアドレスからメールが届いたら、VPS のウェブサーバーに HTTP リクエストを送るようにする
  2. ウェブサーバーでは、前回の記事で紹介した Python スクリプトを実行して、口座残高を取得する(スクレイピングに時間がかかってタイムアウトすることがあるのでジョブキューに投げる)
  3. LINE Notify で残高を通知する

IFTTT

Gmail のアドレスにメールが届いたことを検知するには、Push Notifications  |  Gmail API  |  Google Developers に書かれている方法でできそうだったけれども、Cloud Pub/Sub API とか諸々のお膳立てが面倒なかんじだった。
他に何か良い方法は無いかと考えていたら、IFTTTGmail の Trigger があったのを思い出したので、調べたら、ついでに Maker Channel (https://ifttt.com/maker) というものがあるのを知った。HTTP リクエストを Trigger にしたり、Action で HTTP リクエストを実行してくれる。名前から分かるように、Arduino とか Raspberry Pi みたいなデバイスと連携するためにできた機能っぽいんだけど、既存のウェブサービスと自作ウェブサービスの連携が捗る神機能な気がする。けっこう前からあるようだけど、大昔に TwitterEvernote の連携をして以来 IFTTT を使っていなかったので知らなかった。

LINE Notify

取得した口座残高は LINE Notify ( https://notify-bot.line.me/ja/ ) で通知させることにした。LINE 版 ikachan。
HTTP リクエストを実行すれば、LINE のグループに通知を送れる。シークレットトークンの発行も簡単。

自作ウェブサービス周り

  • VPSVultr の東京リージョンを借りた
  • IFTTT からのリクエストを受け付けるサーバーは Flask で書いた。Flask を使うにあたって Home · yoshiya0503/Flask-Best-Practices Wiki · GitHub とか GitHub - be-hase/ghe-line-notify: LINE Notify Gateway for Github Enterprise. を参考にした
  • 口座残高の取得にけっこう時間がかかるので、ジョブキューに投げることにした。使ったジョブキューのモジュールはシンプルそうな RQ
  • 教養ぐらいのつもりで Docker (Docker Compose) を使って動かすことにした
  • 手元で作った Docker image を EC2 Container Registry に push して、VPS で pull して使う。ECS 使わんの? と思われそうだけど、あれも使いたいこれも使いたいとなって AWS 沼に嵌っていきそうな気がしたのでやめた。あと、リハビリとして、VPS いじりをしたい気持ちだった
  • 手元で開発を行っている環境と同じ環境を簡単に構築できるので、Deploy はすんなりいった。ただ初めてやることが多かったので、Deploy までのお膳立てがけっこう大変だった
  • (自分しか使わないサービスだから別にいいんだけど) Container の監視どうしようかな、と思って、色々調べたら、Datadog を使うのが楽そうだった。Docker integration で 走っている Container の数を監視して、減ったら通知するようにした。通知は Webhook integration で、口座残高と同じく LINE Notify を使った

というかんじで、口座残高が通知されるようになった。ブラウザで動く JavaScript ばかりしばらく書いてて、色々アレになっている部分があるので、今年はこういう個人のお金まわりのウェブアプリを書いてリハビリをする予定。

MPEG-2 TS の PCR のメモ

MPEG-2 TS パケットのヘッダーをパースするプログラムを読んでいたら、PCR というキーワードがでてきたので調べた。個人的なメモ。

PCR の説明は デジタル映像の「アーカイブ&デリバリー」に関する技術情報サイト|mpeg.co.jp > VIDEO-ITを取り巻く市場と技術 が分かりやすかった。PCR は Program Clock Reference の略で、送信機と受信機の時刻を同期するための基準となる時刻。

それを基準に PTS (Presentation Time Stamp) と DTS (Decode Time Stamp) を計算する。前者は再生する時刻で後者は復号する時刻。

以前、仕事で特定の動画を再生したままにして数十分ぐらい放置するとパツンと止まることがよく起きていたのだけど、仙石浩明の日記: 地デジ MPEG-2 TS の PCR/PTS/DTS ラップアラウンド (PCR Wrap-around) 問題を回避して ffmpeg で PS 変換できるようにしてみた に書かれているように PCR の値がおかしくなっているのを疑ってみるとよさそうな気がした。

回転寿司酒場 銀座沼津港 に行ってきた

Bitcoin長者のわっかむさん( @yuma300 )と愉快な仲間たちで行ってきました。

回転寿司酒場 銀座沼津港

食べログ回転寿司酒場 銀座沼津港

銀座なのに沼津港? このお店、Bitcoin で支払いができます。

f:id:kitak:20170117195828j:plain:w350

店内には Bitcoin の ATM が。

f:id:kitak:20170117200736j:plain:w350

板前さんに Bitcoin でチップを払うことができると聞いていたので、試しに購入。

購入したものの、残念ながらチップを払うことができる取り組みは終了していました。

(写真撮り忘れたんですが)肝心のお寿司は、新鮮でネタが大きくおいしかったです。東京で生鯖の寿司を食べたのは初めてかも。
ごちそうさまでした。

三菱東京UFJダイレクトのページの操作を自動化して、口座残高を調べる

家計簿アプリ自給自足の一環。今日はブラウザ操作を自動化して、口座残高を調べます。VISA デビッドをつかったらメールが来るように設定しているので、最終的にそれをハンドリングして、口座残高を LINE とかに通知したい。

こんなかんじの Pythonスクリプトを書きました。三菱東京UFJダイレクトのページにログインして、口座残高が書かれた要素を調べます。ブラウザは PhantomJS, 自動操作には WebDriver (Selenium2) を使うので、事前に PhantomJS と pip で selenium パッケージをインストールしておきます。

# -*- coding: utf-8 -*-
import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.common.exceptions import TimeoutException

def get_amount():
    MUFG_URL = 'https://entry11.bk.mufg.jp/ibg/dfw/APLIN/loginib/login?_TRANID=AA000_001'

    ID = os.environ['MUFG_ID']
    PASSWORD = os.environ['MUFG_PASSWORD']
    browser = webdriver.PhantomJS()

    try:
        browser.get(MUFG_URL)

        WebDriverWait(browser, 10).until(
            expected_conditions.presence_of_element_located(
                (By.ID, 'account_id')
            )
        )

        browser.find_element_by_id('account_id').send_keys(ID)
        browser.find_element_by_id('ib_password').send_keys(PASSWORD)
        # 要素をクリックしたけど効かなかったので、onclickで呼び出している関数を呼び出す
        browser.execute_script('gotoPageFromAA011();')

        WebDriverWait(browser, 3).until(
            expected_conditions.presence_of_element_located(
                (By.ID, 'setAmountDisplay')
            )
        )

        return browser.find_element_by_id('setAmountDisplay').text
    except TimeoutException:
        browser.save_screenshot('debug.png')
        raise
    finally:
        browser.quit()

if __name__ == '__main__':
    print(get_amount())
  • 最初、Chrome でやろうとしていたけど、Chrome driver と selenium パッケージの相性が悪いのか動かなかった
  • Node のほうが、Nightmare や Protractor のような WebDriver API をラップして使いやすくしたパッケージが多いのだけど、サーバを Python で書こうとしているので合わせて Python で書くことにした
  • ログインボタンのクリック処理が動かなくて、仕方なく、ボタンの onclick属性 に書かれていた関数を呼び出すようにした

Google Cloud Vision API の OCR 機能でレシートを読んでみる

題の通り。

趣味で家計簿アプリをちまちま作っているんですが、レシートを読んで支払った金額を入力する機能が実装できるかどうか検証するために触ってみました。事前に GCP Console でプロジェクトを作ったり、API キーを発行しておきます。

コードはこんなかんじです。

import base64
import json
import requests

def detect_text(path):

    with open(path, 'rb') as image_file:
        content = base64.b64encode(image_file.read())
        content = content.decode('utf-8')

    api_key = "YOUR_API_KEY"
    url = "https://vision.googleapis.com/v1/images:annotate?key=" + api_key
    headers = { 'Content-Type': 'application/json' }
    request_body = {
        'requests': [
            {
                'image': {
                    'content': content
                },
                'features': [
                    {
                        'type': "TEXT_DETECTION",
                        'maxResults': 10
                    }
                ]
            }
        ]
    }
    response = requests.post(
        url,
        json.dumps(request_body),
        headers
    )
    result = response.json()
    print(result['responses'][0]['textAnnotations'][0]['description'])

if __name__ == '__main__':
    detect_text("receipt.jpg")

今回読んでみたレシート

結果

サンつコ
渋谷マークシティ店
電話 03-3464-2593
領収書
合計
¥1 57
(うち消費税等 8.0%
¥11)
ルジット支払
¥1 57
クレジット売上票
お客様控え
ルジット支払額
¥157
会社名
JCB
会員NO
お取扱日
承認番号
0927657
店舗名
サンクス 渋谷マークシティ店

けっこうちゃんと読めてますね。上のリストをなめて、「合計」が含まれる行の後ろの行を金額として扱えば大体うまくいくんじゃないかな、と思いました。また、「合計」が認識できなかった場合は、 \¥(\d|\s)+正規表現パターンにマッチする行を取り出して、入力の候補として選択させればよさそうです。