15分で情シスに怒られる方法
株式会社アシスト 山田 聡@DENZOWILL
みんなのPYTHON勉強会#7 LT(2015/12/9)
注意
※本当に怒られても責任は取れません。
ジョークです
mechanizeとかbottleとか触るちょっとしたきっかけにな
れば...
お題
イントラの社員検索で怒られる
名前とか社員番号でしか検索できなくて不便
内線番号とかでも検索できるようにして改善して怒られ
たい
材料
Python
BeautifulSoup
mechanize
bottle
レシピ
1. 社員検索にアクセスします
2. 結果のHTMLを解析します
3. 検索条件に該当する社員を取得します
4. 結果をJSONで戻します
1. 社員検索にアクセスします
検索用のクラスを作成
import mechanize
from BeautifulSoup import BeautifulSoup
class EmpWorker(object):
    """
    社員検索を改善したい
    """
    def __init__(self):
        self.browser = mechanize.Browser()
        # proxyはいらない
        self.browser.set_proxies({})
        self.browser.set_handle_robots(False)
        # POSTパラメータをGETにして全社員が戻るURL
        self.target_url = "http://xxxxxxxx.do?p_kensaku=_&p_kensaku2=&p_kensaku3=
2. 結果のHTMLを解析します
検索用のメソッド追加
    # 検索キーワードを取る
  def get_emp(self, search_key=None, search_value=None):
        res = self.browser.open(self.target_url)
        # 割と文字コード判定ミスる
        # BeautifulSoup大好き
        soup = BeautifulSoup(res, fromEncoding="sjis")
3. 検索条件に該当する社員
を取得します
(get_empの続き)
        # 結果用のリスト
        ret_list = []
        # うちの社員検索はtableタグ
        for i, tr_node in enumerate(soup.findAll("tr")):
            tds = [x.text for x in tr_node.findAll("td")]
            if len(tds) > 7:
                tmp_dict = {
                    u"社員番号": tds[0],
                    u"社員名": tds[1],
                    u"読み": tds[2],
                    u"地区": tds[3],
                    u"所属部署": tds[4],
                    u"内線": tds[6],
                }
                # 有効な検索条件があるときだけ働く
                if search_key and search_value and search_key in tmp_dict:
                    if search_value in tmp_dict[search_key]:
                        ret_list.append(tmp_dict)
                else:
                    ret_list.append(tmp_dict)
        return ret_list
使ってみる
社員名 == 山田 聡
In [1]: import EmpWalker
In [6]: EmpWalker.EmpWalker().get_emp(search_key=u"社員名", search_value=u"山田  聡
Out[6]: 
[{u'u5185u7dda': u'"sayamada',
  u'u5730u533a': u'u5e02u30f6u8c37',
  u'u6240u5c5eu90e8u7f72': u'23131',
  u'u793eu54e1u540d': u'u5c71u7530  u8061',
  u'u793eu54e1u756au53f7': u'2409',
  u'u8aadu307f': u'SATOSHI YAMADA'}]
見づらかったので
In [14]: result = EmpWalker.EmpWalker().get_emp(search_key=u"社員名", search_value
In [15]: for k, v in result[0].items():print k,v
所属部署 99999
社員番号 999999
地区 xxxx
内線 12345
読み SATOSHI YAMADA
社員名 山田  聡
4. 結果をJSONで戻します
JSONモジュール使うだけ
In [16]: import json
In [17]: result = EmpWalker.EmpWalker().get_emp(search_key=u"社員名", search_value
In [18]: print json.dumps(result, indent=4)
[
    {
        "u6240u5c5eu90e8u7f72": "99999", 
        "u793eu54e1u756au53f7": "99999", 
        "u5730u533a": "xxxxxxx", 
        "u5185u7dda": "12345", 
        "u8aadu307f": "SATOSHI YAMADA", 
        "u793eu54e1u540d": "u5c71u7530  u8061"
    }
]
怒られポイント
一人しらべるだけでも社員全員取得している
select * from emp where hoge=foo;
↓
select * from emp;
モット怒られるために
5. WEB サービスとして公開する
BOTTLEのREADMEから
from bottle import route, run, template
@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)
run(host='localhost', port=8080)
これだけでとりあえずAPサーバとして動いてる
http://localhost:8080/hello/foo
Hello foo!
EMPWALKERを組み込むだけ
# coding:utf­8
from bottle import route, run, response
import json
import EmpWalker 
@route('/')
@route('/<search_key>/<search_value>')
def index(search_key=None, search_value=None):
    # routeで取れるのはstr
    # print type(search_key)
    result = EmpWalker.EmpWalker().get_emp(
        search_key=search_key.decode("utf­8"), 
        search_value=search_value.decode("utf­8")
    )
    # JSONを戻すと明示
    response.content_type = 'application/json'
    return json.dumps(result, indent=4)
run(host='localhost', port=8080)
こんな感じで使える
-> 全員戻る
-> 内線番号が1234なデータが戻る
http://localhost:8080/
http://localhost:8080/内線番号/1234
後はこれを社内でばらまくだけで
情シスから処分されます
LET'S TRY !

15分で情シスに怒られる方法