地域(都道府県)を指定して、ガソリンの価格を返却してくれるPython関数を作ってみました。

BeautifulSoupで都道府県別のガソリンの平均価格を掲載しているサイトにアクセスして、価格を返却します。

プログラムの概要

フローチャート図

フローチャート図

緑で囲ってある部分は関数なので、外部から呼び出しできます。その場合、地域とガソリンの種類を引数とします。

ソースコード

#! /usr/bin/python3
import re,requests,bs4,sys,datetime

GASOLINE_LINK   = "https://e-nenpi.com/gs/prefavg"

DEFAULT_AREA    = "東京都"
DEFAULT_TYPE    = "レギュラー"

AREA_LIST       = ["和歌山県","徳島県","熊本県","佐賀県","千葉県","奈良県","香川県","神奈川県","東京都","埼玉県","茨城県","京都府","岐阜県","愛知県","三重県","愛媛県","新潟県","群馬県","大阪府","岩手県","滋賀県","宮崎県","長崎県","岡山県","栃木県","福井県","青森県","兵庫県","石川県","宮城県","静岡県","広島県","富山県","山口県","福岡県","島根県","山形県","山梨県","福島県","鹿児島県","大分県","北海道","長野県","鳥取県","高知県","秋田県","沖縄県",]
TYPE_LIST       = ["レギュラー","ハイオク","軽油"]
TODAY           = datetime.datetime.now().strftime("%Y年%m月%d日")

TIMEOUT         = 10
HEADERS         = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0'}

#地域とガソリンの種類を指定して価格を返却する関数
def gasoline_cost(oil_area,oil_type):

    cost = ""

    try:
        site_data = requests.get(GASOLINE_LINK , timeout=TIMEOUT , headers=HEADERS)
        site_data.raise_for_status()
    except Exception as e:
        print("ERROR_DOWNLOAD:{}".format(e))
        return False

    else:
        site_data_soup  = bs4.BeautifulSoup(site_data.content,"lxml")
        site_data_table = site_data_soup.select('table')

        site_data_td_price      = site_data_soup.select('table > tbody > tr > .price')
        site_data_td_area       = site_data_soup.select('table > tbody > tr > .pref')

        price_list  = []
        area_list   = []

        for i in range(len(site_data_td_price)):
            price   = site_data_td_price[i].getText()
            price_list.append(price)

        for i in range(len(site_data_td_area)):
            area    = site_data_td_area[i].getText()
            area_list.append(area)

        regular_dic     = {}
        high_ok_dic     = {}
        light_oil_dic   = {}

        if len(price_list) == len(area_list):

            for i in range(len(price_list)):
                if i%3 == 0:
                    regular_dic[area_list[i]]   = price_list[i]
                if i%3 == 1:
                    high_ok_dic[area_list[i]]   = price_list[i]
                if i%3 == 2:
                    light_oil_dic[area_list[i]] = price_list[i]

        if oil_type == "レギュラー":
            cost = str(regular_dic.get(oil_area,"NULL"))
        elif oil_type == "ハイオク":
            cost = str(high_ok_dic.get(oil_area,"NULL"))
        elif oil_type == "軽油":
            cost = str(light_oil_dic.get(oil_area,"NULL"))
        else:
            return False

        print("\n本日({}) の {} での {} の平均価格は {} です。\n".format(TODAY,oil_area,oil_type,cost))

    return cost

if __name__ == "__main__":
    try:
        while True:

            oil_area    = input("地域を入力してください。(デフォルト:{}) ".format(DEFAULT_AREA))
            oil_type    = input("ガソリンの種類を入力してください。(1:レギュラー,2:ハイオク,3:軽油)(デフォルト:{}) ".format(DEFAULT_TYPE))

            if oil_area == "" or oil_area not in AREA_LIST:
                oil_area = DEFAULT_AREA

            if oil_type == "1" or oil_type == "1":
                oil_type = "レギュラー"
            elif oil_type == "2" or oil_type == "2":
                oil_type = "ハイオク"
            elif oil_type == "3" or oil_type == "3":
                oil_type = "軽油"
            elif oil_type == "" or oil_type not in TYPE_LIST:
                oil_type = DEFAULT_TYPE

            gasoline_cost(oil_area,oil_type)

    except KeyboardInterrupt:
        print("\nprogram was ended.\n")
        sys.exit()

