Chienomi

Python * PyQt5 * QtWebEngine 関係の簡単なソフトウェア

今回は表題の組み合わせでいくつかのソフトウェアを開発した。

そのうちふたつの話をしようと思う。

大元としてはAutoscrolling Textに含まれているUnsurfというウェブブラウザの改善にあったのだが、 従来このブラウザはQQmlApplicationEngineを使用したものだったのだが、「Weblioの翻訳を開くのに使いたい」という理由から物語は始まった。

旧バージョンのコード

Python

#!/usr/bin/python
import sys
import os
from PyQt5 import QtGui, QtQml
from OpenGL import GL  #Linux workaround.  See: http://goo.gl/s0SkFl

argv = sys.argv
argc = len(argv)

if (argc != 2):
    print("Usage:\n  webview.py addr")
    quit()

app = QtGui.QGuiApplication(["Qt Webview"])
engine = QtQml.QQmlApplicationEngine()
engine.rootContext().setContextProperty("myUrl", argv[1])
engine.load("{home}/lib/unsurf/unsurf.qml".format(home=os.environ["HOME"]))
app.exec_()

QML

import QtQuick 2.0
import QtQuick.Window 2.0
import QtWebEngine 1.0

Window {
    width: 1024
    height: 750
    visible: true
    WebEngineView {
        anchors.fill: parent
        url: myUrl
    }
}

これでちゃんと動く。

しかしこれだとWeblioを見ると、フォーム部品がさざなみゴシックのビットマップになってしまい大変汚い。 そもそもFontConfigのほうでビットマップフォントも埋め込みビットマップも無効にしているのになぜビットマップが出てしまうのか謎でならないけど、とにかくさざなみが嫌。

というわけで、「デフォルトフォント」を変更したいのだけど、QQmlApplicationEngineでそれをする方法がいくすら調べてもわからなかった。 もう、これでどうせQMLを使うのはちょっとダサいからQMLやめよう、というのが出発点。

ちなみに、Dilloのほうが速いのだが、fltk1.3では日本語入力ができない(1.4で修正済み)ので、待てばよいのだが待てなかった。

また、 私はPythonに関してもQtに関してもGUIプログラミングに関してもずぶの素人である のでご了承願いたい。

Weblioが見たくて

Gist

#!/usr/bin/python

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import *

app = QApplication(sys.argv)

web = QWebEngineView()

setty = QWebEngineView.settings(web)
setty.setFontFamily(QWebEngineSettings.StandardFont, "Source Han Sans JP")
setty.setFontFamily(QWebEngineSettings.SansSerifFont, "Source Han Serif JP")
setty.setFontFamily(QWebEngineSettings.SerifFont, "Source Han Serif JP")
setty.setAttribute(QWebEngineSettings.JavascriptEnabled, False)
setty.setAttribute(QWebEngineSettings.AutoLoadImages, False)

web.load(QUrl("https://ejje.weblio.jp/"))
web.show()

sys.exit(app.exec_())

実はこれ、ちゃんとしたUnsurfができてから必要な要素を変更して作っている。

QWebEngineView.settings().setFontFamilyという形でフォントの指定ができる。どちらかといえばfixedFontを設定することが多いようだが、ここらへんの情報はQtのドキュメントにある

さらに、同ドキュメントを参考に画像とJavaScriptを無効にすることで速度向上を狙っている。それでも結構重いが。 JavaScriptを無効にするとWeblioは広告が出ない。ちなみに、Weblioは珍しくgeneric fontを使う親切設計。

新しいUnsurf

commit 70cc1fde60760d2bae9e2894a3475a9979d66726 のもの。

#!/usr/bin/python
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtGui import QIcon
import re
import os

argv = sys.argv
argc = len(argv)

if (argc != 2):
    print("Usage:\n unsurf.py addr")
    quit()

# For opening local file.
url = argv[1]
if re.match('^[a-z]+://', url):
    pass # do nothing.
elif re.match('^/', url):
    url = 'file://' + url
else:
    url = "file://" + os.getcwd() + "/" + url

