Sponsored Link

月別アーカイブ: 8月 2017

(89) Pythonで画像をHTTP出力する。

(89) Pythonで画像をHTTP出力する。

アクセスカウンタの画像表示などでよく使われる方法だ。
通常、HTMLの IMGタグの SRC属性には画像ファイルのURLを指定する。
SRC属性に Pythonプログラムを指定し、HTTPレスポンスとして画像を返させることができる。

用途

プログラムで動的に生成した画像をHTTPレスポンスとして返したい場合に使用できる。
また、画像ファイルのパスを秘密にしておきたい場合に使用できる。

プログラム

以下のプログラムでは、IMGタグの SRC属性に Pythonプログラムを指定している。
この Pythonプログラムでは、実行ごとにランダムに画像を選択し、HTTPレスポンスとして返している。

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>サンプル</title>
</head>
<body>
<img src="load_img.cgi">
</body>
</html>

load_img.cgi

※cgiファイルはアップロード後に実行属性を付与しないと500エラーが出るので注意

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
import os
import random

# 画像ファイルをランダム選択
img_src = "%d.jpg" % random.randint(1,2)

# 画像を出力
print "Content-Type: image/jpeg"
print "Content-Length: %d\n" % os.stat(img_src).st_size
print open(img_src,"rb").read()

実行サンプルはこちら(↓)
https://python.dogrow.net/sample/0089

[F5]キー押下などでページを更新するとランダムに表示画像が変わる。


(88) ライブカメラ画像をホームページに貼る。

(88) ライブカメラ画像をホームページに貼る。

■やりたいこと

・実家の窓際にライブカメラを設置し、窓から見える景色を東京でも眺めたい。
・映像ではなく、1分に1回程度更新される静止画でよい。
・カメラはなるべく安価なものがよい。

■必要なもの

・ホームページ設置サーバー(FTP,Python,PHPが使えること)
・WEBカメラ(Wifi接続可能であること)

■手順

手順1:WEBカメラを購入する。

・今回はI-O DATA社製の TS-WRLCE を使用する。(その後、赤外線カメラ付きのTS-WLC2でも同じ手順でできた。)

手順2:WEBカメラの設定をする。

・画像を転送するFTPサーバーの情報を設定する。

・動作検知の検出範囲を画面全体に設定する。

・動作検知の検出間隔を60秒に設定し、動作検知機能を有効に設定する。

手順3:最新画像ファイル取得プログラムを作成(Python)

このライブカメラは、指定したディレクトリ配下に「snapshot_yyyymmddhhmm」なるディレクトリを複数作成する。さらに、個々のディレクトリ配下に「motion-yyyy-mm-dd-hh-mm-ss.jpg」なるJPEG画像ファイルを複数作成する。

したがって、ホームページ上に最新の1枚を表示したい場合は、最新ディレクトリ配下の最新画像ファイルを1個だけ取得し、表示すればよい。ここではPythonでこの機能を実装する。

get_img.py

import sys
import os

#---------------------------------
# argv[1] : directory path
if __name__ == '__main__':
    ary_argv = sys.argv
    img_path = ary_argv[1] + "/"

    # 指定ディレクトリ配下の最新ディレクトリを取得
    ary_entry = os.listdir(img_path)
    ary_entry = [x for x in ary_entry if os.path.isdir(img_path + x) ]
    ary_entry = sorted(ary_entry, reverse=True)
    target_dir = img_path + ary_entry[0] + "/"

    # 最新ディレクトリ配下の最新画像ファイルを取得
    ary_jpeg = os.listdir(target_dir)
    ary_jpeg = [x for x in ary_jpeg if os.path.isfile(target_dir + x) ]
    ary_jpeg = sorted(ary_jpeg, reverse=True)
    target_jpeg = ary_jpeg[0]

    # 実行者へ答えを提供
    print(target_dir + target_jpeg)

手順4:ライブ画像を閲覧するためのホームページを作成(HTML+PHP)

