为请求的网页接收多个loadFinished信号

时间:2013-02-08 19:51:17

标签: c++ qt webkit qt5 qwebpage

当我尝试加载loadFinished时,我收到多个QWebPage信号,而我不确定导致问题的原因。还有一些其他问题似乎暗示了同样的问题,但解决方案并不适用于我:

在第一个问题中,答案是仅将信号连接到插槽一次,“但我已经这样做了。第二个问题的答案表明我应该连接到帧的loadFinished信号,但我只是完成后不要获得必要的数据。

我尝试加载多个页面:

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

    QList<QUrl> urls;
    urls.append(QUrl("http://www.useragentstring.com/pages/Chrome/"));
    urls.append(QUrl("http://www.useragentstring.com/pages/Firefox/"));
    urls.append(QUrl("http://www.useragentstring.com/pages/Opera/"));
    urls.append(QUrl("http://www.useragentstring.com/pages/Internet Explorer/"));
    urls.append(QUrl("http://www.useragentstring.com/pages/Safari/"));

    foreach(QUrl url, urls)
    {
        UA* ua = new UA();
        QWebPage* page = new QWebPage();
        //QObject::connect(page, SIGNAL(loadFinished(bool)), ua, SLOT(pageLoadFinished(bool)));
        QObject::connect(page->mainFrame(), SIGNAL(loadFinished(bool)), ua, SLOT(frameLoadFinished(bool)));
        // Load the page
        page->mainFrame()->load(url);
    }

    return app.exec();
}

处理信号的类看起来像这样:

class UA:public QObject
{
    Q_OBJECT
private:
    int _numPageLoadSignals;
    int _numFrameLoadSignals
public:
    UA()
    {
        _numPageLoadSignals = 0;
        _numFrameLoadSignals = 0;
    }
    ~UA(){}
public slots:
    void pageLoadFinished(bool ok)
    {
        _numPageLoadSignals++;

        QWebPage * page = qobject_cast<QWebPage *>(sender());
        if(ok && page)
        {    
            qDebug() << _numPageLoadSignals << " loads " 
                << page->mainFrame()->documentElement().findAll("div#liste ul li a").count()
                << " elements found on: " << page->mainFrame()->requestedUrl().toString();
        }
    }

    void frameLoadFinished(bool ok)
    {
        _numFrameLoadSignals++;
        QWebFrame * frame = qobject_cast<QWebFrame *>(sender());
        if(ok && frame)
        {
            qDebug() << _numFrameLoadSignals << " loads " 
                <<  frame->documentElement().findAll("div#liste ul li a").count()
                << " elements found on: " << frame->requestedUrl().toString();
        }
    }
};

以下是仅连接到帧loadFinished信号的结果:

1  loads  0  elements found on:  "http://www.useragentstring.com/pages/Safari/"
1  loads  0  elements found on:  "http://www.useragentstring.com/pages/Chrome/"
1  loads  0  elements found on:  "http://www.useragentstring.com/pages/Opera/"
1  loads  0  elements found on:  "http://www.useragentstring.com/pages/Firefox/"
1  loads  241  elements found on:  "http://www.useragentstring.com/pages/Internet Explorer/"

以下是我连接到网页的loadFinished信号时的结果:

1  loads  0  elements found on:  "http://www.useragentstring.com/pages/Safari/"
1  loads  0  elements found on:  "http://www.useragentstring.com/pages/Chrome/"
1  loads  0  elements found on:  "http://www.useragentstring.com/pages/Firefox/"
1  loads  0  elements found on:  "http://www.useragentstring.com/pages/Internet Explorer/"
2  loads  576  elements found on:  "http://www.useragentstring.com/pages/Safari/"
2  loads  782  elements found on:  "http://www.useragentstring.com/pages/Chrome/"
2  loads  241  elements found on:  "http://www.useragentstring.com/pages/Internet Explorer/"
2  loads  1946  elements found on:  "http://www.useragentstring.com/pages/Firefox/"
3  loads  241  elements found on:  "http://www.useragentstring.com/pages/Internet Explorer/"
3  loads  1946  elements found on:  "http://www.useragentstring.com/pages/Firefox/"
3  loads  782  elements found on:  "http://www.useragentstring.com/pages/Chrome/"
1  loads  964  elements found on:  "http://www.useragentstring.com/pages/Opera/"
3  loads  576  elements found on:  "http://www.useragentstring.com/pages/Safari/"

我不明白这种行为,为什么有时候我会得到相关内容,有时候我却没有。如果我连接到页面的loadFinished信号,那么我最终会获得内容,但我不知道它何时会实际发生。 如何知道我的网页何时实际加载完毕?

更新

我假设我的大部分内容都会在不到3秒的时间内到达,所以我想出了一个解决方法:我设置一个计时器事件,在第一个UA::loadFinished后3秒发出信号loadFinishedQWebPage收到1}}信号。这不是很漂亮,也不是很有效,但它适用于这种情况。

2 个答案:

答案 0 :(得分:1)

引用QWebPage文档:

  

最后,在完全加载页面内容时发出loadFinished()信号,与脚本执行或页面呈现无关。

抓住的是最后一句话。因此,以下主题中的某些人指出了我认为的问题。

Why is QWebView.loadFinished called several times on some sites e.g. youtube?

我一直在努力编写一个爬虫程序,它涉及在幕后使用javascript加载内容的页面。多个loadFinished是一个问题(我希望它能在一切安定下来之后触发。)但是我注意到,基本的问题是,即使在最后一个loadFinished激活一个插槽后,网页内容仍然无法呈现/准备。

所以我尝试了很多QWebPage类的信号,看看在loadFinished信号之后是否一直触发它们。

找到一个:repaintRequested(QRect)

我不知道这是否一直有效。但是,如果任何内容影响网页的外观,我相信必须调用此信号才能使页面完整。我既不显示页面,也不使用视图小部件,但信号始终被触发。唯一的问题是它被多次触发。 (比loadFinished更常见),因此您需要检查mainFrame-&gt; requestedUrl()是否与mainFrame-&gt; url()相同,并且您感兴趣的内容的关键字是否存在。 (特别是如果你像我一样重复使用webPage。后续请求会更改requestedUrl,而之前加载的mainFrame内容仍然存在。那里有一些持久性)

减少要检查的信号数量的技巧可能是仅在从QWebPage接收到loadFinished信号后才连接repaintRequested(并且可能检查额外的条件)。

这可能无法解决无限的嵌套加载,因为人们不知道是否有任何信号是最后一个,但如果您正在搜索内容,那么在加载特定内容后必然会触发信号(我的意思是集成)进入DOM:)

答案 1 :(得分:0)

我解决了这个问题,指明死对象的内存缓存容量,换句话说,我只是使用以下命令禁用QtWebKit内存缓存:

QWebSettings::setObjectCacheCapacities(0, 0, 0);

要了解更多信息,请点击链接

http://qt-project.org/doc/qt-4.8/qwebsettings.html#setObjectCacheCapacities