schedule2018-07-27

リクエスト情報から訪問者の情報を集めてみる[Python Flask + DynamoDB]-2.実装編

2018年12月にブログを移行した際にこの機能は削除しました。

はじめに

解析の勉強のため、このブログの統計情報を集めようと思い立ちました。

この記事は、設計編からの続きとなります。

リクエスト情報から訪問者の情報を集めてみる[Python Flask + DynamoDB]-1.設計編

機能を実装していきましょう。

ブログに実装する

記事にリクエストがきた場合は、記事IDとreuestsをVieLogsManagerに渡します。 insert()が、記事の閲覧履歴を追加します。

@article.route('/<article_id>', methods=['GET'])
def get_article(article_id='1'):
    """
    記事のテンプレートを返す
    """
    article = ArticleManager().get_article(article_id)
    sidebar = SidebarManager()
    # 閲覧記録を保存する。
    VieLogsManager().insert(article_id, request)
    return render_template('article.html', title=article.title, article=article, sidebar=sidebar)

ViewLogModel.py

import os
import boto3
from boto3.dynamodb.conditions import Attr, Key

from datetime import datetime, timedelta, timezone


class VieLogsManager:
    """
    ページビュー記録の操作
    """
    def __init__(self):
        # Initialize connection with database
        session = boto3.session.Session(
            region_name=os.environ['MY_REGION'], 
            aws_access_key_id=os.environ['MY_ACCESS_KEY_ID'], 
            aws_secret_access_key=os.environ['MY_SECRET_ACCESS_KEY']
        )

        dynamodb = session.resource('dynamodb')

        # Connect to db table
        self.table_name = 'page_view_logs'
        self.table = dynamodb.Table(self.table_name)
        self.JST = timezone(timedelta(hours=+9), 'JST')
    
    def insert(self, article_id, request):
        """
        閲覧履歴を記録する。
        """
        # if request.environ['REMOTE_ADDR'] is '127.0.0.1':
        #     # localでのテストは集計しない
        #     return

        http_connection = 'close'
        try:
            http_connection = request.environ['HTTP_CONNECTION']
        except Exception, e:
            print(e)

        item = {
            'article_id': article_id,
            'view_at': datetime.now(self.JST).strftime('%Y-%m-%d %H:%M:%s'), 
            'remote_addr': request.environ['REMOTE_ADDR'],
            'is_keep_alive': self.is_keep_alive(http_connection),
            'browser': self.accessed_browser(request.environ['HTTP_USER_AGENT']),
            'user_os': self.user_os(request.environ['HTTP_USER_AGENT'])
        }
        
        # 追加する
        responce = self.table.put_item(
            TableName=self.table_name,
            Item=item
        )
        return responce

クラス内のメソッドは順次解説します。

解説

__init__(self)では、クラスの呼び出し時にDynamoDBとの接続をします。 キー情報は、環境変数に入れてあります。

put_item()では、保存する項目をdictで渡せます。DynamoDbではプライマリーキーを必ず渡しましょう。

コネクションの有無

@staticmethod
    def is_keep_alive(http_connection):
        return http_connection == 'keep-alive'
20180728追記:
request.environ[&#39;HTTP_CONNECTION&#39;]がローカルでは取得できましたが、Lamabda上ではKeyErrorとなっていしまいます。
現在、コネクションの有無は判定できません。

ユーザーのブラウザを判定

HTTP_USER_AGENTから、ユーザーのブラウザを判定する関数です。 下記を参考にしました。

UserAgentからOS/ブラウザなどの調べかたのまとめ

keywordsに判定するkeyとブラウザをおきます。 異なるブラウザも同じキーワードが入っているため、判定する順序に気をつけてください。

python3.6からdictの順序が保たれます

@staticmethod
    def accessed_browser(http_user_agent):
        """
        return accessed browser
        """
        http_user_agent = http_user_agent.lower()
        keywords = {
            'trident': 'IE11',
            'edge': 'Edge',
            'chrome': 'Chrome', 
            'opr': 'Opera', 
            'firefox': 'Firefox',
            'safari': 'safari'
        }
        for key, val in keywords.items():
            if http_user_agent.find(key) > -1:
                return val
        return 'othres'

対象は、IE11, Edge, Chrome, Opera, Firefox, safariとその他otherとします。

ユーザーのOSを判定

OSも同じく、HTTP_USER_AGENTから判定します。 参考も同じ。

@staticmethod
    def user_os(http_user_agent):
        """
        return user os
        """
        http_user_agent = http_user_agent.lower()

        keywords = {
            'nt 10.0': 'Windows 10',
            'mac': 'Mac', 
            'android': 'Android',
            'iphone': 'iPhone',
            'nt 6.1': 'Windows 7',
            'nt 5': 'Windows XP', 
            'linux': 'Linux'
        }
        for key, val in keywords.items():
            if http_user_agent.find(key) > -1:
                return val
        return 'othres'

OSでは、パソコンの他にスマホやタブレットも判定できるようです。 この関数では、Windows XP, 7, 10, Mac, Linux, iPhone, Androidを判定します。

結果

local環境で動かした結果です。

table_page_view_logs

ChromeとFireFox、それからMacを認識できていますね。 その他の、ブラウザとOSは手元にないため、運用しつつテストしていこうと思います。

IPアドレスの取り扱いについて

IPアドレスによって個人情報までばれてしまうと、心配になる方がいらっしゃるかと思います。 当サイトでは、IPアドレスを使って個人を特定することはありません。 あくまでも、統計解析の材料として扱います。

個人のIPアドレスで分かるのは、最寄りのルーター位置のみで、最大でも市区町村単位までです。 また、IPアドレスはリクエスト先や途中でも、常に公開されるものです。

IPアドレスから得られる情報
IPアドレスの経路を確認した場合に、ルータのホスト名から位置を推定できる場合もあります。しかし、その場合であっても、追跡できるのは最寄りのルータまでとなり、そこから先の詳細な住所などはわかりません。 弊社では専任の調査員による位置情報調査を行っていますが、ルータ単位での位置判定は、最大で市区町村単位となっています。
引用元:IPアドレスから個人情報はどこまでわかる?

ご自身のIPアドレスの情報はIPアドレスから住所を検索から確認できます。 私が試した結果は、位置情報は隣の市が表示されました。

それでも心配な方は、セキュリティソフトやファイヤーウォールの設定をしっかりと見直してください。

おわりに

機能の構築と本記事の作成の中で、ウェブの解析ソフトが見ている情報や情報の扱いまで学ぶことが出来ました。 ネットワークの技術も、これを機に調べていこうと思います。

収集したデータを使った解析は、また次回行います。

最後までご覧いただき、ありがとうございます。


設計編はこちら リクエスト情報から訪問者の情報を集めてみる[Python Flask + DynamoDB]-1.設計編


本ブログの構成について