回り道しながら一歩ずつ

回り道しながら一歩ずつ

プログラミングのアウトプットが中心、その他ジャンル問わず気になったことを投稿するブログ

【Python | Tkinter | Beautifulsoup】スクレイピングアプリ(最終回)

Pythonスクレイピング Top画像
PythonとBeautifulsoupを使った、Webスクレイピングツールの最終回は、Tkinterで作成したGUIに指定日を入力すると、
その日に投稿された記事を取得しExcelに入力するツールの完成形です。
前回の「Webサイトから取得した情報をExcelに自動入力する機能の実装編」をまだ見ていない方は、
先にこちらから見ていただくと分かりやすいと思います。

myroad.hatenablog.com

完成形

実際にスクレイピングツールを動かした時の動作はこんな感じです。
GUIに指定日を入力し実行ボタンをクリック、あらかじめ指定されたExcelファイルに
指定日に投稿された記事のタイトルとURLと投稿日が入力されます。

スクレイピングツールのデモ

苦労した点

GUIで入力した指定日を、メソッドに渡す処理がなかなかうまくいかなかった。
・ クラスを別ファイルに分けて作成したが、値の受け渡しがうまくいかず、別ファイルにわけるのは断念。
 

ソースコードのポイント

・Beautifulesoupで取得したhtmlから、必要な情報が含まれているタグだけを抽出し、
 さらに抽出した値から指定日に投稿された記事だけを抽出

 # ↓BeautifulsoupでHtmlソース(?)を取得
        soup = BeautifulSoup(self.html_data.content, 'html.parser')
    
        # ↓(日付けの判定用)Beautiufulsoupで取得した値からタグを指定して抽出
        output_days_tag = soup.select("tr")

        judge = 0
        # ↓trタグを取り除いてテキストだけをさらに抽出
        for i in output_days_tag:        
            if judge == 0: # 0の時は処理を実行
                for a_link in i.select('a'):
                    # jに投稿日を代入
                    j = i.contents[1].text
                    # 変数jが指定日より大きい間、ループを実行
                    if j > target_day: 
                        continue
                    # 変数jが指定日を一致したら、一致した日の記事タイトルとURLを取得
                    elif j == target_day:
                        self.target_news_title.append(i.contents[3].text)
                        self.target_news_url.append(a_link.get('href'))
                    # 上記以外になったら、変数judgeに1を代入し、処理を終了
                    else:
                        judge = 1
                        break
            else:
                break

judge = 0以降の判定の処理は、if judge == 0がTrueのあいだ処理を実行し、
次の行のfor a_link in i.select('a')内で記事投稿日と指定日を比較し、両値が一致したタイミングで、
記事のタイトルとURLを取得するような処理にしました。 もっと他にいい方法があると思うのですが、今はこれが精いっぱい( ;∀;)

ソースコード

苦労した点でも書きましたが、最初はクラスは別ファイルに記載してモジュールとしてインポートして使う想定でしたが、
何度試してもうまくいかなかったので、1ファイルにまとめる方向に妥協しました。。

#!usr/bin/python
# -*- coding: UTF-8 -*-

import tkinter
import requests
from bs4 import BeautifulSoup
from datetime import datetime
import openpyxl
import re

# 取得した情報を書き込むファイルを指定
target_file = "20200903.xlsx"
# ファイルの保存先のパス
filepath = r"C:/Users/USER/Documents/"

# ↓収集したデータをExcelに入力するクラス
class ExcelInput:
    def excelwrite(self, target_news_title, target_url, target_day ):
        
        # ↓データを入力するExcelファイルを指定してインスタンス化
        book = openpyxl.load_workbook(filepath + target_file)
        # ↓指定したExcelファイルに存在するシート名を指定してインスタンス化
        sheet = book['input_date']

        # ↓取得した情報の入力開始行を指定
        i = 6       
        # ↓セルに値が入っている場合、次の行を指定
        while sheet.cell(column=1, row=i).value != None:
            i += 1

        # ↓リストのtarget_url[]の値を指定する変数
        j = 0
        # ↓収集したニュースタイトル数だけ処理を実行するループ
        for tnt in target_news_title:
            # 1列目にニュースタイトル
            sheet.cell(column=1, row=i).value=tnt
            # 2列目にニュースURL
            sheet.cell(column=2, row=i).value=target_url[j]
            # 3列目に指定日
            sheet.cell(column=3, row=i).value=target_day
            i += 1
            j += 1

        book.save(r"C:/Users/USER/Documents/" + target_file)

