2024-02-24

QWebEnginePage のコンテクスト・メニュー

PySide (Qt for Python) は、Qt(キュート)の Python バインディングで、GUI などを構築するためのクロスプラットフォームなライブラリです。Linux/X11, macOS および Microsoft Windows をサポートしています。配布ライセンスは LGPL で公開されています。

QWebEngineView に表示されたウェブサイト上を右クリックするとコンテクスト・メニューが表示されます。メニューの中で、Back / Forward / Reload については機能が付いていますが、残る Save pageView page source については(少なくとも試した PySide6 のバージョンでは)何も反応がありません。

今回のテーマ
  • QWebEngineView で読み込んだ URL は、QWebEnginePage に表示されます。
  • ここに表示されたウェブサイト上で、右クリックすると表示されるコンテクスト・メニュー(下記)の Save pageView page source を利用します。

なお、本サンプルで使用しているウェブサイトは、下記を利用しています。

下記の OS 環境で動作確認をしています。

Fedora Workstation 39 x86_64
Python 3.12.1
PySide6 6.6.2

サンプルを以下に示します。

qt_webenginepage_3.py
#!/usr/bin/env python
# coding: utf-8
import sys
from PySide6.QtCore import QFileInfo, QUrl
from PySide6.QtGui import QAction
from PySide6.QtWebEngineCore import QWebEngineDownloadRequest, QWebEnginePage
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWidgets import QApplication, QFileDialog
class Example(QWebEngineView):
def __init__(self, url: QUrl):
super().__init__()
self.resize(1000, 800)
self.load(url)
self.page().titleChanged.connect(self.setWindowTitle)
self.page().profile().downloadRequested.connect(
self.on_download_requested
)
def createWindow(self, wwtype: QWebEnginePage.WebWindowType):
action: QAction = self.pageAction(QWebEnginePage.WebAction.ViewSource)
if not action.isEnabled():
return
# Just STDOUT
self.page().toHtml(self.print_html)
def on_download_requested(self, download: QWebEngineDownloadRequest):
action: QAction = self.pageAction(QWebEnginePage.WebAction.SavePage)
if not action.isEnabled():
return
# Save page as single HTML
url_path = download.url().path()
if url_path == '/':
url_path = 'index.html'
suffix = QFileInfo(url_path).suffix()
path, _ = QFileDialog.getSaveFileName(
self, 'Save File', url_path, '*.' + suffix
)
if path:
download.setSavePageFormat(
QWebEngineDownloadRequest.SavePageFormat.SingleHtmlSaveFormat
)
download.setDownloadFileName(path)
download.accept()
@staticmethod
def print_html(html: str):
print(html)
def main(url: QUrl):
app = QApplication()
ex = Example(url)
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
url_init = QUrl('https://www.ueno-panda.jp/')
main(url_init)

このサンプルの実行例を以下に示しました。

qt_webenginepage_3.py の実行例

サンプルの説明

Save page

参考サイト [2]PySide6.QtWebEngineCore.QWebEnginePage.WebAction の説明によると、

定  数説  明
QWebEnginePage.SavePage
(QWebEnginePage.WebAction.SavePage)
Save the current page to disk. MHTML is the default format that is used to store the web page on disk. Requires a slot for downloadRequested() .
[参考訳]
現在のページをディスクに保存します。MHTML は、Web ページをディスクに保存する際のデフォルトのフォーマットです。downloadRequested() のスロットが必要です。

downloadRequested() のスロットが必要?

具体的に何をするのかピンとこなかったのですが、参考サイト [1] にズバリ知りたかったことが記載されていましたので、参考にさせていただきました。

class Example(QWebEngineView):
    def __init__(self, url: QUrl):
        super().__init__()
          :
          :
        self.page().profile().downloadRequested.connect(
            self.on_download_requested
        )

on_download_requested メソッドでは、最初に念のため self.pageAction(QWebEnginePage.WebAction.SavePage) が有効になっているか確認しています。

def on_download_requested(self, download: QWebEngineDownloadRequest):
    action: QAction = self.pageAction(QWebEnginePage.WebAction.SavePage)
    if not action.isEnabled():
        return
 
    # Save page as single HTML
    url_path = download.url().path()
    if url_path == '/':
        url_path = 'index.html'
    suffix = QFileInfo(url_path).suffix()
    path, _ = QFileDialog.getSaveFileName(
        self, 'Save File', url_path, '*.' + suffix
    )
    if path:
        download.setSavePageFormat(
            QWebEngineDownloadRequest.SavePageFormat.SingleHtmlSaveFormat
        )
        download.setDownloadFileName(path)
        download.accept()

QWebEngineDownloadRequest クラスの使い方、あるいはそのインスタンス download の扱い方については、試行錯誤をしている状態です。とりあえず、表示されている HTML の内容が保存されることで良しとしています。🙇🏻

View page source

参考サイト [2]PySide6.QtWebEngineCore.QWebEnginePage.WebAction の説明によると、

定  数説  明
QWebEnginePage.ViewSource
(QWebEnginePage.WebAction.ViewSource)
Show the source of the current page in a new tab. Requires implementation of createWindow() or newWindowRequested() .
[参考訳]
現在のページのソースを新しいタブに表示します。createWindow() または newWindowRequested() の実装が必要です。

これもなんだかよく判らなかったのですが、とにかく createWindow メソッドを実装(オーバーライド)してテストしてみました。すると、コンテクスト・メニューの View page source を選択すると、確かにこのメソッドが実行されることを確認できました。

この createWindow メソッドが呼び出されるのは、ソースを表示したい時だけではないかもしれないので、まず self.pageAction(QWebEnginePage.WebAction.ViewSource) が有効になっているかどうかを確認しています。なお、HTML ソースの内容を QTextEdit などに表示した方が実用的ですが、ここでは単に print_html メソッドで標準出力しています。

def createWindow(self, wwtype: QWebEnginePage.WebWindowType):
    action: QAction = self.pageAction(QWebEnginePage.WebAction.ViewSource)
    if not action.isEnabled():
        return
    # Just STDOUT
    self.page().toHtml(self.print_html)
@staticmethod
def print_html(html: str):
    print(html)

参考サイト

  1. python - How to download csv file with QWebEngineView and QUrl - Stack Overflow [2019-05-03]
  2. QWebEnginePage - Qt for Python
  3. QWebEngineView - Qt for Python
  4. QWebEngineDownloadRequest - Qt for Python

下記の動画では PyQt6 を利用しており、PySide6 ではありませんが大部分が同じなので参考になります。

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



0 件のコメント: