Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Language Bindings
  4. wrap QApplication::exec() into a function or class

wrap QApplication::exec() into a function or class

Scheduled Pinned Locked Moved Unsolved Language Bindings
python
12 Posts 3 Posters 5.0k Views
  • 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 redstoneleo

    I want the following code to get the request url starting with http://down.51en.com:88 during the web loading process , and then do other processing with the response object of the url .
    In my program, once targetUrl is assigned a value , I want the function targetUrlGetter(url) to return it to the caller, however , the problem is that QApplication::exec() enters the main event loop so cannot execute code at the end of thetargetUrlGetter() function after the exec() call , thus the function cannot return , I have tried with qApp.quit() in interceptRequest(self, info) in order to tell the application to exit so that targetUrlGetter(url) can return , but the function still cannot return and the program even crashes on exit, so how can I return the targetUrl to the caller program ?

    BTW, I am going to use the code at (Django) web server side.

    import sys
    
    from PyQt5.QtWidgets import *
    from PyQt5.QtWebEngineWidgets import *
    from PyQt5.QtWebEngineCore import *
    from PyQt5.QtCore import *
    
    
    class WebEngineUrlRequestInterceptor(QWebEngineUrlRequestInterceptor):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.page = parent
    
        def interceptRequest(self, info):
            if info.requestUrl().toString().startswith('http://down.51en.com:88'):
                self.targetUrl = info.requestUrl().toString()
                print('----------------------------------------------', self.targetUrl)
                qApp.quit()
    
                # self.page.load(QUrl(''))
    
    
    def targetUrlGetter(url=None):
        app = QApplication(sys.argv)
        page = QWebEnginePage()
        globalSettings = page.settings().globalSettings()
        globalSettings.setAttribute(
            QWebEngineSettings.PluginsEnabled, True)
        globalSettings.setAttribute(
            QWebEngineSettings.AutoLoadImages, False)
        profile = page.profile()
        webEngineUrlRequestInterceptor = WebEngineUrlRequestInterceptor(page)
        profile.setRequestInterceptor(webEngineUrlRequestInterceptor)
        page.load(QUrl(url))
        # view = QWebEngineView()
        # view.setPage(page)
        # view.show()
        app.exec_()
        return webEngineUrlRequestInterceptor.targetUrl
    
    
    url = "http://www.51en.com/news/sci/everything-there-is-20160513.html"
    # url = "http://www.51en.com/news/sci/obese-dad-s-sperm-may-influence-offsprin.html"
    # url = "http://www.51en.com/news/sci/mars-surface-glass-could-hold-ancient-fo.html"
    targetUrl = targetUrlGetter(url)
    print(targetUrl)
    
    jsulmJ Offline
    jsulmJ Offline
    jsulm
    Lifetime Qt Champion
    wrote on last edited by
    #2

    @redstoneleo Why not connect http://doc.qt.io/qt-5/qwebenginepage.html#loadFinished signal to quit() slot?

    R 1 Reply Last reply
    0
    • jsulmJ jsulm

      @redstoneleo Why not connect http://doc.qt.io/qt-5/qwebenginepage.html#loadFinished signal to quit() slot?

      R Offline
      R Offline
      redstoneleo
      wrote on last edited by
      #3

      @redstoneleo said:

      once targetUrl is assigned a value

      I cannot see the difference On doing that

      jsulmJ 1 Reply Last reply
      0
      • R redstoneleo

        @redstoneleo said:

        once targetUrl is assigned a value

        I cannot see the difference On doing that

        jsulmJ Offline
        jsulmJ Offline
        jsulm
        Lifetime Qt Champion
        wrote on last edited by
        #4
        This post is deleted!
        1 Reply Last reply
        0
        • R redstoneleo

          I want the following code to get the request url starting with http://down.51en.com:88 during the web loading process , and then do other processing with the response object of the url .
          In my program, once targetUrl is assigned a value , I want the function targetUrlGetter(url) to return it to the caller, however , the problem is that QApplication::exec() enters the main event loop so cannot execute code at the end of thetargetUrlGetter() function after the exec() call , thus the function cannot return , I have tried with qApp.quit() in interceptRequest(self, info) in order to tell the application to exit so that targetUrlGetter(url) can return , but the function still cannot return and the program even crashes on exit, so how can I return the targetUrl to the caller program ?

          BTW, I am going to use the code at (Django) web server side.

          import sys
          
          from PyQt5.QtWidgets import *
          from PyQt5.QtWebEngineWidgets import *
          from PyQt5.QtWebEngineCore import *
          from PyQt5.QtCore import *
          
          
          class WebEngineUrlRequestInterceptor(QWebEngineUrlRequestInterceptor):
              def __init__(self, parent=None):
                  super().__init__(parent)
                  self.page = parent
          
              def interceptRequest(self, info):
                  if info.requestUrl().toString().startswith('http://down.51en.com:88'):
                      self.targetUrl = info.requestUrl().toString()
                      print('----------------------------------------------', self.targetUrl)
                      qApp.quit()
          
                      # self.page.load(QUrl(''))
          
          
          def targetUrlGetter(url=None):
              app = QApplication(sys.argv)
              page = QWebEnginePage()
              globalSettings = page.settings().globalSettings()
              globalSettings.setAttribute(
                  QWebEngineSettings.PluginsEnabled, True)
              globalSettings.setAttribute(
                  QWebEngineSettings.AutoLoadImages, False)
              profile = page.profile()
              webEngineUrlRequestInterceptor = WebEngineUrlRequestInterceptor(page)
              profile.setRequestInterceptor(webEngineUrlRequestInterceptor)
              page.load(QUrl(url))
              # view = QWebEngineView()
              # view.setPage(page)
              # view.show()
              app.exec_()
              return webEngineUrlRequestInterceptor.targetUrl
          
          
          url = "http://www.51en.com/news/sci/everything-there-is-20160513.html"
          # url = "http://www.51en.com/news/sci/obese-dad-s-sperm-may-influence-offsprin.html"
          # url = "http://www.51en.com/news/sci/mars-surface-glass-could-hold-ancient-fo.html"
          targetUrl = targetUrlGetter(url)
          print(targetUrl)
          
          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #5

          @redstoneleo You should not put app and app.exec() into a function. And instead of using the return value of a function you should use signals/slots to get the value (you can emit a signal in interceptRequest()).

          R 1 Reply Last reply
          0
          • jsulmJ jsulm

            @redstoneleo You should not put app and app.exec() into a function. And instead of using the return value of a function you should use signals/slots to get the value (you can emit a signal in interceptRequest()).

            R Offline
            R Offline
            redstoneleo
            wrote on last edited by
            #6

            @jsulm Please see the updated post again ! thanks !

            The difficulties here are how to exit the Qt event loop without crash and return the request url to the caller , I cannot see the signals/slots can help here

            1 Reply Last reply
            0
            • jazzycamelJ Offline
              jazzycamelJ Offline
              jazzycamel
              wrote on last edited by
              #7

              You have a number of issues, running exec_ from a function actually isn't one of them (in this case!). I have a number of questions/points:

              • Why are you doing this with Qt? If you are going to be running this on a server (with Django?) then it will probably be headless and a Q(Gui)Application won't run there. You should probably look at a pure python solution using urllib / HTTPRedirectHandler.
              • Your program will only hit qApp.quit() IF it is redirected to your specified URL; what if it doesn't?
              • You should definitely be doing this using the signal/slot mechanism! You are currently trying to work against Qt's asynchronicity.

              The following is a working version of what you're trying to do (Python 3.5.1, PyQt5.7):

              from sys import argv
              
              from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, QObject, QUrl
              from PyQt5.QtWidgets import QApplication, qApp
              from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor
              from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineView, QWebEngineSettings
              
              class Interceptor(QWebEngineUrlRequestInterceptor):
                  urlIntercepted=pyqtSignal(str)
              
                  def __init__(self, url, parent=None, **kwargs):
                      super().__init__(parent, **kwargs)
              
                      self._url=url
                      self._page=parent
              
                  def interceptRequest(self, info):
                      if info.requestUrl().toString().startswith(self._url):
                          self.urlIntercepted.emit(info.requestUrl().toString())
              
              class TargetUrlGetter(QObject):
                  def __init__(self, url, interceptUrl, show=False, parent=None, **kwargs):
                      super().__init__(parent, **kwargs)
              
                      self._targetUrl=None
                      self._url=url
                      self._interceptUrl=interceptUrl
                      self._page=QWebEnginePage(loadFinished=qApp.quit)
              
                      settings=self._page.settings().globalSettings()
                      settings.setAttribute(QWebEngineSettings.PluginsEnabled, True)
                      settings.setAttribute(QWebEngineSettings.AutoLoadImages, False)
              
                      self._interceptor=Interceptor(
                          self._interceptUrl,
                          self._page,
                          urlIntercepted=self.urlIntercepted
                      )
                      profile=self._page.profile()
                      profile.setRequestInterceptor(self._interceptor)
              
                      self._page.load(QUrl(url))
              
                      if not show: return
              
                      self._view=QWebEngineView()
                      self._view.setPage(self._page)
                      self._view.show()
              
                  def getTargetUrl(self): return self._targetUrl
              
                  @pyqtSlot(str)
                  def setTargetUrl(self, url):
                      if url==self._targetUrl: return
                      self._targetUrl=url
              
                  targetUrl=pyqtProperty(str, getTargetUrl, setTargetUrl)
              
                  @pyqtSlot(str)
                  def urlIntercepted(self, url):
                      self.targetUrl=url
                      qApp.quit()
              
              def getTargetUrl(url, interceptUrl):
                  app=QApplication(argv)
                  t=TargetUrlGetter(url, interceptUrl)
                  exitValue=app.exec_()
                  return t.targetUrl
              
              if __name__=="__main__":
                  url="http://www.51en.com/news/sci/everything-there-is-20160513.html"
                  interceptUrl='http://down.51en.com:88'    
                  print(getTargetUrl(url, interceptUrl))
              

              For the avoidance of doubt:

              1. All my code samples (C++ or Python) are tested before posting
              2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
              jsulmJ 1 Reply Last reply
              1
              • jazzycamelJ jazzycamel

                You have a number of issues, running exec_ from a function actually isn't one of them (in this case!). I have a number of questions/points:

                • Why are you doing this with Qt? If you are going to be running this on a server (with Django?) then it will probably be headless and a Q(Gui)Application won't run there. You should probably look at a pure python solution using urllib / HTTPRedirectHandler.
                • Your program will only hit qApp.quit() IF it is redirected to your specified URL; what if it doesn't?
                • You should definitely be doing this using the signal/slot mechanism! You are currently trying to work against Qt's asynchronicity.

                The following is a working version of what you're trying to do (Python 3.5.1, PyQt5.7):

                from sys import argv
                
                from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, QObject, QUrl
                from PyQt5.QtWidgets import QApplication, qApp
                from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor
                from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineView, QWebEngineSettings
                
                class Interceptor(QWebEngineUrlRequestInterceptor):
                    urlIntercepted=pyqtSignal(str)
                
                    def __init__(self, url, parent=None, **kwargs):
                        super().__init__(parent, **kwargs)
                
                        self._url=url
                        self._page=parent
                
                    def interceptRequest(self, info):
                        if info.requestUrl().toString().startswith(self._url):
                            self.urlIntercepted.emit(info.requestUrl().toString())
                
                class TargetUrlGetter(QObject):
                    def __init__(self, url, interceptUrl, show=False, parent=None, **kwargs):
                        super().__init__(parent, **kwargs)
                
                        self._targetUrl=None
                        self._url=url
                        self._interceptUrl=interceptUrl
                        self._page=QWebEnginePage(loadFinished=qApp.quit)
                
                        settings=self._page.settings().globalSettings()
                        settings.setAttribute(QWebEngineSettings.PluginsEnabled, True)
                        settings.setAttribute(QWebEngineSettings.AutoLoadImages, False)
                
                        self._interceptor=Interceptor(
                            self._interceptUrl,
                            self._page,
                            urlIntercepted=self.urlIntercepted
                        )
                        profile=self._page.profile()
                        profile.setRequestInterceptor(self._interceptor)
                
                        self._page.load(QUrl(url))
                
                        if not show: return
                
                        self._view=QWebEngineView()
                        self._view.setPage(self._page)
                        self._view.show()
                
                    def getTargetUrl(self): return self._targetUrl
                
                    @pyqtSlot(str)
                    def setTargetUrl(self, url):
                        if url==self._targetUrl: return
                        self._targetUrl=url
                
                    targetUrl=pyqtProperty(str, getTargetUrl, setTargetUrl)
                
                    @pyqtSlot(str)
                    def urlIntercepted(self, url):
                        self.targetUrl=url
                        qApp.quit()
                
                def getTargetUrl(url, interceptUrl):
                    app=QApplication(argv)
                    t=TargetUrlGetter(url, interceptUrl)
                    exitValue=app.exec_()
                    return t.targetUrl
                
                if __name__=="__main__":
                    url="http://www.51en.com/news/sci/everything-there-is-20160513.html"
                    interceptUrl='http://down.51en.com:88'    
                    print(getTargetUrl(url, interceptUrl))
                
                jsulmJ Offline
                jsulmJ Offline
                jsulm
                Lifetime Qt Champion
                wrote on last edited by
                #8

                @jazzycamel It is perfectly fine to use Qt for non GUI applications. See QtCore, QtNetwork and some other modules.

                1 Reply Last reply
                0
                • jazzycamelJ Offline
                  jazzycamelJ Offline
                  jazzycamel
                  wrote on last edited by jazzycamel
                  #9

                  @jsulm I agree, but as I said this needs a QApplication because its using QWebEnginePage/View... that will crash if you try and start it in a headless (i.e. typical web server) environment. Also, doing this with Qt rather than a python builtin module really is using a sledgehammer to crack a nut.

                  For the avoidance of doubt:

                  1. All my code samples (C++ or Python) are tested before posting
                  2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
                  R 1 Reply Last reply
                  1
                  • jazzycamelJ jazzycamel

                    @jsulm I agree, but as I said this needs a QApplication because its using QWebEnginePage/View... that will crash if you try and start it in a headless (i.e. typical web server) environment. Also, doing this with Qt rather than a python builtin module really is using a sledgehammer to crack a nut.

                    R Offline
                    R Offline
                    redstoneleo
                    wrote on last edited by redstoneleo
                    #10

                    @jazzycamel

                    1.Once I changed

                    url = "http://www.le.com/ptv/vplay/1417484.html"
                    interceptUrl = 'http://api.le.com/mms/out/video/playJson?'
                    

                    in your code, then the program crashes during running , tested on Win7 32bit. What I am sure is this time the flash player was used by QtWebEngine, while in your original code, flash player was not used.

                    1. During Loading this web page , the browser makes many requests like this
                      http://i.stack.imgur.com/shSOu.png
                      now I need a certain request url (e.g.starts with 'http://api.le.com/mms/out/video/playJson?') during the Loading process ,the data needed to replicate the request url has been encrypted , so I resort for help to some browser like tools to get the url directly rather than figure out the encryption algorithm of the data within the url(the latter way is often more difficult or nearly impossible), while QtWebEngine provides the necessary tools, this is reason why I choose to use Qt in my project, and if I get the url this way, then I plane to return the url to the caller to get the response data of the url.
                      The main reason why I want to put this piece of code at server side is that I found it is error prone when packaging PyQt5 program involved with QtWebEngine into executables, so I turn to think about putting the code involved with QtWebEngine at the server side to get rid of the packaging problem .

                    2. If my program doesn’t found the target url until QWebEnginePage loadFinished,I think it is ok just to return None to the caller .
                      As for the program design ,I want to make the object created during the first time running being reusable as much as possible for easing the creation time consuming. I think using the signal/slot mechanism could help achieve this object-reusable goal.

                    jazzycamelJ 1 Reply Last reply
                    0
                    • R redstoneleo

                      @jazzycamel

                      1.Once I changed

                      url = "http://www.le.com/ptv/vplay/1417484.html"
                      interceptUrl = 'http://api.le.com/mms/out/video/playJson?'
                      

                      in your code, then the program crashes during running , tested on Win7 32bit. What I am sure is this time the flash player was used by QtWebEngine, while in your original code, flash player was not used.

                      1. During Loading this web page , the browser makes many requests like this
                        http://i.stack.imgur.com/shSOu.png
                        now I need a certain request url (e.g.starts with 'http://api.le.com/mms/out/video/playJson?') during the Loading process ,the data needed to replicate the request url has been encrypted , so I resort for help to some browser like tools to get the url directly rather than figure out the encryption algorithm of the data within the url(the latter way is often more difficult or nearly impossible), while QtWebEngine provides the necessary tools, this is reason why I choose to use Qt in my project, and if I get the url this way, then I plane to return the url to the caller to get the response data of the url.
                        The main reason why I want to put this piece of code at server side is that I found it is error prone when packaging PyQt5 program involved with QtWebEngine into executables, so I turn to think about putting the code involved with QtWebEngine at the server side to get rid of the packaging problem .

                      2. If my program doesn’t found the target url until QWebEnginePage loadFinished,I think it is ok just to return None to the caller .
                        As for the program design ,I want to make the object created during the first time running being reusable as much as possible for easing the creation time consuming. I think using the signal/slot mechanism could help achieve this object-reusable goal.

                      jazzycamelJ Offline
                      jazzycamelJ Offline
                      jazzycamel
                      wrote on last edited by jazzycamel
                      #11

                      @redstoneleo

                      1. I'm using a Macbook Pro (OSX 10.11.4, El Capitan). It doesn't crash on mine with your new URLs, but it doesn't find the intercept URL either... I'm not sure how/if QtWebEngine handles Flash or if the implementation/plugin used is platform specific, sorry.

                      2. The complexity of your use case was not evident from the example you gave, so maybe a simple python builtin solution won't be enough.

                      3. a) My point was not that returning None if your URL isn't found was a problem (that's what my example does after all), it was that in your original example the program would never have returned as the only place the event loop was stopped (qApp.quit()) was in the conditional block handling the intercept URL.
                        b) The problem of keeping the objects alive is that once QApplication.exec_() is called, it blocks, and the only way to release it is to quit it. You need to call exec_() for the event loop to run. The obvious answer would normally be to run this in a thread, but you can't create GUI/Widgets objects outside of the main thread...

                      As a general point, you might do better looking at some of the web scraping/crawling libraries out there (Scrapy for example).

                      For the avoidance of doubt:

                      1. All my code samples (C++ or Python) are tested before posting
                      2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
                      R 1 Reply Last reply
                      0
                      • jazzycamelJ jazzycamel

                        @redstoneleo

                        1. I'm using a Macbook Pro (OSX 10.11.4, El Capitan). It doesn't crash on mine with your new URLs, but it doesn't find the intercept URL either... I'm not sure how/if QtWebEngine handles Flash or if the implementation/plugin used is platform specific, sorry.

                        2. The complexity of your use case was not evident from the example you gave, so maybe a simple python builtin solution won't be enough.

                        3. a) My point was not that returning None if your URL isn't found was a problem (that's what my example does after all), it was that in your original example the program would never have returned as the only place the event loop was stopped (qApp.quit()) was in the conditional block handling the intercept URL.
                          b) The problem of keeping the objects alive is that once QApplication.exec_() is called, it blocks, and the only way to release it is to quit it. You need to call exec_() for the event loop to run. The obvious answer would normally be to run this in a thread, but you can't create GUI/Widgets objects outside of the main thread...

                        As a general point, you might do better looking at some of the web scraping/crawling libraries out there (Scrapy for example).

                        R Offline
                        R Offline
                        redstoneleo
                        wrote on last edited by
                        #12

                        @jazzycamel

                        Thanks for reply!

                        1 . Sorry , I’ve forgot to tell you that you should have Flash Player installed in

                        /Library/Internet Plug-Ins/PepperFlashPlayer/PepperFlashPlayer.plugin
                        

                        On OS X according to the doc before you test the program with my new URLs.

                        2 . If the URL I want wasn't found , then I agree with your solution

                        QWebEnginePage(loadFinished=qApp.quit)
                        

                        to quit the event loop so the function can return .
                        3. I am also considering using Chrome extension to solve the problem .

                        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