もなかアイスの試食品

「とりあえずやってみたい」そんな気持ちが先走りすぎて挫折が多い私のメモ書きみたいなものです.

PythonでSlackにサーバの状態を送信してみた

はじめに

はてなブログのTOPページを見ていたらたまたま見つけたブログ

blog.8arrow.org

このサイトを見るまでSlackを知らなかった

Slackについて、失礼ながら以下のサイトから転記

mayonez.jp

Slackとは、チャットができるコミュニケーションツールです。シンプルなUIデザインで、ショートカットキーも豊富、プログラミングコードを綺麗に投稿できるスニペットが用意されていて、高性能な検索機能など、情報共有のしやすさ情報の蓄積として使いやすいコミュニケーションサービスです。機能は他にもまだまだあります。Web版、スマホアプリ版、タブレット版があり、いつでもどこでも情報共有ができます。「ショートカット」が豊富なのと、「プログラムコード投稿オプション」がついているので、特にエンジニアがコミュニケーションとるのに便利です。

社内のチャットツールとして結構使われているらしい

いくつか料金プランがあり、無料でも使える

↓料金プランについてはコチラのサイトがわかりやすい

iteach.jp

すごく個人的な問題点

実は1年前から気象庁XMLを受信しているけど、全然活用できていない・・・

XMLが3~4GBたまっているんですけど

どこかのAPIを利用したいと思いつつも、万が一間違った情報が人の目に付くところに出るのも困る

でも何かに利用したいと考えていたところ、Slackで一人チャットなら問題ないでしょ!

というわけで、SlackのAPIを利用してみた

Slackのユーザ登録はおいていて、個人的にハマったアプリの登録から手順をφ(..)メモメモ

アプリの登録・OAuthの認証

アプリの登録・OAuthの認証方法は以下のサイトと同じ手順でやった

qiita.com

一応、公式サイトと同じ手順ではある

api.slack.com

アプリの登録は、Slack APIのサイトの右上の方にの「Your Apps」から登録した

f:id:monakaice88:20170124224656p:plain

あとアプリのOAuth認証は、ブラウザを使った手動で行った。(本当は、OAuthの認証まで内部処理を作らないとイケないでしょうが・・・)

また、OAuthをする前に「Redirect URL(s)」の設定をしないと「Step1」でうまく行かなかった

f:id:monakaice88:20170124232612p:plain

Step1(認証)

以下のようなURLにアクセスする

https://slack.com/oauth/authorize?client_id=xxx&scope=channels:read chat:write:bot&

client_idscopeは必須

  • client_id - アプリと登録されたときに発行されたID
  • scope - アプリの権限。ココでアプリが出来ること(やること)を設定する

scopeの詳細は以下のサイトを見るべし!

api.slack.com

アクセスすると「なんかアプリが許可求めているけどどうする?」的な画面が表示されるのでOKする。

すると「Redirect URL(s)」で設定したページへGETクエリ付きでリダイレクトする。

GETクエリに「code=???」と付いているけど、次のstepで使用する

Step2(アクセストークンの取得)

次にアクセストークンを取得する

https://slack.com/api/oauth.access?client_id=xxx&client_secret=yyy&code=zzz

client_idclient_secretcodeは必須

  • client_id - アプリと登録されたときに発行されたID
  • client_secret - アプリと登録されたときに発行されたモノ
  • code - Step1のリダイレクトで送られた(取得した)コード

アクセスするとjsonが帰ってくる

{
  "access_token": "xxx",
  "ok": true,
  "scope": "xxx",
  "team_id": "xxx",
  "team_name": "xxx",
  "user_id": "xxx"
}

Pythonでサーバの状態を通知する

取り敢えず動作確認なので、Pythonスクリプトでtopコマンドを実行した結果を1時間の間隔で通知することにした。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import subprocess
import requests

def res_cmd_lfeed(cmd):
 return subprocess.Popen(
   cmd, stdout=subprocess.PIPE,
   shell=True).stdout.readlines()