このプログラムの解説

起動後、地域(都道府県)とガソリンの種類を指定します。(例えば、東京のハイオクの価格を知りたい場合は、「東京都」「ハイオク」と入力する)

指定された地域のガソリンの平均価格を取得し、返却します。

工夫したところ

テーブルの処理について

今回スクレイピングしたサイトは、レギュラーガソリン、ハイオクガソリン、軽油の平均価格の要素の全てが同じクラス名のテーブルになっていました。(全てクラス名が.priceになっている)

そこで、一旦、レギュラーとハイオクと軽油をsite_data_td_priceにリストとして代入させ、3で割ってあまりが0をレギュラーガソリン、あまりが1をハイオクガソリン、あまりが2の場合は軽油とすることで振り分けています。

二次元リストではなく、辞書型を採用した

ガソリンの価格と地域の組み合わせをするためには、二次元リストと辞書型の二種類があります。

二次元リストでも問題なく利用できますが、検索のしやすさを考慮して辞書型を採用しました。

動作環境

  • Python3
  • BeautifulSoup4、requests、lxmlがインストール済み

実際に動かしてみる

実際に動かしてみます。北海道の軽油の平均価格を知りたい場合は、「北海道」「軽油」と入力していきます。

すると、こんなふうに価格が表示されました。

北海道の軽油の平均価格を表示

何も入力しない場合や、間違った値を入力した場合はデフォルトの値が代入されます。

試しに、デフォルトで指定されている「広島県」「レギュラー」をEnterで表示させてみます。

デフォルトのガソリン価格はEnterキーを押すだけ

デフォルト値が入力され、価格が表示されました。

メリットとデメリット

メリット

  • すぐに該当地域のガソリンの平均価格を調べることができる
  • デフォルトの場合はEnterキーを押していくだけ
  • 無限ループしているので、連続で調査できる。

whileで無限ループしているので、地域とガソリン価格を連続で調査できます。

プログラムの冒頭の定数にデフォルトの地域とガソリンの種類を指定しておけば、起動した後はEnterキーを押すだけで済みます。

デメリット

  • サイトのアクセスと価格の返却が分離されていない

ちょっと改造すればすぐに済むことですが、価格情報を掲載しているサイトへアクセスする機能と価格の返却をする機能が分離されていません。

別の地域のガソリンの価格まで表示したい場合は、再度サイトにアクセスする必要があります。

何度もサイトにアクセスすることになるので、このあたりはもう少し改良の余地がありそうです。

結論

後は、cronで自動的に価格を取得して、CSVにでも格納できるようになれば十分でしょう。

主な用途としては、交通費計算、取得した平均価格と地元のガソリンスタンドでの実売価格との比較などが考えられます。

技術的にはBeautifulSoupとrequestsモジュールを使用して、ガソリン価格と地域情報を取得しているだけです。スクレイピングする対象がAmazonやTwitterなどの動的サイトの場合は、Seleniumを使わないと難しいでしょう。

関連記事

Google検索で表示されるサイトからテキスト情報だけをシェルにハイライト表示する

【内部リンク】Pythonでテキストを抽出表示するウェブスクレイピングを更に改良してみた【ハイライト機能付き】

仕組みはほとんど変わりません。ただ、こちらは検索ワードを正規表現で置換処理をして、ハイライト表示しています。

CRON+スクレイピング

【内部リンク】cronで動作させ、テキストを連続で抽出して保存するウェブスクレイピングをPythonで作ってみた

crontabで動くので、検索ワードを入力した後、放ったらかしにしておいても自動的に処理をしてくれます。

うっとうしいウェブ広告やトラッカーなどが除外され、テキストファイルで情報が閲覧できるのでとても快適です。