# ↓Webサイトから情報を取得するクラス
class webget:

    def __init__(self):
        self.target_news_title = []
        self.target_news_url = []

    def webaccess(self, url, target_day):
        self.target_url = url # URLを格納する変数
        self.html_data = '' # サイトから取得したhtmlソースを格納する変数
        self.news_url = ''

        # ↓引数で渡されたURLにアクセスし、responseオブジェクトを取得
        self.html_data = requests.get(self.target_url)

        # ↓BeautifulsoupでHtmlソース(?)を取得
        soup = BeautifulSoup(self.html_data.content, 'html.parser')
    
        # ↓(日付けの判定用)Beautiufulsoupで取得した値からタグを指定して抽出
        output_days_tag = soup.select("tr")

        judge = 0
        # ↓trタグを取り除いてテキストだけをさらに抽出
        for i in output_days_tag:        
            if judge == 0: # 0の時は処理を実行
                for a_link in i.select('a'):
                    # jに投稿日を代入
                    j = i.contents[1].text
                    # 変数jが指定日より大きい間、ループを実行
                    if j > target_day: 
                        continue
                    # 変数jが指定日を一致したら、一致した日の記事タイトルとURLを取得
                    elif j == target_day:
                        self.target_news_title.append(i.contents[3].text)
                        self.target_news_url.append(a_link.get('href'))
                    # 上記以外になったら、変数judgeに1を代入し、処理を終了
                    else:
                        judge = 1
                        break
            else:
                break

        ei = ExcelInput()
        ei.excelwrite(self.target_news_title, self.target_news_url, target_day)

wg = webget()

def btn_click():
    # ↓指定日を取得
    target_day = dateInputEntry.get()
    wg.webaccess(r'https://www.ipa.go.jp/about/news/2020.html', target_day)

base = tkinter.Tk()

# ↓GUI画面のサイズ調整
base.geometry('300x100')

# ↓GUIのタイトル
base.title('新着情報自動化')

# ↓GUIのベースに
frame = tkinter.Frame(base)
frame.pack()

# ↓指定日ラベル
dateInputLabel = tkinter.Label(frame, foreground='#000000', text="指定日")
dateInputLabel.grid(row=2, column=0)

# 指定日を入力するフォーム
dateInputEntry = tkinter.Entry(frame,)
dateInputEntry.grid(row=2, column=1)

# ボタンを作成
execBtn = tkinter.Button(frame, text="OK", command=btn_click)
execBtn.grid(row=3, column=1)

base.mainloop()

まとめ

最終的に思ったような動作ができたのですが、ロジックを別ファイルに分けて読み込ませるという点が実現できず妥協してしまったところは、
自分でもまだまだクラス系の知識が足りていないところだと痛感しました。
関数やクラスの理解度を上げないとダメですね(>_<) これからも精進します!

【Python | Beautifulsoup】スクレイピングアプリ(第2回) 取得した情報をExcelに自動入力

Excel Auto Inputのメイン画像
Excel Auto Input

PythonとBeautifulsoupを使った、Webスクレイピングツールを作成する第2回目は、Webサイトから取得した情報をExcelに自動入力する機能の追加です。
第1回目で作成したWebから情報を取得する記事をまだ見ていない方は、先にこちらから見ていただくことで流れがつかめると思います。

myroad.hatenablog.com

