PyQt5の練習の続き。もう少し実用的な例として、Yahoo! 形態素解析の結果をWebを通じて取得し、テーブルに表示するアプリを作成しました。
実験環境
Win7 Pro + Python 3.4.3 + PyQt5
アプリのスクリーンショット
最上部には、ご利用ガイド - Yahoo!デベロッパーネットワークで取得したアプリケーションIDを入力します。
解析したい日本語を適当に入力してボタンを押すと、形態素解析結果がテーブルに表示されます。
コード全文
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys from PyQt5.QtWidgets import (QWidget, QGridLayout, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, QPlainTextEdit, QTableWidget, QTableWidgetItem, QPushButton, QMessageBox, QApplication) from PyQt5.QtCore import Qt import urllib.request, urllib.parse, urllib.error from bs4 import BeautifulSoup # 形態素解析した結果をリストで返す pageurl = "http://jlp.yahooapis.jp/MAService/V1/parse" def morph(sentence, appid, results="ma", filter="1|2|3|4|5|6|7|8|9|10|11|12|13"): ret = [] # 文章をURLエンコーディング sentence = urllib.parse.quote_plus(sentence.encode("utf-8")) response = "surface,reading,pos,baseform" query = "%s?appid=%s&results=%s&filter=%s&sentence=%s&response=%s" \ % (pageurl, appid, results, filter, sentence, response) res = urllib.request.urlopen(query) soup = BeautifulSoup(res.read()) # print(soup.prettify()) return [(w.surface.string, w.reading.string, w.baseform.string, w.pos.string) for w in soup.ma_result.word_list] class Example(QWidget): def __init__(self): super().__init__() self.initUI() def buttonClicked(self): # ユーザが入力した文字列を形態素解析 try: result = morph(self.text_textedit.toPlainText(), appid=self.api_lineedit.text().strip()) except urllib.error.HTTPError: reply = QMessageBox.question( self, 'Error', '形態素解析結果の取得に失敗しました。アプリケーションIDは正しくセットされていますか?', QMessageBox.Ok, QMessageBox.Ok ) return # テーブルに結果を出力 self.result_table.setRowCount( len(result) + 1 ) for i, (word, reading, baseform, pos) in enumerate(result): self.result_table.setItem(i+1, 0, QTableWidgetItem(word)) self.result_table.setItem(i+1, 1, QTableWidgetItem(reading)) self.result_table.setItem(i+1, 2, QTableWidgetItem(baseform)) self.result_table.setItem(i+1, 3, QTableWidgetItem(pos)) def initUI(self): api_label = QLabel("Yahoo! アプリケーションID") api_lineedit = QLineEdit() api_lineedit.setEchoMode(QLineEdit.Password) self.api_lineedit = api_lineedit text_label = QLabel("解析したい日本語") text_textedit = QPlainTextEdit() text_textedit.setTabChangesFocus(True) self.text_textedit = text_textedit grid = QGridLayout() grid.addWidget(api_label, 0, 0) grid.addWidget(api_lineedit, 0, 1) grid.addWidget(text_label, 1, 0) grid.addWidget(text_textedit, 1, 1) go_button = QPushButton("Go") go_button.setAutoDefault(True) # go_button.clicked.connect(self.buttonClicked) hbox1 = QHBoxLayout() hbox1.addStretch(1) hbox1.addWidget(go_button) hbox1.addStretch(1) result_label = QLabel("解析結果") result_table = QTableWidget() result_table.setColumnCount(4) result_table.setRowCount(1) result_table.setItem(0, 0, QTableWidgetItem("表記")) result_table.setItem(0, 1, QTableWidgetItem("読みがな")) result_table.setItem(0, 2, QTableWidgetItem("基本形表記")) result_table.setItem(0, 3, QTableWidgetItem("品詞")) self.result_table = result_table hbox2 = QHBoxLayout() hbox2.addWidget(result_label) hbox2.addWidget(result_table) vbox = QVBoxLayout() vbox.addLayout(grid) vbox.addLayout(hbox1) vbox.addLayout(hbox2) self.setLayout(vbox) self.setGeometry(100, 100, 700, 550) self.setWindowTitle('Yahoo! 形態素解析のデモ') self.show() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() ret = app.exec_() sys.exit(ret)
コードの解説
形態素解析結果の取得
Yahoo! APIを叩いて形態素解析を取得する部分は、PythonからYahoo!形態素解析APIを使う - 人工知能に関する断創録 を参考にしました。Python 3で動かすために、Beautiful Soup 4を使ったり、urllibライブラリの仕様変更に対応させたりしました。
ウィジェットの配置
ウィジェットの配置はQGridLayout(), QHBoxLayout(), QVBoxLayout()を使って手動で行っています。
その他細々としたこと
後ではまりそうなこと、工夫したことの羅列です。
- QTextEditではなくQPlainTextEditを使う
- QTextEditを使うと、文字列をペーストした時に修飾情報が残ってしまう。QPlainTextEditを使うと問題なし
- QTextEditでタブを押すと次のウィジェットにフォーカスが移るようにするにはsetTabChangesFocus(True)を呼ぶ
- ボタンにフォーカスを当てた状態でEnterを押すとクリックしたのと同じ動作をするにはsetAutoDefault(True)を呼ぶ
- あまりよくわかってない