def res_cmd_no_lfeed(cmd):
  return [x.decode('utf-8').rstrip("\n") for x in res_cmd_lfeed(cmd)]


def main():
  cmd = ("top -b -n 1 | sed -n '1,5p'")
  cmd_res = res_cmd_no_lfeed(cmd)
  msg = '\n'.join(cmd_res)
  post_message(msg)


def post_message(msg):
  postUrl = 'https://slack.com/api/chat.postMessage'
  token = 'xxxxxx'
  channel = 'xxxxxx'
  username = 'xxxxxx'

  pyload = {
    'token': token,
    'channel': channel,
    'username': username,
    'text': msg
  }

  res = requests.post(postUrl, data=pyload)

if __name__ == '__main__':
  main()

参考にしたサイト

qiita.com

作ったPythonスクリプトを「/usr/local/bin/cron/chat_top.py」に保存し、cronで1時間おきに実行するようにした。

以下の様なテキストファイルを「crontab.conf」に保存

0 */1 * * * export PATH="/usr/local/lib/anaconda3/bin:$PATH"; python /usr/local/bin/cron/chat_top.py

以下のコマンドでcronを設定

crontab crontab.conf

一時間おきにサーバからチャットが送られるようになった

f:id:monakaice88:20170124224649p:plain

サーバからSlackへチャットを送ることが出来るようになった。

次はPythonでデーモンを作って、電車の運行情報や気象庁XML情報をチャットに送ることをやってみようと思う

【Python】スクレイピングで電車の運行情報を取得してみた

はじめに

最近、Slackというチャットサービスを個人的に利用していて

Slack APIを使って電車の運行情報をチャットで流せないかなーて考え中

電車の運行情報のAPIを公開されているけどお金がかかる・・・

プライベートで公開されている方もいるけど、こだわり始めるとその方のサーバに負荷かけそう

大手サイトのWEBページから取得できたらいいなーと思っていたら、

Qiitaに情報が載っていた

qiita.com


このサイトを見るまで「スクレイピング」という単語を知らなかった・・・

情報元

電車の運行情報で、時々利用するのが以下のサイト。

Pythonを動かしているときにちょうど遅延情報が出ていた。

transit.yahoo.co.jp

江ノ島電鉄線は利用したこと無いけど

見た目はこんな感じ

f:id:monakaice88:20170122124201p:plain


htmlの構造はこんな感じ

f:id:monakaice88:20170122124522p:plain


このサイトから、Python3.5とライブラリ「Beautiful Soup4」を利用して運行情報を取得する

環境構築の準備

私はAnacondaをWindowsにインストールしているため、以下のコマンドで今回用の環境を構築

conda create -n py35 python=3.5 anaconda
activate py35
pip install beautifulsoup4

実装

あまり深く考えず、参考にしたサイトを見よう見真似でコード作成

# -*- coding: utf-8 -*-

import urllib.request
import bs4

url = 'http://transit.yahoo.co.jp/traininfo/detail/148/0/'
html = urllib.request.urlopen(url).read()
soup = bs4.BeautifulSoup(html, 'lxml')

informationElement = soup.find('div', {'id': 'mdServiceStatus'})
information = informationElement.find('p').find(text=True, recursive=False)

postingDateElement = informationElement.find('p').find('span')
postingDate = ''
if postingDateElement is not None:
    postingDate = postingDateElement.find(text=True, recursive=False)

print(information + postingDate)


実行結果

f:id:monakaice88:20170122125611p:plain

とりあえず運行情報が取得できるようになったので、DBも利用してSlackを通して運行情報を知らせるサーバを構築しよう

CentOS6.8にMapServerのビルド&インストールしてみた

はじめに

単純にMapServerのインストールなら、以下のコマンドでインストールされる

# yum install mapserver

↓参考サイト

システム覚書帳 : [mapserver]CentOS6.5でmapserver6.0.3をyumでインストール - めっちゃ簡単!