最近「作業の自動化」関連の本を書店でもよく見かけるようになりました。それだけ、今注目度が高い自動化ですが、Python × Excelで検索すると、作業自動化の情報が豊富に出てくるあたり、PythonExcelは相性がいいんだなってひしひし感じますね(^^♪

作るもの

・Webサイトから、前日に投稿されたニュース記事のタイトルとURLを取得し、Excelに自動入力するツール
 

機能要件

・Webサイトから必要な情報を取得
★取得した情報をExcelに書き込み
・情報を書き込むExcelファイルを選択

今回は、機能要件の2つ目の「取得した情報をExcelに書き込み」の部分を作成していきます。
手動でExcelに情報を入力する工程をイメージすると、

1. 指定したExcelを開く
2. シートを指定する
3. 入力するセルにマウスカーソルを合わせる
4. 入力する

これらの工程を自動化するため、プログラムを組んでいきます。

プログラムを組む前に、openpyxlを少し勉強

openpyxlは、PythonExcelを操作するためのモジュールで、Excelのファイルやシート、セルなどを指定して処理を実行できます。 使い方はこんな感じです。

Excelファイルの読み込みは以下のように記述します。
 openpyxl.load_workbook(ファイル名.xlsx)
★シートを指定する場合は、インスタンス化します。
 excel_book['sheet名']
★セルの指定は、row(行)、column(列)で指定できます。
 sheet.cell(row=5, column=6)

ソースコード

Webから取得した情報をExcelに入力するクラスを追加しました。今回苦労した点は、一つ目のサイトから取得した値をExcelに入力した後、二つ目のサイトから取得した値を追加する際、すでに値があるセルに上書きされてしまったため、空のセルを見つけるまでセルをチェック処理を組むのが、かなり大変でした。。

#!usr/bin/python
# -*- coding: UTF-8 -*-

import requests
from bs4 import BeautifulSoup
from datetime import datetime
import openpyxl

target_day = "2020年9月18日"

# ↓収集したデータをExcelに入力するクラス
class ExcelInput:
    def excelwrite(self, target_news_title, target_url, target_day ):
        
        # ↓データを入力するExcelファイルを指定してインスタンス化
        book = openpyxl.load_workbook('C:/Users/USER/Desktop/20200901.xlsx')
        # ↓指定したExcelファイルに存在するシート名を指定してインスタンス化
        sheet = book['input_date']

        # ↓値を入力する行を指定する変数
        i = 6       
        # ↓値を入力するセルが空かどうか判定
        while sheet.cell(column=1, row=i).value != None:
            i += 1

        # ↓リストのtarget_url[]の値を指定する変数
        j = 0
        # ↓収集したニュースタイトル数だけ処理を実行するループ
        for tnt in target_news_title:
            sheet.cell(column=1, row=i).value=tnt
            sheet.cell(column=2, row=i).value=target_url[j]
            sheet.cell(column=3, row=i).value=target_day
            i += 1
            j += 1

        book.save('C:/Users/USER/Desktop/20200901.xlsx')

# ↓Webサイトから情報を取得するクラス
class Webget:
    def webaccess(self, url):
        self.target_url = url # URLを格納する変数
        self.html_data = '' # サイトから取得したhtmlソースを格納する変数
        self.news_url = ''

        # ↓引数で渡されたURLにアクセスし、responseオブジェクトを取得
        self.html_data = requests.get(self.target_url)

        # ↓BeautifulsoupでHtmlソース(?)を取得できる認識です
        soup = BeautifulSoup(self.html_data.content, 'html.parser')
    
        # ↓(日付けの判定用)Beautiufulsoupで取得した値からタグを指定して抽出
        output_days_tag = soup.select("th")

        # ↓タグを取り除いてテキストだけをさらに抽出
        output_days = [i.text for i in output_days_tag]

        # ↓欲しい値-タイトル(タグあり)
        news_title_tag = soup.select("td a")

        # ↓タイトル(タグ無し)
        news_title = [i.text for i in news_title_tag]

        # ↓URLの取得
        news_url = [i["href"] for i in news_title_tag]

        target_news_title = []
        target_url = []
        i = 0

        # ↓ループ処理でニュース投稿日を変数'r'に追加
        for r in output_days:

            # ↓ニュース投稿日が指定日と一致するか判定
            if r == target_day:
                # ↓一致する場合、リストにタイトルとURLを取得
                target_news_title.append(news_title[i])
                url = news_url[i]
                # ↓URLが'http'で始まっているか判定
                if url.startswith("http"):
                    target_url.append(url)
                # ↓'http'で始まらない場合は、付与
                else:
                    target_url.append("https://www.ipa.go.jp" + url)
                i += 1
            # ↓ニュース投稿日が指定日より後か判定
            elif r > target_day:
                i += 1
                continue
            else:
                break

        ei = ExcelInput()
        ei.excelwrite(target_news_title, target_url, target_day)

wg = Webget()
wg.webaccess(r'https://www.ipa.go.jp/about/news/2020.html')
wg.webaccess(r'https://www.ipa.go.jp/security/announce/alert.html')

解説

今回は業務で使うExcelを想定し、6行目から取得した値を入力したかったのでi = 6とし、for文でループして6、7、8・・・とデータを入力していくようにコードを書きました。前述でも書きましたが、一つ目のWebサイトから取得した値は、ループで順に行を変えて入力できたのですが、二つ目のWebサイトで取得した値をExcelに入力する場合、変数 iが初期値の6に戻るため、一つ目の値が上書きされる現象が発生したため、回避するために、入力する行に値があるか判定する方法として、

while sheet.cell(column=1, row=i).value != None:

とwhile文で、セルがNoneと一致するまで変数 iを1ずつ増やし、空のセルが見つかるまでループをまわしたことで、思った通りの動作を実現できました。
実際のイメージはこちらです。(GIF動画でExcel未入力 → ソース実行 → Excel入力が見れます) Excel自動入力イメージ動画

次回は、Tkinterを使って、GUI上で入力した日付の情報をスクレイピングさせてツールの完成を目指します。

【Python | Beautifulsoup】スクレイピングアプリ(第1回)Webサイトから必要な情報を取得

topimage
今回は会社で毎日行っているルーティンワークを、自動化するためのツールづくりを(全3回)に分けて、お届けします!第1回は、Pythonの外部モジュールのBeautifulsoupRequestsを使用して、Webサイトから情報を取得する(Webスクレイピング)部分の作成です。思ったように動かなかったりエラーの解消に時間がかかったりと、かなり苦労しました。。

作るもの

・Webサイトから、前日に投稿されたニュース記事のタイトルとURLを取得し、Excelに自動入力するツール
 

機能要件

★Webサイトから必要な情報を取得
・取得した情報をExcelに書き込み
・情報を書き込むExcelファイルを選択

Webスクレイピングでよく聞く「Beautifulsoup」と「Requests」とは

Webスクレイピングググると必ず検索でヒットする、BeautifulsoupRequestsですが、そもそも何ができるのかちゃんと理解できていなかったので、改めて調べると以下のような認識、、ですが合ってますかね(;'∀')

Beautifulsoup・・HTMLやXMLからデータと抽出するためのPythonパッケージ
使用例) Requests・・HTTP通信でリクエストを送りレスポンスを受け取れるライブラリ

