Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Fetch text from a site as QString
Forum Updated to NodeBB v4.3 + New Features

Fetch text from a site as QString

Scheduled Pinned Locked Moved Solved General and Desktop
24 Posts 6 Posters 3.1k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    realroot
    wrote on last edited by
    #1

    How can I fetch text from a site as QString in a function of a C++ class?
    Can I do it using Qt classes as QNetworkAccessManager etc.?

    C 1 Reply Last reply
    0
    • R realroot

      If something is wrong let me know, thanks.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #19

      @realroot
      It looks reasonable. Although your

      QNetworkAccessManager* m_manager = new QNetworkAccessManager(this);
      

      will work personally I would do the new in the MyClass constructor, to the line above where you have moved the connect() like @SGaist said. But maybe that's just me. In any case I believe your code is now acceptable.

      1 Reply Last reply
      0
      • posktomtenP Offline
        posktomtenP Offline
        posktomten
        wrote on last edited by
        #2

        Hello!@realroot
        I have made a library that reads a text string from a text file on a web server.
        My library compares the loaded character string (which contains the latest version number) to the current version.

        You might be able to get some help if you check the part of the library that reads the text string.
        https://gitlab.com/posktomten/libcheckforupdates

        posktomten

        1 Reply Last reply
        0
        • posktomtenP Offline
          posktomtenP Offline
          posktomten
          wrote on last edited by
          #3

          The library
          https://gitlab.com/posktomten/libcheckforupdates/-/tree/master/bibliotek/code?ref_type=heads

          posktomten

          1 Reply Last reply
          0
          • R realroot

            How can I fetch text from a site as QString in a function of a C++ class?
            Can I do it using Qt classes as QNetworkAccessManager etc.?

            C Offline
            C Offline
            ChrisW67
            wrote on last edited by
            #4

            @realroot said in Fetch text from a site as QString:

            Can I do it using Qt classes as QNetworkAccessManager etc.?

            Yes. Most of the logic is in this example.

            1 Reply Last reply
            2
            • R Offline
              R Offline
              realroot
              wrote on last edited by realroot
              #5
              QNetworkAccessManager qnam;
                 QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> reply;
                 reply.reset(qnam.get(QNetworkRequest(QUrl(
                     "https://...file"))));
                 QByteArray bytes = reply->readAll();
               QString s = QString::fromUtf8(bytes));
              

              It's empty.
              I just want to fetch the webpage as text no need to open files etc.

              JonBJ 1 Reply Last reply
              0
              • R realroot
                QNetworkAccessManager qnam;
                   QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> reply;
                   reply.reset(qnam.get(QNetworkRequest(QUrl(
                       "https://...file"))));
                   QByteArray bytes = reply->readAll();
                 QString s = QString::fromUtf8(bytes));
                

                It's empty.
                I just want to fetch the webpage as text no need to open files etc.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #6

                @realroot said in Fetch text from a site as QString:

                It's empty.

                Yes, it would (likely) be. You are calling readAll() too early. QNetworkAccessManager::get() only starts the process of getting the response content

                Posts a request to obtain the contents of the target request and returns a new QNetworkReply object opened for reading which emits the readyRead() signal whenever new data arrives.

                It is asynchronous. See https://doc.qt.io/qt-6/qnetworkaccessmanager.html#details for an example of what you should be doing. You need to act on the QNetworkReply's readyRead() or finished() signals, there you will be able to read the data returned.

                1 Reply Last reply
                2
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #7

                  Hi,

                  Beside what @JonB, you code sample also has an object lifetime issue. You need to ensure it lasts longer than the query call.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  1
                  • R Offline
                    R Offline
                    realroot
                    wrote on last edited by
                    #8

                    If I need to act on signals() does that mean that I have to connect my C++ class to do that?

                    connect(manager, &QNetworkAccessManager::finished,
                            this, &MyClass::replyFinished);
                    

                    To fix the lifetime can I do this?

                    QString s = QString::fromUtf8(reply->readAll());
                    
                    JonBJ 1 Reply Last reply
                    0
                    • R realroot

                      If I need to act on signals() does that mean that I have to connect my C++ class to do that?

                      connect(manager, &QNetworkAccessManager::finished,
                              this, &MyClass::replyFinished);
                      

                      To fix the lifetime can I do this?

                      QString s = QString::fromUtf8(reply->readAll());
                      
                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #9

                      @realroot
                      Yes, after your connect() (or you could have connected the reply object) you should be able to reply->readAll() in slot.

                      No to second, that's not the issue. The reply needs to outlive where you do the get(), till (at least) the finished(). You won't want to use a QScopedPointer, that will destroy it. And of course the QNAM must also be kept in existence.

                      1 Reply Last reply
                      1
                      • R Offline
                        R Offline
                        realroot
                        wrote on last edited by
                        #10
                        QNetworkAccessManager *manager = new QNetworkAccessManager(this);
                           connect(manager, &QNetworkAccessManager::finished,
                               this, &MyClass::replyFinished);
                        
                           manager->get(QNetworkRequest(QUrl(
                               "https://...file")));
                        
                        // Class public slot function:
                        
                        void replyFinished(QNetworkReply *reply) {
                           if (reply->error() == QNetworkReply::NoError) {
                               QByteArray data = reply->readAll();
                               QFile file(<file>);
                               if (file.open(QIODevice::WriteOnly)) {
                                   QTextStream out(&file);
                                   out << data;
                                   file.close();
                                   doSomething(<file>);
                               }
                           }
                           reply->deleteLater();
                        }
                        

                        Thanks, this is working. Is it safe now?

                        1 Reply Last reply
                        0
                        • SGaistS Offline
                          SGaistS Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on last edited by
                          #11

                          When are you creating your manager object ? Based only on your code, it seems you will be creating it many times though you only need one instance during the lifetime of your application.

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          1 Reply Last reply
                          1
                          • R Offline
                            R Offline
                            realroot
                            wrote on last edited by
                            #12

                            In the function there is no more code:

                            void MyClass::downloadFile() {
                            QNetworkAccessManager *manager = new QNetworkAccessManager(this);
                               connect(manager, &QNetworkAccessManager::finished,
                                   this, &MyClass::replyFinished);
                            
                               manager->get(QNetworkRequest(QUrl(
                                   "https://...file")));
                            }
                            

                            Should I make a manager instance as private member of MyClass?

                            JonBJ 1 Reply Last reply
                            0
                            • R realroot

                              In the function there is no more code:

                              void MyClass::downloadFile() {
                              QNetworkAccessManager *manager = new QNetworkAccessManager(this);
                                 connect(manager, &QNetworkAccessManager::finished,
                                     this, &MyClass::replyFinished);
                              
                                 manager->get(QNetworkRequest(QUrl(
                                     "https://...file")));
                              }
                              

                              Should I make a manager instance as private member of MyClass?

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by JonB
                              #13

                              @realroot said in Fetch text from a site as QString:

                              In the function there is no more code:

                              It is not a question of whether this function has more code. It is a question of whether MyClass::replyFinished() completes all processing of the reply/downloading the file. Which I imagine it does.

                              Should I make a manager instance as private member of MyClass?

                              Yes. And do not allocate it more than once! You could alternatively allocate manager within the class instead of with new, i.e. QNetworkAccessManager manager; as a member variable would work. And don't forget you need to call reply->deleteLater() in MyClass::replyFinished(QNetworkReply *reply). As per https://doc.qt.io/qt-6/qnetworkaccessmanager.html#details

                              Note: After the request has finished, it is the responsibility of the user to delete the QNetworkReply object at an appropriate time. Do not directly delete it inside the slot connected to finished(). You can use the deleteLater() function.

                              1 Reply Last reply
                              0
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #14

                                In addition to what @JonB wrote, the fact that you pass a parent to your manager object only ensures that it will get destroyed when the parent gets destroyed.

                                What you currently have is a variant of memory leak since you create new instances of QNetworkAccessManager every time you call that function and they will only get destroyed when your MyClass instance will as well.

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                1 Reply Last reply
                                1
                                • R Offline
                                  R Offline
                                  realroot
                                  wrote on last edited by
                                  #15

                                  I see thanks.
                                  If I declare it as QNetworkAccessManager manager; I have errors so I made it like this:

                                  private:
                                      QNetworkAccessManager* m_manager = new QNetworkAccessManager(this);
                                  
                                  void MyClass::downloadFile() {
                                     connect(m_manager, &QNetworkAccessManager::finished,
                                         this, &MyClass::replyFinished);
                                  
                                     manager->get(QNetworkRequest(QUrl(
                                         "https://...file")));
                                  }
                                  
                                  void MyClass::replyFinished(QNetworkReply *reply) {
                                     if (reply->error() == QNetworkReply::NoError) {
                                         QByteArray data = reply->readAll();
                                         QFile file(<file>);
                                         if (file.open(QIODevice::WriteOnly)) {
                                             QTextStream out(&file);
                                             out << data;
                                             file.close();
                                             doSomething(<file>);
                                         }
                                     }
                                     reply->deleteLater();
                                  }
                                  
                                  SGaistS 1 Reply Last reply
                                  0
                                  • R realroot

                                    I see thanks.
                                    If I declare it as QNetworkAccessManager manager; I have errors so I made it like this:

                                    private:
                                        QNetworkAccessManager* m_manager = new QNetworkAccessManager(this);
                                    
                                    void MyClass::downloadFile() {
                                       connect(m_manager, &QNetworkAccessManager::finished,
                                           this, &MyClass::replyFinished);
                                    
                                       manager->get(QNetworkRequest(QUrl(
                                           "https://...file")));
                                    }
                                    
                                    void MyClass::replyFinished(QNetworkReply *reply) {
                                       if (reply->error() == QNetworkReply::NoError) {
                                           QByteArray data = reply->readAll();
                                           QFile file(<file>);
                                           if (file.open(QIODevice::WriteOnly)) {
                                               QTextStream out(&file);
                                               out << data;
                                               file.close();
                                               doSomething(<file>);
                                           }
                                       }
                                       reply->deleteLater();
                                    }
                                    
                                    SGaistS Offline
                                    SGaistS Offline
                                    SGaist
                                    Lifetime Qt Champion
                                    wrote on last edited by
                                    #16

                                    @realroot said in Fetch text from a site as QString:

                                    I see thanks.
                                    If I declare it as QNetworkAccessManager manager; I have errors so I made it like this:

                                    private:
                                        QNetworkAccessManager* m_manager = new QNetworkAccessManager(this);
                                    
                                    void MyClass::downloadFile() {
                                       connect(m_manager, &QNetworkAccessManager::finished,
                                           this, &MyClass::replyFinished);
                                    
                                    
                                    

                                    Move that connect to the constructor of your class. Otherwise each time you call downloadFile you will create a new connection which means that the slot will be called an additional time.

                                    Interested in AI ? www.idiap.ch
                                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                    1 Reply Last reply
                                    2
                                    • R Offline
                                      R Offline
                                      realroot
                                      wrote on last edited by
                                      #17

                                      Then it should be so I believe:

                                      class MyClass : public QAbstractListModel {
                                          Q_OBJECT
                                      public:
                                          MyClass(QObject *parent = nullptr) : QAbstractListModel(parent) {
                                              connect(m_manager, &QNetworkAccessManager::finished,
                                                      this, &MyClass::downloadFinished);
                                          }
                                      private:
                                          QNetworkAccessManager* m_manager = new QNetworkAccessManager(this);
                                      
                                      void MyClass::downloadFile() {
                                          m_manager->get(QNetworkRequest(QUrl(
                                             "https://...file")));
                                      }
                                      

                                      It's working at least.

                                      1 Reply Last reply
                                      0
                                      • R Offline
                                        R Offline
                                        realroot
                                        wrote on last edited by
                                        #18

                                        If something is wrong let me know, thanks.

                                        JonBJ 1 Reply Last reply
                                        0
                                        • R realroot

                                          If something is wrong let me know, thanks.

                                          JonBJ Offline
                                          JonBJ Offline
                                          JonB
                                          wrote on last edited by JonB
                                          #19

                                          @realroot
                                          It looks reasonable. Although your

                                          QNetworkAccessManager* m_manager = new QNetworkAccessManager(this);
                                          

                                          will work personally I would do the new in the MyClass constructor, to the line above where you have moved the connect() like @SGaist said. But maybe that's just me. In any case I believe your code is now acceptable.

                                          1 Reply Last reply
                                          0
                                          • R realroot has marked this topic as solved on
                                          • R Offline
                                            R Offline
                                            realroot
                                            wrote on last edited by
                                            #20

                                            @JonB Like this?

                                            public:
                                                        MyClass(QObject *parent = nullptr) : QAbstractListModel(parent) {
                                                            m_manager = new QNetworkAccessManager(this);
                                                            connect(m_manager, &QNetworkAccessManager::finished,
                                                                    this, &MyClass::downloadFinished);
                                                        }
                                            
                                            Pl45m4P 1 Reply Last reply
                                            0

                                            • Login

                                            • Login or register to search.
                                            • First post
                                              Last post
                                            0
                                            • Categories
                                            • Recent
                                            • Tags
                                            • Popular
                                            • Users
                                            • Groups
                                            • Search
                                            • Get Qt Extensions
                                            • Unsolved