【python】ウェブスクレイピングで社内ツールを作る

2015年6月23日

蛇使い見習い社員24号です。

エ○ソンさんのプリンターをリース契約しています。
リース契約している関係上、枚数に制限があります。
この枚数を毎朝お知らせしてくるようなツールが欲しくなりましたので
pythonでサクッと作ってみたいと思います。

概要としては
・毎朝○時にpythonシェルを実行する。(cronに実行してもらう)
・プリンターの枚数を取得する。
・メールする。

ここで問題なのがプリンターの枚数ですが、
エ○ソンさんのリースプリンターは「HTTPS://IPアドレス」で
枚数が閲覧出来るようです。

そうなると後は、印刷枚数の抽出となり、今回の本題ウェブスクレイピングの出番です。

そもそもウェブスクレイピングとは・・・

ウェブスクレイピング(Web scraping)とは、ウェブサイトから情報を抽出するコンピュータソフトウェア技術のこと。
ウェブスクレイピング – Wikipedia

つまり、ウェブサイトから必要な情報を抽出する技術です。

今回利用したウェブスクレイピングモジュールは、PyQueryです。
jQueryをもじったような名前ですが、jQuery風に利用できる便利なモジュールです。
※利用する場合はpipかeasy_installして下さい。

PyQueryの簡単な使い方。

<html>
  <body>
    <div>犬</div>
    <div>猫</div>
    <div>ハムスター</div>
  </body>
<html>

なんてHTMLの猫を取りたかったら

from pyquery import PyQuery as pq
pq(response).find('div').eq(1).text()

といった書き方で抽出出来ます。

さて、今回ウェブスクレイピングするタグ構成は

<div class="wrap">
    <div class="header-main">情報確認メンテナンス情報</div>
    <div class="section">
      <dl class="values">
      </dl>
      <fieldset class="group">
          略・・・
      </fieldset>
      <fieldset class="group">
          略・・・
      </fieldset>
      <fieldset class="group">
        <legend>機能別印刷ページ数</legend>
        <dl class="values">
          <dt class="key">
            <span class="key">モノクロコピー:</span>
          </dt>
          <dd class="value clearfix">
            <div class="preserve-white-space">1</div>
          </dd>
          <dt class="key">
            <span class="key">カラーコピー:</span>
          </dt>
          <dd class="value clearfix">
            <div class="preserve-white-space">2</div>
          </dd>
          <dt class="key">
            <span class="key">モノクロファクス:</span>
          </dt>
          <dd class="value clearfix">
            <div class="preserve-white-space">3</div>
          </dd>
          <dt class="key">
            <span class="key">カラーファクス:</span>
          </dt>
          <dd class="value clearfix">
            <div class="preserve-white-space">4</div>
          </dd>
          長いので略・・・
        </dl>
      </fieldset>
      <fieldset class="group">
          略・・・
      </fieldset>
    </div>
    略・・・
  </div>

必要なのは
「fieldset3番目」
「dt(タイトル)、dd(印刷枚数)」
となってるようです。

これをモノクロ、カラーで分けて取得すると以下の様なソースになります。

monoqlo = 0
color = 0

# リクエスト
r = requests.get("https://192.168.xx.xx/xxxxxxx", verify=False)
# レスポンス取得
requestEncode = r.encoding
request = r.text.encode(requestEncode)
# DOMから印刷枚数取得
fieldset = pq(request).find('fieldset').eq(2)
dt = fieldset.find('dt')
dd = fieldset.find('dd')
n = min(len(dt), len(dd))
for i in range(n):
    # メール内容
    title = pq(dt[i]).text()
    count = pq(dd[i]).text()
    # 総数カウント
    if u'モノクロ' in title:
        monoqlo += int(count)
    elif u'カラー' in title:
        color += int(count)

・リクエストを送る
・レスポンスをエンコードゴニョゴニョ
・レスポンスのタグからfieldset3番目セレクター指定
・dt、ddセレクターをeachしてタイトルと枚数取得

ちなみにHTTPライブラリはrequestsというライブラリを利用しています。

ここまで出来れば後はメールを送るだけ。
以下はウェブスクレイピングで印刷枚数抽出後、メールを送るまでのサンプルです。

# -*- coding: utf-8 -*-
# インポート
import requests
from pyquery import PyQuery as pq
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email import charset
# メール送信用変数
monoqlo = 0
color = 0
mailBody = ""
# リクエスト
r = requests.get("https://192.168.xxx.xxx/xx/xx/xx/xx/TOP", verify=False)
# レスポンス取得
requestEncode = r.encoding
request = r.text.encode(requestEncode)
# DOMから印刷枚数取得
fieldset = pq(request).find('fieldset').eq(2)
dt = fieldset.find('dt')
dd = fieldset.find('dd')
n = min(len(dt), len(dd))
for i in range(n):
    # メール内容
    title = pq(dt[i]).text()
    count = pq(dd[i]).text()
    mailBody += title + count + "\n"
    # 総数カウント
    if u'モノクロ' in title:
        monoqlo += int(count)
    elif u'カラー' in title:
        color += int(count)
mailBody += u"----------------------------\n"
mailBody += u"モノクロ総数:" + str(monoqlo) + "/1000" + "\n"
mailBody += u"カラー総数:" + str(color) + "/500\n"
# メール送信
con = smtplib.SMTP('localhost')
con.set_debuglevel(True)
charset.add_charset('utf-8', charset.SHORTEST, None, 'utf-8')
cset = 'utf-8'
message = MIMEText(mailBody, 'plain', cset)
message['Subject'] = Header(u'プリンター使用枚数のお知らせ', cset)
message['From'] = 'info@exsample.com'
message['To'] = 'your@exsample.com'
con.sendmail('info@exsample.com', ['your@exsample.com'],
message.as_string())
con.close()

※メール送信をiso-2022-jpにしたかったのですがヘビさんに噛まれましたので今後の課題と言うことで。

【感想】
多くのウェブスクレイピングモジュールはjQuery風に利用できますので
すごく使い勝手良いです。
ウェブスクレイピングはアイディア次第でいろいろ活用出来るはずなので
是非利用していきたい技術です。