Beautifulsoupの使い方

Beautifulsoupは、サードパーティ製のライブラリですので、使用する場合はインポートする必要があります。

from bs4 import BeautifulSoup
これで使用できるようになりましたが、インスタンス化するときに`BeautifulSoup`と入力するのは長くて面倒ですし、入力ミスを引き起こす恐れがありますので、from bs4 import BeautifulSoup as bsなど、別名をつけるのが一般的です。

Requestsの使い方

Requestsは、Webサイトのテキスト情報の取得などに使うライブラリです。もちろん、こちらもインポートが必要です。

import Requests
Requestsは`get`や`post`といったメソッドがあり、活用できる幅が豊富です。自分はまだ、HTMLの取得くらいしか思いつきませんが…

ソースコード

まずは必要なモジュールのインポートとWebサイトから情報を取得するクラスを作成しました。動きはしますが、きっと無駄の多いソースコードになっていると思うので、今後改善していくつもりです。

#!usr/bin/python
# -*- coding: UTF-8 -*-

import requests
from bs4 import BeautifulSoup
from datetime import datetime
import openpyxl

target_day = "2020年7月15日"

# ↓Webサイトから情報を取得するクラス
class Webget:
    def __init__(self, url):
        self.target_url = url # URLを格納する変数
        self.html_data = '' # サイトから取得したhtmlソースを格納する変数
        self.news_url = ''

    # ↓指定サイトにアクセスして情報を取得する関数
    def webaccess(self):

        # ↓引数で渡されたURLにアクセスし、responseオブジェクトを取得
        self.html_data = requests.get(self.target_url)

        # ↓BeautifulsoupでHtmlソース(?)を取得できる認識です
        soup = BeautifulSoup(self.html_data.content, 'html.parser')

        # ↓(日付けの判定用)Beautiufulsoupで取得した値からタグを指定して抽出
        output_days_tag = soup.select("th")

        # ↓タグを取り除いてテキストだけをさらに抽出
        output_days = [i.text for i in output_days_tag]

        # ↓欲しい値-タイトル(タグあり)
        news_title_tag = soup.select("td a")

        # ↓タイトル(タグ無し)
        news_title = [i.text for i in news_title_tag]

        # ↓URLの取得
        news_url = [i["href"] for i in news_title_tag]

        target_news_title = []
        target_url = []
        i = 0

        # ↓ループ処理でニュース投稿日を変数'r'に追加
        for r in output_days:

            # ↓ニュース投稿日が指定日と一致するか判定
            if r == target_day:
                # ↓一致する場合、リストにタイトルとURLを取得
                target_news_title.append(news_title[i])
                url = news_url[i]
                # ↓URLが'http'で始まっているか判定
                if url.startswith("http"):
                    target_url.append(url)
                # ↓'http'で始ま禎ない場合は、付与する
                else:
                    target_url.append("https://www.ipa.go.jp" + url)
                i += 1
            # ↓ニュース投稿日が指定日より後か判定
            elif r > target_day:
                i += 1
                continue
            else:
                break

        for s in range(len(target_news_title)):
            print("タイトル:" + target_news_title[s] + " " + "URL:" + target_url[s])

wg = Webget(r'https://www.ipa.go.jp/security/announce/alert.html')
wg.webaccess()

実行結果がこちらです。

実行結果イメージ

何とか動いたんで、本日はここまでとします。

【Python】Tkinterで足す・引く・掛ける・割るを自由に選択できる計算機を作ってみた | プログラミング

Tkinterで足す・引く・掛ける・割るを選択できる計算機を作ってみたのメインイメージ
前回は、TkinterのEntryとButtonを使って、ボタンをクリックするとフォームに入力した数値を足し算し、結果フォームに答えが出力されるツールを作成しました。ずいぶん時間はかかりましたが、思ったことが形にできて満足してます。

myroad.hatenablog.com

今回は前回作成したツールの改良版で、ラジオボタンを使って、足す引く掛ける割るを選択できるようにするツールを作ってみました。