ただし、今回は「PHP 5.6」と「PostgreSQL 9.6」を使用したいので、ソースコードからコンパイル&インストールする方法でやる

MapServerの最新は「7.x」だけど、コンパイル時に依存的な問題に引っかかったため、6.4.4にした

今回構築したMapServerの環境

SELinuxの無効化

# vi /etc/sysconfig/selinux
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
#SELINUX=enforcing
SELINUX=disabled

CentOSを再起動する

"Development Tools"をインストール

# yum groupinstall "Development Tools"

ApacheサーバのインストールとEPELリポジトリの追加

# yum install httpd httpd-devel epel-release

PHP5.6のインストール

# rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
# yum install --enablerepo=remi,remi-php56 php php-devel php-mbstring php-pdo php-gd php-xml php-pear php-pgsql

PostgreSQL9.6 & PostGIS2.3のインストール

# rpm -Uvh https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-6-x86_64/pgdg-centos96-9.6-3.noarch.rpm
# yum install postgresql96 postgresql96-server postgresql96-devel  postgis2_96

PostgreSQLのDBクラスタの構築・サーバ起動については過去記事と同じなのでリンク

monakaice88.hatenablog.com

MapServerのインストールだけなら不要なのでココでは省略

MapServerのビルド & インストール

MapServerのビルドとインストールは以下のサイトを参考にした

↓参考サイト

システム覚書帳 : [mapserver]CentOS6.5で、可能な限りyumでmapserverをセットアップする

↓公式サイト

Compiling on Unix — MapServer 7.0.4 documentation

必須パッケージのインストール

# yum install libpng libpng-devel
# yum install freetype freetype-devel
# yum install libjpeg libjpeg-devel
# yum install zlib zlib-devel

推奨パッケージのインストール

# yum install proj proj-devel proj-epsg
# yum install libcurl libcurl-devel
# yum install gdal gdal-devel

オプションなパッケージのインストール

# yum install libtiff libtiff-devel
# yum install libgeotiff libgeotiff-devel
# yum install geos geos-devel
# yum install libxml2 libxml2-devel
# yum install giflib giflib-devel
# yum install fcgi fcgi-devel
# yum install cairo cairo-devel
# yum install libxslt libxslt-devel

MapServerのインストールに「cmake28」が必要なのでインストールする

# yum install cmake28

MapServerのソースコードのダウンロード

# cd
# yum install wget
# wget http://download.osgeo.org/mapserver/mapserver-6.4.4.tar.gz

ダウンロード可能なソースコードの一覧はこちら

MapServerのソースコードアーカイブを展開し、ビルド準備する

# tar xvhf mapserver-6.4.4.tar.gz
# cd mapserver-6.4.4
# mkdir build
# cd build
# cmake28 .. -DWITH_CURL=ON -DWITH_CLIENT_WFS=ON -DWITH_CLIENT_WMS=ON -DWITH_PHP=ON -DWITH_KML=ON -DWITH_XMLMAPFILE=ON -DWITH_POSTGIS=ON -DCMAKE_PREFIX_PATH=/usr/pgsql-9.6/bin/ -DWITH_FRIBIDI=0

cmakeコマンドがうまくいくと以下のように出力される

