PythonとPyQt5で簡易ブラウザを作ってみた話

# はじめに
開発にかぎらず、働いていると環境に関して色々と制限を受ける。所定の手続きを取れば必要なツールをインストールできるが、例外なのがWebブラウザ。いずれのOSもデフォルトとなるWebブラウザを最初から積んでおり、それ以外のブラウザを新たにインストールするとなると（事務的に）かなりめんどくさい。

Webブラウザをインストールすることはできないが、ブラウザを作ることは禁止されていない。というわけで、自分が使いやすいブラウザを作ることにした。（今年の年越しハッカソン）

# 前提と環境
- OSを選ばず動かせる
- ブラウザ以外の用途としても使えるツールを使う
- 各Webページの情報が参照できれば良い（きれいなレンダリングとかいらない）

以上より、自分が普段使っているPythonと、過去かじったことのあるQt（今回はPyQt5）を使うことにした。

# PyQt5の勉強
Qtは使ったことがあるものの、PyQt5となるとまた別。というわけで、[tutorial](http://zetcode.com/gui/pyqt5/)で勉強する。ひたすら写経。
並行して、[PyQt5 Reference Guide](http://pyqt.sourceforge.net/Docs/PyQt5/index.html)で使えるアイテムをチェック。

# PyQt5で作った簡易ブラウザ：Persephone
できた画面はこんな具合。
![window_of_persephone.png](https://qiita-image-store.s3.amazonaws.com/0/93354/aaf4f6d6-341c-bd6e-8398-326aa708a7a0.png)

- back / forward / reload / move ボタンは実装
- webページは表示可。YouTubeを見れる。
- url入力部は貧弱ではあるものの、一応ある。

コードは[GitHub](https://github.com/montblanc18/persephonep)にアップしてるが、こんな感じ。簡単にかける。

```python3
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os
from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit, 
                             QTextEdit, QGridLayout, QApplication, QPushButton,  QDesktopWidget)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView

__program__ = 'PERSEPHONE'


class PersephoneWindow(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.initUI()
        
        
    def initUI(self):
        
        initurl = 'https://www.google.co.jp'

        # setting browser
        self.browser = QWebEngineView()
        self.browser.load(QUrl(initurl))        
        self.browser.resize(1000,600)
        self.browser.move(200,200)
        self.browser.setWindowTitle(__program__)

        # setting button
        self.back_button = QPushButton('back')
        self.back_button.clicked.connect(self.browser.back)        
        self.forward_button = QPushButton('forward')
        self.forward_button.clicked.connect(self.browser.forward)
        self.reload_button = QPushButton('reload')
        self.reload_button.clicked.connect(self.browser.reload)
        self.url_edit = QLineEdit()
        self.move_button = QPushButton('move')
        self.move_button.clicked.connect(self.loadPage)

        # signal catch from moving web pages.
        self.browser.urlChanged.connect(self.updateCurrentUrl)

        # setting layout
        grid = QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(self.back_button, 1, 0)
        grid.addWidget(self.forward_button, 1, 1)
        grid.addWidget(self.reload_button, 1, 2)
        grid.addWidget(self.url_edit, 1, 3, 1, 10)
        grid.addWidget(self.move_button, 1, 14)
        grid.addWidget(self.browser,2, 0, 5, 15)
        self.setLayout(grid) 
        self.resize(1200, 800)
        self.center()
        self.setWindowTitle(__program__)
        self.show()

    
    def center(self):
        ''' centering widget
        '''
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def loadPage(self):
        ''' move web page which is set at url_edit
        '''
        move_url = QUrl(self.url_edit.text())
        self.browser.load(move_url)
        self.updateCurrentUrl

    def updateCurrentUrl(self):
        ''' rewriting url_edit when you move different web page.
        '''
        # current_url = self.browser.url().toString()
        self.url_edit.clear()
        self.url_edit.insert(self.browser.url().toString())

if __name__ == '__main__':
    # mainPyQt5()
    app = QApplication(sys.argv)

    # setWindowIcon is a method for QApplication, not for QWidget
    path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'icon_persephone.png')
    app.setWindowIcon(QIcon(path))

    ex = PersephoneWindow()
    sys.exit(app.exec_())
```
ちょっと面倒だったのは、下から4行目の```os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'icon_persephone.png')```。ここだけ上述のチュートリアルと異なり、このように書くことでアイコンの画像を設定することができる（[ここ](https://stackoverflow.com/questions/35864177/why-using-pyqt5-on-mac-can-not-add-a-icon)を参考にした）。
ちなみに名前の由来は、自分の星座である乙女座のモデルとなった（らしい）少女ペルセポネ。


# 感想と今後実装したいもの

- やはりQtはクロスプラットフォーム向けのフレームワークとして優秀。使いやすい。
- タッチパネルのスワイプに対応した画面遷移機能はまだない。ほしい。
- url入力部分が貧弱。httpの省略表示や入力補完ができていない。
- タブ機能がほしい。
- ブックマークはいらないが、それに相当するページをホームとして、そこに移動するためのボタンがほしい。
- proxy対応は必要かも。