Tkinterラジオボタンを設置

Tkinterラジオボタンを追加する方法も、他のウィジェットと同様で以下のようにインスタンス化を行う必要があります。

radiobtn = tkinter.Radiobutton

今回作成する計算機が、足す引く掛ける割るラジオボタンで選択して計算する計算機になるため、GUIに4つのラジオボタンを設置する必要があります。完成イメージはこんな感じです。
入力式計算ツール完成形
1つ1つボタンを設置すると、同じようなコードを4つ書く必要があるので手間だと思っていたのですが、参考にさせていただいたブログが、For文を使ってラジオボタンを設置していたので、コードの省略にもなるし便利だと思って同じ方法をまねてみたのですが、どのような仕組みになっているのか解読するのに時間がかかりました。
For文の抜粋が以下のような感じです。

# ↓タプルに格納された演算子の数分for文を回してラジオボタンを作る
for i in range(len(calc)):
    rdbtn = tkinter.Radiobutton(master=root, value = i, variable=var, text=calc_name[i], command=Change_stats)
    rdbtn.place(x=30 + (i*60), y=20)

len()は設定された引数の値を取得する関数で、さらにfor i in rangeで取得した値分、for文を実行します。ラジオボタンインスタンスのカッコ内のvalue=ifor i in rangeiで、for文が実行されるたびにcalcから取得した値を追加し、text=calc_name[i]iも同様の値を追加して、ラジオボタンの名称を表示させています。

ラジオボタンの変更に合わせて表示している演算子を変更

選択されたラジオボタンの値(varに格納されている)を取得し、if文をつかってどの演算子と一致するかを判定して、一致した演算子を表示するようにしました。

# ↓ラジオボタン変更時に実行される関数
def Change_stats():
    checked = var.get()
    if (checked == 0):
        # ↓ラジオボタンの状態に応じて演算子を変えるIF文
        plus_label = tkinter.Label(master=root, text='+', font=20)
        plus_label.place(x=135, y=70)
    elif (checked == 1):
        # ↓ラジオボタンの状態に応じて演算子を変えるIF文
        plus_label = tkinter.Label(master=root, text='-', font=20)
        plus_label.place(x=135, y=70)
    elif (checked == 2):
        # ↓ラジオボタンの状態に応じて演算子を変えるIF文
        plus_label = tkinter.Label(master=root, text='×', font=20)
        plus_label.place(x=135, y=70)
    else:
        # ↓ラジオボタンの状態に応じて演算子を変えるIF文
        plus_label = tkinter.Label(master=root, text='÷', font=20)
        plus_label.place(x=135, y=70)

ここの処理は、もう少しコードを減らせそうですが今の自分の力量ではごれが限界ですね。。

計算処理を実施する関数の作成

前回の処理を使って、ラジオボタンに設定された演算子に連動し、足す引くなどを実行させるのにだいぶ苦労しました。
というのも、もともとeval()という関数の知らなかったため、文字列型の計算式をちゃんと計算できるようにするには、どうすればいいのか全く見当がつかなかったので、手あたり次第に検索して、やっとeval()の存在をしりました。 参考にさせていただいた、このブログには本当に感謝です。
pythonで文字列を式として計算するeval()関数 - Qiita

# ↓ボタンクリック時に実行される関数
def Calculation():
    enzanshi = var.get()
    val_1 = str(num_area_1.get())
    val_2 = str(num_area_2.get())
    # ↓文字列状態の式を実行
    answer = eval(val_1 + calc[enzanshi] + val_2)
    answer_ent.delete(0, tkinter.END)
    answer_ent.insert(0, answer)

以下が今回のソースコードの全文です。

#! /usr/bin/env python
import tkinter

# ↓ボタンクリック時に実行される関数
def Calculation():
    enzanshi = var.get()
    val_1 = str(num_area_1.get())
    val_2 = str(num_area_2.get())
    # ↓文字列状態の式を実行
    answer = eval(val_1 + calc[enzanshi] + val_2)
    answer_ent.delete(0, tkinter.END)
    answer_ent.insert(0, answer)

# ↓ラジオボタン変更時に実行される関数
def Change_stats():
    checked = var.get()
    if (checked == 0):
        # ↓ラジオボタンの状態に応じて演算子を変えるIF文
        plus_label = tkinter.Label(master=root, text='+', font=20)
        plus_label.place(x=135, y=70)
    elif (checked == 1):
        # ↓ラジオボタンの状態に応じて演算子を変えるIF文
        plus_label = tkinter.Label(master=root, text='-', font=20)
        plus_label.place(x=135, y=70)
    elif (checked == 2):
        # ↓ラジオボタンの状態に応じて演算子を変えるIF文
        plus_label = tkinter.Label(master=root, text='×', font=20)
        plus_label.place(x=135, y=70)
    else:
        # ↓ラジオボタンの状態に応じて演算子を変えるIF文
        plus_label = tkinter.Label(master=root, text='÷', font=20)
        plus_label.place(x=135, y=70)
    