livecam.php

<!DOCTYPE html>
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=utf-8" />
<TITLE>サンプル</TITLE>
</HEAD>
</BODY>
<?php
  exec("python3 ./get_img.py '{FTP画像転送先ディレクトリ}'", $resp, $code);
  echo "<img src='{$resp[0]}'>";
?>
</BODY>
</HTML>

【余談#3】 Value-Serverが無料SSLを開始

【余談#3】 Value-Serverが無料SSLを開始

このブログは有料ホスティングサービスであるValueServer上に設置している。

私が利用している「スタンダード」プランの場合、ディスク容量とファイル数が制限範囲内ならば、
・ WordPressをいくつも開設可能
・メールアドレスをいくつも作成可能
・データベースをいくつも作成可能
など、通常個人が使用する程度ならば無制限と言えるサービスで重宝している。



2017年8月8日、さらに喜ばしいことに、
無料SSLを開始しました。
との案内メールが入っていた。

私が所有する他のいくつかのサイトでは数年前から常時SSL化しているのだが、それらは独自IPアドレス代が年額5,000円弱、SSL証明書代が年額1,500円弱と、常時SSL化のコストはけっこうお高い…

これが無料になるというのだから早速やってみた。
ログイン時にIDとパスワードが暗号化されるだけでも価値がある。

作業時間はわずか1分弱という簡単さだった。手順はこちら(↓)を参照。
https://www.value-server.com/startup/free_ssl.html

当サイトへの接続時に鍵アイコンが表示されるようになった。(FireFoxを使用)
※ただし、非セキュア(非SSL)のページに置かれた画像のリンクを貼っているため黄色い△が付いてしまう…

参照画像もHTTPSアクセス可能な場所に置いたら緑色の鍵マークになった。

(87) NPBプロ野球選手の年別成績を取得する。(ver.2)

(87) NPBプロ野球選手の年別成績を取得する。(ver.2)

前回の 「(86) NPBプロ野球選手の年別成績を取得する。」 では、一人の選手の紹介ページのURLを入力し、一人の選手の年別成績を出力するだけの機能だった。数百人ものプロ野球選手についてこれを手作業で繰り返すのは大変だ。

今回は、NPB様サイトのチームメンバー一覧ページのURLを入力し、そこから個々の選手紹介ページのURLを抽出し、個々の選手の年別成績を出力するように改良する。すなわち、チームを指定すれば所属メンバー全員分のデータが自動で出力されるようにする。

■仕様

・NPB様ホームページの1チームの選手一覧ページのURLを入力する。
・そのページから選手個々の紹介ページのURLを自動抽出する。
・選手個々の紹介ページから年別成績を自動抽出する。
・打者成績、投手成績に分けてCSVファイルを自動出力する。

■プログラム

ちょっと力ずくなところもあるが後で改良しよう…

コマンドライン入力

以下の操作でホークスの全選手の年度別投手成績、年度別打者成績がファイル出力される。

$ mkdir ./da
$ mkdir ./pt
$ python3

>>> import lib_npb
>>> lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_h.html", "H")

他のチームのURLは以下の通り。

http://npb.jp/bis/teams/rst_c.html 広島
http://npb.jp/bis/teams/rst_g.html 巨人
http://npb.jp/bis/teams/rst_db.html 横浜
http://npb.jp/bis/teams/rst_t.html 阪神
http://npb.jp/bis/teams/rst_s.html ヤクルト
http://npb.jp/bis/teams/rst_d.html 中日

http://npb.jp/bis/teams/rst_h.html ソフトバンク
http://npb.jp/bis/teams/rst_f.html 日ハム
http://npb.jp/bis/teams/rst_m.html ロッテ
http://npb.jp/bis/teams/rst_l.html 西武
http://npb.jp/bis/teams/rst_e.html 楽天
http://npb.jp/bis/teams/rst_bs.html オリックス

lib_npb.py

