Pobieranie strony WWW/HTML z sieci za pomocą Qt
-
Pewnie wielu z Was zastanawiało się jak w prosty sposób można pobrać zawartość sieci, konkretnie stronę web za pomocą Qt i wykorzystać ją do własnych celów. Właśnie sam się nad tym zastanawiam.
Podobno można wykorzystać klasę QNetworkAccessManager.
Jeśli uda mi się coś napisać to na pewno zamieszczę tu rozwiązanie. Jeśli zaś Wy już macie swoje rozwiązania na ten problem zapraszam do dyskusji. ;) -
Cześć tutaj na forum masz opisane w jaki sposób powinno być to wykonane: https://forum.qt.io/topic/3352/qnetworkaccessmanager-doesn-t-download-whole-web-page
W skrócie dość prosto korzystasz z metody QNetworkAccesManager::get() i swoim slotem podpinasz się pod sygnał: QNetworkAccesManager::finished() następnie odczytujesz dane poprzez readAll() -
Niestety mnie się nie udaje za pomocą sygnałów, QNetworkAccesManager, QNetworkReply i QNetworkRequest. Mój kod wygląda tak... ale nie ma żadnej reakcji.
qDebug() << "Pobieranie strony WWW"; QNetworkAccessManager manager; QNetworkReply *odpowiedz = NULL; QNetworkRequest request; //request.setRawHeader("User-Agent", "MyOwnBrowser 1.0"); request.setHeader(QNetworkRequest::UserAgentHeader, "Cos 1.1"); request.setPriority( QNetworkRequest::HighPriority ); request.setUrl( QUrl( "http://www.theravenlords.za.pl" )); //"http://old.radiopolska.pl/wykaz/galeria.php?l=A#0") ); odpowiedz = manager.get( request ); connect( odpowiedz, SIGNAL(finished()), this, SLOT( slot_ReplyFinished() )); connect( odpowiedz, SIGNAL(readyRead()), this, SLOT(slot_ReadyRead())); connect( odpowiedz, SIGNAL( error(QNetworkReply::NetworkError) ), this, SLOT( slot_blad() )); connect( odpowiedz, SIGNAL( sslErrors(QList<QSslError>)), this, SLOT( slot_SslBlad() ));
Oczywiście slot_ReplyFinished() , slot_ReadyRead(), slot_blad(), slot_SslBlad() są moimi, przeze mnie zaprogramowanymi slotami. Wyglądało by na to, że sygnał finished() emitowany przez QNetworkReply nigdy nie jest emitowany.
Co Wy na to ? :)
-
O właśnie, wielgaśne dzięki. :)
Dziś w dzień jak siedziałem nad tym zagadnieniem na korytarzu mojej uczelni doszedłem do tego rozwiązania, tylko tyle, że nie wiedziałem, że się to nazywa "czasem życia obiektu".
Możesz mi wytłumaczyć dla czego ma to wpływ?
Bo ja zrozumiałem, że jakoś, z tego powodu nie jest wywoływany sygnał finished() przez QNetworkAccessManager.W przypadku kiedy pisałem:
QNetworkAccessManager manager; connect(&manager, SIGNAL( finished() ), this, SLOT( slot_zakonczony() ) );
kod zdawał się nie działać, zawartość strony nie była pobierana...
a w przypadku, kiedy robiłem tak jak zapisałeś poprzez wskaźnik i new kod działał. -
W telegraficznym skrócie i maksymalnej prostocie to tworząc obiekt w jakiejś metodzie w taki sposób:
QNetworkAccessManager manager;
zostaje on niszczony po zakończeniu działania metody w której został stworzony. W związku z tym, że QNetworkAccessManager działa asynchronicznie i jego obiekt zostanie zniszczony przed zakończeniem requesta to sygnał nie zostanie wyemitowany.Tworząc obiekt przez operator 'new' nie zostanie on zniszczony po wyjściu z metody, lecz musisz pamiętać by samemu usunąć go w momencie gdy nie będzie Ci już potrzebny używając
delete
lub (zalecany dla QObjectów)deleteLater()
.
Jeżeli tworząc obiekt przez operator new podasz mu w konstruktorze parenta to zostanie on zniszczony wraz z swoim rodzicem (gdybyś go sam nie usunął). Jeżeli nie usuniesz obiektu będziesz miał doczynienia z wyciekiem pamięci.
W ramach nauki możesz stworzyć sobie dowolny QObject i podpiąć się slotem pod sygnałdestroyed()
wtedy zobaczysz kiedy jest on niszczony. :)
Pozdrawiam. -
Ja nie mowie za bardzo po polsku, jestem z niemec. Ale moze zrozumiece co pisze :) Use QEventLoop:
QNetworkAccessManager nam; // Request QNetworkRequest request; request.setUrl(QUrl("http://www.google.de")); QNetworkReply *reply = nam.get(request); // Wait for server answer QEventLoop loop; connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); // Read resoinse QByteArray response = reply->readAll(); // response == website data
-
@turaz
Dzięki wielkie Turaz, rozjaśniłeś mi sprawę. :) W sumie masz rację, wcześniej nie dostrzegałem problemu długości życia zmiennych i wysyłanych przez nie sygnałów, teraz to widzę. :)
Żeby connect() zadziałał utworzony prze zemnie obiekt musi istnieć po zakończeniu funkcji, a jak deklaruje go zwyczajnie/niedynamicznie to obiekt przestaje istnieć po zakończeniu funkcji w której jest tworzony. W sumie nawet zmienna - wskaźnik do utworzonego obiektu za pomocą operatora new też przestaje istnieć, więc pewnie wewnątrz funckji connect() robiona jest kopia wskaźnika... hmm... w sumie zawsze to tak działało. :)
Dzięki wielkie za pomoc, zrobiłem sobie przy okazji praktyczne powtórzenie materiału. :) -
@cybercatalyst
Rozumiemy, nie martw się. :)
Nigdy, jak dotąd nie korzystałem z klasy QEventLoop. Dzięki za podsunięcie pomysłu, kolejnego sposobu na rozwiązanie tego problemu. :)[ENG] If you don't understand what I wrote, I can rewrite this at english. :) I suppose you speak english. :)