# ↓ベースとなるGUIの作成
root = tkinter.Tk()

# ↓GUIのタイトル
root.title(u'Pythonで足し算')
# ↓GUIのサイズ
root.geometry('320x300')

# ↓タプル型に四則演算子を格納
calc = ('+', '-', '*', '/')

# ↓タプル型に四則演算子の名称を格納
calc_name = ('足す', '引く', '掛ける', '割る')

# ↓ラジオボタンの初期状態を設定
var = tkinter.IntVar()
var.set(0)

# ↓ラジオボタンの状態を取得
var.get()

# ↓タプルに格納された演算子の数分for文を回してラジオボタンを作る
for i in range(len(calc)):
    rdbtn = tkinter.Radiobutton(master=root, value = i, variable=var, text=calc_name[i], command=Change_stats)
    rdbtn.place(x=30 + (i*60), y=20)

# ↓テキストエリア作成,計算問題を入力する
num_area_1 = tkinter.Entry(master=root, width=5, font=20)
num_area_1.place(x=60, y=70)

# ↓テキストエリア作成,計算問題を入力する
num_area_2 = tkinter.Entry(master=root, width=5, font=20)
num_area_2.place(x=180, y=70)

# ↓ボタン作成,クリックで計算処理を実行する
answer_btn = tkinter.Button(master=root, text='Answer', command=Calculation)
answer_btn.place(x=240, y=70)

# ↓計算結果が表示されるラベル
answer_ent = tkinter.Entry(master=root, width=15, font=20)
answer_ent.place(x=60, y=150)

# ↓最初に表示する演算子ラベル
Change_stats()

root.mainloop()

今回は、if文やfor文といった条件分岐など覚えたての知識と、evalという新たな関数をフルに活用して思った通りの計算機を作成することができました。次回、どういったものを作るか、まだ検討中ですが、少しずつボリュームのあるソースコードが掛けるようになり、できることも増えてきたので楽しくなってきました。このモチベーションを維持したまま、勉強がんばっていきます。では、本日はここまで。

【Python】Tkinterで入力式計算ツールを作ってみた | プログラミング

Tkinterで入力式計算ツールを作ってみたのイメージ画像
前回は、Tkinterで作ったウィンドウに計算問題と式を表示するプログラムを作成しましたが、プログラム内で入力した式と答えが表示されるだけという、あまりにも味気ないものになってしまいました。
myroad.hatenablog.com

そこで、今回はテキストエリアに数字を入力して、ボタンをクリックすると答えが表示されるという前回から一気に進化した計算ツールの作成に挑戦しました。作り終えるまでにかなりの時間と労力を費やしましたが、何とか自分がやりたいことが形になったので達成感は半端ないですね。

TkinterのEntryで入力した値の取得が難しい

まず作成した完成形ツールがこちらです。 入力式計算ツール完成形
前回は、TkinterのLabelというウィジェットGUIのパーツ)使って、数式と答えを表示させましたが、今回は足し算する数値を入力するフォームと結果が表示されるフォーム、結果を表示するボタンを作成するウィジェットを使用しました。

Entry・・入力フォーム、フォントサイズやフォームの長さなどを指定可能
使用例)tkinter.Entry(width=任意の数値,font=任意の数字)
Button・・ボタン、ボタン上に表示する文字列やボタンサイズ、クリック時に実行する関数などを指定可能
使用例)tkinter.Button(text='表示したい文字列'width=任意の数値)

また、今回のツールを作成するにあたって必要となった知識が関数の知識です。関数は書籍でもだいぶ後の方に出てくる内容だったので、先に学習すべき部分を飛ばして関数を勉強しました。関数を勉強した率直な感想は、『いろいろな処理をまとめることができ、使いたいときに呼び出して何度でも使える汎用性の高さが素晴らしい!だけど難しい…』です。関数は書き方が以下のように、書き方が決まっています。

def xxxx:   #(xxxxは任意の名称)のあとは必ず「:」コロンを入力
  print(xxx)  #コロンの後は、コードの前にスペース(半角4つが推奨)を挿入

使用するときは、

xxxx()   #xxxxのあとに(カッコ)を入力

開発に入る前の学習でだいぶ時間を費やしましたが、何とか書ききったコードがこちらです。

#! /usr/bin/env python
import tkinter

# ↓ボタンクリック時に実行される関数
def Calculation():
    val_1 = int(num_area_1.get())
    val_2 = int(num_area_2.get())
    answer = val_1 + val_2
    answer_ent.delete(0, tkinter.END)
    answer_ent.insert(0, answer)