import urllib.request
from bs4 import BeautifulSoup
import csv

#////////////////////////////////////////////////////////////////
class NpbPlayer:
    #------------------------------------------------------------
    def __init__(self, name, url):
        self.name = name
        self.url  = "http://npb.jp" + url
        self.ary_record_pitch = []    # 投手記録
        self.ary_record_bat = []      # 打者記録

    #------------------------------------------------------------
    # 1選手の投手記録をCSVファイルに出力
    def output_record_to_csv_file_pitch(self, fname):
        if len(self.ary_record_pitch) > 0 :
            with open(fname, "w") as fh:
                writer = csv.writer(fh, lineterminator="\n")
                writer.writerows(self.ary_record_pitch)

    #------------------------------------------------------------
    # 1選手の打者記録をCSVファイルに出力
    def output_record_to_csv_file_bat(self, fname):
        if len(self.ary_record_bat) > 0 :
            with open(fname, "w") as fh:
                writer = csv.writer(fh, lineterminator="\n")
                writer.writerows(self.ary_record_bat)

    #------------------------------------------------------------
    # 1選手の記録を収集
    def get_record(self):
        try:
            resp = urllib.request.urlopen(self.url)
        except urllib.error.HTTPError as e:
            print("HTTP-Error : ", e.code)
            return False
        except urllib.error.URLError as e:
            print("URL-Error : ", e.reason)
            return False
        else:
            self.ary_record_pitch = []
            self.ary_record_bat = []
            bs = BeautifulSoup(resp.read(), "html.parser")
            for div in bs.findAll("div",id="registermaintbl"):
                th = div.find(text="防")
                for tr in div.findAll("tr",class_="registerStats"):
                    ary_1_record = []
                    for td in tr.findAll("td"):
                        ary_1_record.append(td.get_text())
                    if th == None :
                        self.ary_record_bat.append(ary_1_record)
                    else:
                        self.ary_record_pitch.append(ary_1_record)
            return True

#////////////////////////////////////////////////////////////////
def get_player_list_detail( resp ):
    ary_cPlayer = []
    bs = BeautifulSoup(resp.read(), "html.parser")
    # find name
    for tr in bs.findAll("tr",{"class":"rosterPlayer"}):
        td = tr.find("td",{"class":"rosterRegister"})
        a = td.find("a")
        if a == None :
            continue
        url  = a.attrs["href"]
        name = a.get_text()
        cPlayer = NpbPlayer(name, url)
        ary_cPlayer.append(cPlayer)
    return ary_cPlayer

#////////////////////////////////////////////////////////////////
def get_player_list( team_url ):
    try:
        resp = urllib.request.urlopen(team_url)
    except urllib.error.HTTPError as e:
        print("HTTP-Error : ", e.code)
        return None
    except urllib.error.URLError as e:
        print("URL-Error : ", e.reason)
        return None
    else:
        ary_cPlayer = get_player_list_detail(resp)
        return ary_cPlayer

#////////////////////////////////////////////////////////////////
def generate_record_file_for_1team( team_url, prefix ):
    ary_cPlayer = get_player_list(team_url)
    for cPlayer in ary_cPlayer:
        if True == cPlayer.get_record():
            print("now generating %s" % cPlayer.name)
            cPlayer.output_record_to_csv_file_bat(  "./da/data_%s_%s_da.txt" % (prefix, cPlayer.name))
            cPlayer.output_record_to_csv_file_pitch("./pt/data_%s_%s_pt.txt" % (prefix, cPlayer.name))

■備忘録

python3では reload()が使えなくなった。
同じことを以下のように実現できる。

import importlib
importlib.reload(lib_npb)

シーズン中は日々成績が変化するので、ときどき以下を実行して最新情報を収集する。

import lib_npb
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_c.html", "C")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_g.html", "G")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_db.html", "DN")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_t.html", "T")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_s.html", "Y")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_d.html", "D")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_h.html", "H")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_f.html", "F")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_m.html", "M")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_l.html", "L")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_e.html", "E")
lib_npb.generate_record_file_for_1team("http://npb.jp/bis/teams/rst_bs.html", "O")

