Search code examples
c++qtqt5qwebengineviewqwebenginepage

How to save dynamically generated web page in QWebEngineView?


I am loading a web page onto QWebEngineView. A user creates a different kind of tables (reports) and then needs to save those tables to local computer as a web page. Here is what I have tried:

  1. Here I use a QWebEnginePage::save() method, but nothing happens:

    connect(saveButton, &QPushButton::clicked, this, [this]()
    {
       engineWebView->page()->save("save.html");
    });
    
  2. Then I tried a QWebEngineProfile::download() method:

    connect(saveButton, &QPushButton::clicked, this, [this]()
    {
        engineWebView->page()->download(engineWebView->page()->url(), "save");
    });
    connect(engineWebView->page()->profile(), &QWebEngineProfile::downloadRequested, this, [this](QWebEngineDownloadItem *download) 
    {
        download->setPath("save.html");
        download->accept();
    });

In the second solution, I can save only the first loaded webpage. No dynamically created content.

How do I save a dynamically created data?


Edit: minimal reproducible code:

#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QHBoxLayout>
#include <QPushButton>
#include <QWebEngineProfile>
#include <QWebEngineView>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWebEngineView *engine = new QWebEngineView;
    QObject::connect(engine->page()->profile(), &QWebEngineProfile::downloadRequested, [](QWebEngineDownloadItem *download) {
        download->setPath("download.html");
        download->accept();
    });

    QPushButton *saveButton = new QPushButton("Save");
    QObject::connect(saveButton, &QPushButton::clicked, [engine]()
    {
        engine->page()->save("save.html");
    });

    QPushButton *toHtmlButton = new QPushButton("ToHtml");
    QObject::connect(toHtmlButton, &QPushButton::clicked, [engine]()
    {
        engine->page()->toHtml([](QString html){
        QFile file("toHtml.html");
        if (file.open(QFile::WriteOnly | QFile::Text))
        {
            QTextStream stream(&file);
            stream << html;
            file.waitForBytesWritten(-1);
            file.close();
        }
        else
            qDebug() << "Cannot create a file";
        });
    });

    QPushButton *downloadButton = new QPushButton("Download");
    QObject::connect(downloadButton, &QPushButton::clicked, [engine]()
    {
        engine->page()->download(engine->page()->url());
    });

    QHBoxLayout *hLyt = new QHBoxLayout;
    hLyt->addWidget(saveButton);
    hLyt->addWidget(toHtmlButton);
    hLyt->addWidget(downloadButton);

    QVBoxLayout *vLyt = new QVBoxLayout;
    vLyt->addLayout(hLyt);
    vLyt->addWidget(engine);

    QWidget *mainWin = new QWidget;
    mainWin->setLayout(vLyt);
    mainWin->show();

    // The url is an example for react usage. I am generating data using ReactJS that's why I use this example. What I need is to store the exact view of the dynamically generated calculator        
    engine->load(QUrl("https://ahfarmer.github.io/calculator/"));

    return app.exec();
}

Solution

  • If you want to get the dynamically generated html you can use javascript to get the outerHTML of the document using the runJavaScript() method of QWebEnginePage:

    #include <QtWebEngineWidgets>
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QWebEngineView *view = new QWebEngineView;
        QPushButton *button = new QPushButton("Press me");
        button->setEnabled(false);
        QObject::connect(button, &QPushButton::clicked, [view]()
        {
            view->page()->runJavaScript("document.documentElement.outerHTML", [](const QVariant &v) { 
                QFile file("outerHTML.html");
                if(!file.open(QFile::WriteOnly | QFile::Text)){
                    qDebug() << "Cannot create a file";
                    return;
                }
                QTextStream stream(&file);
                stream << v.toString();
                file.close();
            });
        });
        QObject::connect(view, &QWebEngineView::loadFinished, [button](bool ok){
            button->setEnabled(ok);
        });
        view->load(QUrl("https://ahfarmer.github.io/calculator/"));
        QWidget w;
        QVBoxLayout *lay = new QVBoxLayout(&w);
        lay->addWidget(button);
        lay->addWidget(view);
        w.resize(640, 480);
        w.show();
        return app.exec();
    }