# ↓ベースとなるGUIの作成
root = tkinter.Tk()

# ↓GUIのタイトル
root.title(u'Pythonで足し算')
# ↓GUIのサイズ
root.geometry('320x100')

# ↓GUI上にプラス演算子を表示するラベル
plus_label = tkinter.Label(master=root, text='+', font=20)
plus_label.place(x=135, y=20)

# ↓テキストエリア作成,計算問題を入力する
num_area_1 = tkinter.Entry(master=root, width=5, font=20)
num_area_1.place(x=60, y=20)

# ↓テキストエリア作成,計算問題を入力する
num_area_2 = tkinter.Entry(master=root, width=5, font=20)
num_area_2.place(x=180, y=20)

# ↓ボタン作成,クリックで計算処理を実行する
answer_btn = tkinter.Button(master=root, text='Answer', command=Calculation)
answer_btn.place(x=240, y=20)

# ↓計算結果が表示されるラベル
answer_ent = tkinter.Entry(master=root, width=5, font=20)
answer_ent.place(x=60, y=60)
root.mainloop()

ツールを完成させるにあたって一番時間がかかったのが、入力した数値を関数に渡すところです。 num_area_1 = tkinter.Entry(master=root, width=5, font=20)が一つ目の数値が入力されるフォームですが、num_area_1変数に数値が入力されるので、関数内でnum_area_1を使用したら格納された状態だと思ったのですが、実行してもエラーが表示されるし、どこが間違っているのかさっぱりでした。何度見ても分からないことは、あまり悩みすぎず検索することが解決の早道ですね。Tkinter Entry 値 取得で検索すると、あっさり答えが分かりました。あんなに悩んでいた時間はなんだったのか…
Entryから値を取得するには、 Entry名称 + .get()と記述しないといけないみたいですね。

num_area_1.get()

これで、ようやく前に進むことができました。
あと、今回はウィジェットの位置指定にplaceを使用しました。packだと思うような位置に配置できなかったので…placeはウィンドウの左上を起点に(x , y)で指定できるので、個人的に調整がしやすかったです。フォームとフォームの間に「+」をラベルで表示することも簡単でした。

まとめ

今回初めて関数を使用して、本当に便利なものだと感じたので、使いこなせるようにもっと勉強頑張っていきたいですね。
次は、今回作成したプログラムを発展させて、もう少し色々な計算ができるツールにしたいと思います。

【Python】Tkinterを用いて、数字の計算結果をGUIで表示してみた | プログラミング

Pythonで数字計算のイメージ画像
前回は、自分が購入した書籍がインタラクティブシェルを使って学習するスタイルだったので、実際のアプリ開発のようにGUIを使って学習したいがために、 ググりまくって何とかTkinterで、文字列を表示させたところで終わりました。
前回のブログはこちら

myroad.hatenablog.com

Pythonを使った計算

今日からいよいよ、購入した書籍「確かな力が身につくPython「超」入門」を使った学習を進めていきます。まずはPythonを使って数字の足し算と引き算をおこないます。Pythonでは、「 2 + 3 」と記入すると、それを「5」という風に解釈してくれるため、結果は「5」が表示されます。

記入例

print(2 + 3) #「2 + 3」の部分が自動的に「5」と解釈されるため
5      #「5」が表示される

この問題をGUIで表示するためにまずは、Visual Studio Code(以下,VSCode)を使って、前回のブログで作成したTkinterのコードを活用して、
以下のようなコードを書きました。

#! /usr/bin/env python
import tkinter

# ↓ベースとなるGUIの作成
root = tkinter.Tk()
# ↓GUIのタイトル,今回はここに数式を表示
root.title(u'2 + 3は?')

# ↓ラベル作成,text=のところに計算式を入力
la = tkinter.Label(None, text=2+3, font=('Times', '20'))
la.pack()
root.mainloop()

前回と違うところを説明していくと、 root = tkinter.Tk()はインポートしたTkinterインスタンス(?)を作成しています。

インスタンスとは(自分解釈)・・クラスという設計図から製造した物(オブジェクト) のこと(抽象的ですみません…)

root.title(u'2 + 3は?')は、表示されるGUIウィンドウのタイトルです。今回は、タイトルに計算する問題を表示しました。 ラベルで表示するtextには、2 + 3と式を直接入力しています。前回のブログでは、'Hello World'と文字をシングルクォーテーションで括っていましたが、数字の場合はとくに括らずにそのまま書きます。 このコードの実行結果はこうなります。
コードの実行結果
無事に、タイトルに「 2 + 3は?」と、表示エリアに答えの「5」が表示されました。 続いて、引き算もやってみます。

#! /usr/bin/env python
import tkinter

# ↓ベースとなるGUIの作成
root = tkinter.Tk()
# ↓GUIのタイトル,今回はここに文字列で表示
root.title(u'Pythonで引き算')

# ↓ラベル作成,text=のところに計算式(文字列)を入力
la_1 = tkinter.Label(None, text='5 - 2は?', font=('Times', '20'))
la_1.pack()

# ↓ラベル作成,text=のところに計算式(数字)を入力
la_2 = tkinter.Label(None, text=5-2, font=('Times', '20'))
la_2.pack()
root.mainloop()

足し算の時と違うのは、タイトルには「Pythonで引き算」と文字列をいれて、 引き算の式と答えをクライアント領域に表示するように、ラベルを2つにしました。
実行結果がこちらです。
pythonで5-2の実行結果画像
引き算も無事に表示されました。プログラミングは、エラーが続くと気持ちも折れますが、思った通りの動作をしてくれると、やっぱり楽しいしうれしいですね。

【Python】GUIで動くものを作って勉強するために、Tkinterを勉強 | プログラミング

blog001のトップイメージ 前回は、Pythonの学習に必要な環境の準備で終わってしまいましたが、いよいよPythonプログラミングの学習に入っていきます。アラフォーサラリーマンにとって、テキストを使った勉強は久しぶりなので、今非常にワクワクしてます。
前回のブログはこちら

myroad.hatenablog.com

実際にプログラミングの学習を行っていくにあたって、自分としてはコンソール上での結果表示だけでは、あまりプログラミングをしている感じがしないため、 GUIで動くものを作って勉強したい!…という、初心者にはおこがましい事を思っているのですが、やる前から諦めるのも違うと思うので、少し調べて無理ならまた考えるということで、PythonGUIアプリが作れるか調べてみました。

まずはPython言語について

Python学習用に購入した書籍「確かな力が身につくPython「超」入門」では、いろいろなプログラミング言語があるなかで、Pythonは最初に学習するのもってこいの言語と書いてあります。その理由として、プログラムが読みやすいとのこと。
何故かというと、Pythonは他のプログラミング言語と違って、コーディング規則がしっかり定められているからだそうです。私はHTMLやCSSを多少かじった程度で、プログラミング言語はほとんど触れてこなかったので、比較しようが無いのですが勉強していくうえで、コーディング規則を覚えれば、プログラムが動いてくれるというのは、初心者にとってはありがたい印象を受けますね。

記入例

def xxxxx:
  print('xxxx') ←関数などの場合、先頭にタブまたは4文字分の半角スペースを入れる

PythonGUIアプリ作成

Pythonでは、さまざまなライブラリ(いろいろな機能が詰められた機能拡張と解釈してます。。)をインポートしながら開発をおこなっていくのですが、GUIアプリを作成するために必要なライブラリを調べていくと、主に3つあるみたいです。

Tkinter・・Pythonに標準で搭載されているため、特にインストールの必要がなく、
     一番最初に扱うのにもってこいのライブラリ。

Kivy・・インストールが必要。日本ではそこまで知名度はたかくなく、レイアウト
    調整にKv Languageという独自言語を使う必要がる。
    ちょっとハードル高い

wxPython・・インストールが必要。GUIライブラリのなかでも、メジャーらしい。
      wxWidgetsPython版?

今回は主目的がPythonの基礎学習であるため、GUIの方はとりあえずベースができればいいかなと思うので、インストール不要で情報も豊富にあるTkinterを採用して、学習を始めていきます。 メイン学習に入る前に無謀とも言えますが、やっぱり楽しみながら学習したいので、何事もチャレンジ精神で頑張ります。

まずはPythonTkinterGUIを表示

では、さっそくTkinterGUI画面を表示させてみます。表示方法は、Visual Studio Code(以下VSCode)でPythonファイルを作成し、以下のコードを打ち込んでVSCodeで実行します。

# ↓下の一文はおまじない・・らしい、効果は分かりません。。
#! /usr/bin/env python

# ↓今回のアプリに必要なライブラリのインポート
# as tkはtkinterを略称tkと設定して使用するための記述
import tkinter as tk

# ↓ラベル作成 カッコ内は(親?の指定,text='表示させたい文字', fontの指定)
la = tk.Label(None, text='Hello World', font=('Times', '20'))
# ↓ラベル内に設置する記述
la.pack()
# ↓GUIを表示させるために必要
la.mainloop()

# ちなみに#の行はコメントとして扱われるためプルグラムに影響しない

実行結果がこちら。
TkinterのGUI表示イメージ
余白調整などをしていないので、文字がきつきつの状態ですが、何とかGUIが表示できました。
実はこれを表示するまでに、いろいろと試行錯誤しましたが、いろいろなサイトやブログの力を借りて何とか実現できました。
きりがいいので、本日はここまでです。
次回は本当の本当に、Pythonの学習に入っていきたいと思います。