(86) NPBプロ野球選手の年別成績を取得する。

(86) NPBプロ野球選手の年別成績を取得する。

NPB様のサイトには、現役全選手の年別成績が掲載されている。
趣味でいろいろと統計計算をしてみたいのだが、選手個々のデータをコピペでExcelに貼り付ける作業には限界がある。
そこで、またスクレイピングで取得することにする。

以前 (81) 野球選手の成績を主成分分析 (続編1/2) ではYahooスポーツ様のサイトの掲載情報を計算に使わせていただいた。今回はNPB様のデータを取得してみたい。

試作したプログラムでは、現在三冠王の柳田選手のページを対象にデータ取得してみる。

実行結果はこんな感じになった。
CSVファイルなので、この後はいろいろなツールで読み込んで計算に使える。

2011,福岡ソフトバンク,6,5,5,1,0,0,0,0,0,0,0, 0,0, 0,0,0,3, 0,.000,.000,.000
2012,福岡ソフトバンク,68,212,195,17,48,10,1,5,75,18,6, 1,2, 0,10,5,56, 2,.246,.385,.300
2013,福岡ソフトバンク,104,337,298,48,88,19,2,11,144,41,10, 1,0, 0,32,7,96, 3,.295,.483,.377
2014,福岡ソフトバンク,144,615,524,91,166,18,4,15,237,70,33, 6,0, 3,72,16,131, 8,.317,.452,.413
2015,福岡ソフトバンク,138,605,502,110,182,31,1,34,317,99,32, 8,0, 1,88,14,101, 9,.363,.631,.469
2016,福岡ソフトバンク,120,536,428,82,131,31,4,18,224,73,23, 2,0, 0,100,8,97, 8,.306,.523,.446
2017,福岡ソフトバンク,93,400,317,73,105,23,0,25,203,80,14, 7,0, 7,70,6,86, 5,.331,.640,.453

■仕様

・選手紹介ページのURLを与える。
・対象ページから年別成績を抽出してCSVファイルに保存する。

■プログラム

コマンドライン入力

$ python3

>>> import lib_npb
>>> cPlayer = lib_npb.get_player_data("http://npb.jp/bis/players/31835133.html")
>>> cPlayer.output_record_to_csv_file("data.txt")

lib_npb.py

import urllib.request
from bs4 import BeautifulSoup
import csv

#////////////////////////////////////////////////////////////////
class NpbPlayer:
    def __init__(self, name):
        self.name = name
        self.ary_record = []

    def append_record(self, ary):
        self.ary_record.append(ary)

    def output_record_to_csv_file(self, fname):
        with open(fname, "w") as fh:
            writer = csv.writer(fh, lineterminator="\n")
            writer.writerows(self.ary_record)

#////////////////////////////////////////////////////////////////
def get_player_data_detail( resp ):
    bs = BeautifulSoup(resp.read(), "html.parser")
    # find name
    td = bs.find("td",{"class":"registerPlayer"})
    h1 = td.find("h1")
    cPlayer = NpbPlayer(h1.get_text())
    # find record
    div = bs.find("div",{"id":"registermaintbl"})
    for tr in div.findAll("tr",{"class":"registerStats"}):
        ary_1_record = []
        for td in tr.findAll("td"):
            ary_1_record.append(td.get_text())
        cPlayer.append_record(ary_1_record)
    return cPlayer

#////////////////////////////////////////////////////////////////
def get_player_data( url ):
    try:
        resp = urllib.request.urlopen(url)
    except urllib.error.HTTPError as e:
        print("HTTP-Error : ", e.code)
        return None
    except urllib.error.URLError as e:
        print("URL-Error : ", e.reason)
        return None
    else:
        cPlayer = get_player_data_detail(resp)
        return cPlayer