3

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();
}
Bobur
  • 545
  • 1
  • 6
  • 21
  • The "dynamically created" can be subjective to it would be great if you show what you get (HTML) and what you want to get (HTML) using the url you have offered. On the other hand, the application of reports in HTML generally allows you to download/export those files in a certain format (CSV, PDF, XLSX, etc.). Does your reporting system not provide that? – eyllanesc Aug 05 '19 at 05:14
  • @eyllanesc That is the problem. Our reporting system just generates an HTML table using tags (`, , etc`).
    – Bobur Aug 05 '19 at 05:22
  • @eyllanesc Please open that URL on Chrome. If you see the page source (`Ctrl+U`) it contains just one line that calls JS function. But if you inspect some of the DOM elements (`Ctrs+Shift+I`) it shows you "dynamically generated" data (lots of HTML code). I need exactly that code. – Bobur Aug 05 '19 at 05:27

1 Answers1

4

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();
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Could you also comment on why the proposed methods in the question do not seem to work? – NoDataDumpNoContribution Aug 05 '19 at 06:13
  • @Trilarion Is that there are several HTML in a dynamic web page, in the case of the previous methods they focus on the HTML downloaded from the server, so I assume that the developers of Qt WebEngine thought that the indicated methods only owe that information, but they also gave us more freedom because we can use javascript to interact with the DOM. – eyllanesc Aug 05 '19 at 06:19
  • @Trilarion In conclusion, the concept of HTML depends from the point of view since you analyze it. – eyllanesc Aug 05 '19 at 06:20