app = QApplication([])

# Choice application icon. I don't know smart way for choice generic web browser icon.
for iconpath in ["Papirus/64x64/apps/redhat-web-browser.svg", "Vibrancy-Colors/apps/96/browser.png", "Papirus/64x64/apps/internet-web-browser.svg", "breeze/apps/48/plasma-browser-integration.svg", "breeze/apps/48/internet-web-browser.svg", "Adwaita/scalable/apps/web-browser-symbolic.svg", "gnome/256x256/apps/web-browser.png", "ePapirus/22x22/actions/web-browser.svg", "AwOken/clear/128x128/apps/browser.png", "andromeda/apps/48/internet-web-browser.svg"]:
    if os.path.exists("/usr/share/icons/" + iconpath):
        app.setWindowIcon(QIcon.fromTheme("web-browser", QIcon("/usr/share/icons/" + iconpath)))
        break

web = QWebEngineView()
web.setWindowTitle("Unsruf Quick WebBrowser")
web.load(QUrl(url))
web.show()

sys.exit(app.exec_())

いろいろ追加したので39行ある。ちなみに、処理的に追加された部分を抜くと19行で、17行の旧unsurfと比べると少し長くなっているが、旧unsurfはQMLもあるので一概に比較はできないだろう。 ちなみに、旧Unsurfと同等(タイトルがないが)にすると次のような感じだ。

#!/usr/bin/python
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import *

argv = sys.argv
argc = len(argv)

if (argc != 2):
    print("Usage:\n unsurf.py addr")
    quit()

app = QApplication([])
web = QWebEngineView()
web.load(QUrl(argv[1]))
web.show()

sys.exit(app.exec_())

完全に最小でWebEngine(Blink)なブラウザを書きたいと思っている人のために最小にすると次のようになる。

#!/usr/bin/python
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import *
app = QApplication([])
web = QWebEngineView()
web.load(QUrl(sys.argv[1]))
web.show()
sys.exit(app.exec_())

9行、243バイトのウェブブラウザの完成である。 いやぁ、ツールキットってすごいなぁ…

処理的に追加されたのは、まずファイルを開くときにスキーマをサポートすることであり、QQmlApplicationEngineを使用した場合は絶対パスであればファイルを開ける(相対パスは無理)のだが、 QWebEngineViewの場合はfile:///形式でなければ開けないので、そのための処理が追加されている。ついでに相対パスもサポートすることで使い勝手を上げている。

アイコンに関しては、Zenityのように汎用性のある名前で指定してアイコンを探索する方法があるのではないか、と思って調べたのだが到達できなかったので、 結局私の手元であるものを列挙して探すことにした。

なにかしようとするたんびにimportが増えていくPythonの特徴は、なかなか慣れない。

Incognitoブラウザとして結構イケてる

さて、Surfを導入していない環境に対する救済策としてAutoscrolling TextにバンドルしているUnsurfだが、実は「Surfよりイケてるんじゃないか?」と思い始めている。

SurfはGtkWebKitだし、というのが割と大きい。 そもそもSurfは45kほどあるし、ここまできっぱりと「なんもしてない」とわかるほうが良かったりしないだろうか。

トラッキングとかその他色々について、ここまで単純だと「機能がない」という理由で全く心配しなくて良い。1 Surfは起動が結構遅く、リダイレクトの処理が異様に遅いので、その意味でも単純にページを開くだけだったら結構使いやすい。

むすびに

本当に関連知識が私には乏しいので、私程度が知識をひけらかすべきものではないとは思ったのだけれど、 今回の制作で検索したときになかなか情報がでなくて、「QWebEngineViewで最低限のブラウザはどうすればいいのか」といったことも結構たどり着くのが大変だったので、 同様に知識がない人のために情報として書き残しておくことにする。


  1. この言い方は過剰かもしれない。少なくとも、QWebEngineViewの機能によってキャッシュはする。だが、エンジンやアプリケーションがトラッキングする危惧が相対的に低いということである。↩︎

Wrote on: 2019-10-18 08:17:00 +09:00