-- /usr/include/php/main
-- Found PHP5-Version 5.6.29 (using /usr/bin/php-config)
-- * Summary of configured options for this build
--  * Mandatory components
--   * png: /usr/lib64/libpng.so
--   * jpeg: /usr/lib64/libjpeg.so
--   * freetype: /usr/lib64/libfreetype.so
--  * Optional components
--   * GDAL: /usr/lib64/libgdal.so
--   * OGR: /usr/lib64/libgdal.so
--   * GD: disabled
--   * GIF: /usr/lib64/libgif.so
--   * MYSQL: disabled
--   * FRIBIDI: disabled
--   * GIF: /usr/lib64/libgif.so
--   * CAIRO: /usr/lib64/libcairo.so
--   * SVGCAIRO: disabled
--   * RSVG: disabled
--   * CURL: /usr/lib64/libcurl.so
--   * PROJ: /usr/lib64/libproj.so
--   * LIBXML2: /usr/lib64/libxml2.so
--   * POSTGIS: /usr/pgsql-9.6/lib/libpq.so
--   * GEOS: /usr/lib64/libgeos_c.so
--   * FastCGI: /usr/lib64/libfcgi.so
--   * Oracle Spatial: disabled
--   * SDE: disabled
--   * Exempi XMP: disabled
--  * Optional features
--   * WMS SERVER: ENABLED
--   * WFS SERVER: ENABLED
--   * WCS SERVER: ENABLED
--   * SOS SERVER: disabled
--   * WMS CLIENT: ENABLED
--   * WFS CLIENT: ENABLED
--   * ICONV: ENABLED
--   * Thread-safety support: disabled
--   * KML output: ENABLED
--   * Z+M point coordinate support: disabled
--   * XML Mapfile support: ENABLED
--  * Mapscripts
--   * Python: disabled
--   * PHP: ENABLED
--   * PERL: disabled
--   * RUBY: disabled
--   * JAVA: disabled
--   * C#: disabled
--   * Apache Module (Experimental): disabled
--
-- Will install files to /usr/local
-- Will install libraries to /usr/local/lib64
-- Configuring done
-- Generating done
-- Build files have been written to: /root/mapserver-6.4.4/build

cmakeコマンドが無事成功したときに「make && make install」コマンドを実行する・・・が

PHP5.6をインストールした環境(厳密には5.6.25以上?)では、「make」コマンド実行時に「mapscript/php/error.c 」でコンパイルエラーが発生する

↓こんな感じ

[ 82%] Building C object mapscript/php/CMakeFiles/php_mapscript.dir/error.c.o
/root/mapserver-6.4.4/mapscript/php/error.c: In function ‘zim_errorObj___get’:
/root/mapserver-6.4.4/mapscript/php/error.c:71: error: called object ‘zend_error’ is not a function
/root/mapserver-6.4.4/mapscript/php/error.c:72: error: called object ‘zend_error’ is not a function
make[2]: *** [mapscript/php/CMakeFiles/php_mapscript.dir/error.c.o] エラー 1
make[1]: *** [mapscript/php/CMakeFiles/php_mapscript.dir/all] エラー 2

これはPHPソースコードが変更されたため発生しているらしい

なので、以下のサイトを参考に「mapserver-6.4.4/mapscript/php/error.c」のソースコードを変更する

github.com

github.com

ソースコード「mapscript/php/error.c」未定義となっているマクロを34行目あたりに追記する

# vi /root/mapserver-6.4.4/mapscript/php/error.c
#if PHP_VERSION_ID >= 50625
#undef ZVAL_STRING
#define ZVAL_STRING(z, s, duplicate) do {       \
    const char *__s=(s);                            \
    zval *__z = (z);                                        \
    Z_STRLEN_P(__z) = strlen(__s);          \
    Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\
    Z_TYPE_P(__z) = IS_STRING;                      \
} while (0)
#endif

もう一度ビルドを実行する

# cd /root/mapserver-6.4.4/build
# make
# make install

「make install」でインストールされたCGIApacheにコピーする

# cp /usr/local/bin/mapserv /var/www/cgi-bin/

Apacheサーバの起動

ポートの開放

# vi /etc/sysconfig/iptables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
# ↓追記
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# service httpd start

MapServerにアクセスしてみる

http://<サーバのIP>/cgi-bin/mapserv

ブラウザに以下の文字列が表示される。

No query information to decode. QUERY_STRING is set, but empty.

これが表示されると、無事にMapServerが動作している・・・らしい。

MapServerを構築したが、実は使い方がわかっていない・・・

次回以降にMapServerを使って、何かしらの機能なり画面なりを作って見ようと思う