Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [Qt] Parsowanie dokumentu www
peter13135
post 4.08.2012, 15:30:02
Post #1





Grupa: Zarejestrowani
Postów: 1 447
Pomógł: 191
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Mam taki kodzik :
Kod
    QWebPage page;
    QWebFrame * frame = page.mainFrame();
    frame->setHtml(str);
    QWebElement document = frame->documentElement();
    QWebElementCollection tables = document.findAll(".table");
    int numTables = tables.count();
    qDebug() << numTables;
    return;


Pod zmienną str znajduje się źródło tej strony : http://panoramafirm.pl/szukaj/mazowieckie,...wa/firmy,1.html

Chcę pobrać ilość elementów o klasie table. Niestety program podaje, że tych elementów jest 0. Podczas gdy w rzczywistości jest ich 15.

Gdy zamiast ".table" dam "a", to zwraca mi to 17, czyli jakieś linki znajduje ale chyba jest ich ciut za mało.

W czym może być problem ?

Wszystkie tabelki są w divie o klasie "results" <- tego diva nie mogę pobrać.
Mogę za to pobrać div o nazwię 'socialIcons right" ale nie w całości - na nim program kończy parsowanie.

Ten post edytował peter13135 4.08.2012, 16:07:05


--------------------
:)
Go to the top of the page
+Quote Post
everth
post 6.08.2012, 12:51:01
Post #2





Grupa: Zarejestrowani
Postów: 782
Pomógł: 153
Dołączył: 21.07.2010

Ostrzeżenie: (0%)
-----


Dawno nie miałem już z Qt styczności ale spróbuj zobaczyć co wyrzuca metoda QWebFrame::toHtml. Webkit wykonuje Javascript - możliwe więc że te klasy zostają usunięte w trakcie przetwarzania (albo to zabezpieczenie przed zewnętrznymi skanerami). Ostatecznie zostaje struktura dokumentu HTML - może jest tak zwalona że nie przechodzi (ale to mało prawdopodobne).


--------------------
Już mi się ani wiedzieć, ani tym bardziej myśleć nie chce.
[Think different]!
Go to the top of the page
+Quote Post
cojack
post 6.08.2012, 13:30:49
Post #3





Grupa: Zarejestrowani
Postów: 898
Pomógł: 80
Dołączył: 31.05.2008

Ostrzeżenie: (20%)
X----


Pobierz treść najprościej jak się da, wrzuć do DOM'a prze-iteruj jak xml'a, wyciąg i zlicz dane. Amen.


--------------------
cojack blog - mój blog (na jakiś czas off).
"jak czegoś nie wiem, to nie myślę że wiem" - moja domena
Go to the top of the page
+Quote Post
peter13135
post 6.08.2012, 19:20:43
Post #4





Grupa: Zarejestrowani
Postów: 1 447
Pomógł: 191
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Kod
    frame->setHtml(str);
    qDebug() << frame->toHtml();



Dziwna sprawa. Ostatnie linijki tego "debuga" to:
Kod
<div class="socialIcons right"> <!-- AddThis Button BEGIN --> <span class="shareItText left">Podziel się wynikami</span> <div class="addthis_toolbox addthis_default_style"> <a class="addthis_button_facebook" title="dodaj do facebook'a"></a> <a class="addthis_button_google" title="dodaj do google'a"></a> <a class="addthis_button_compact" title="dodaj do innych"></a> </div> <script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=xa-4fe954876fcacb33"></script></div></div></div></div></div></div></div></body></html>"


Za tym divem (socialIcons) powinien być jeden pusty div z klasą "clear" i potem div reslults z tabelkami.





--------------------
:)
Go to the top of the page
+Quote Post
rzymek01
post 6.08.2012, 21:38:53
Post #5





Grupa: Zarejestrowani
Postów: 592
Pomógł: 62
Dołączył: 3.08.2006

Ostrzeżenie: (0%)
-----


ten kod, który podałeś znajduje się z źródle strony, sprawdź w firebugu,
co prawda powinien byc jeszcze ten clear i result, ale nie wiem z jakiej strony jest ten wyciąg smile.gif


--------------------
:]
Go to the top of the page
+Quote Post
peter13135
post 7.08.2012, 08:28:46
Post #6





Grupa: Zarejestrowani
Postów: 1 447
Pomógł: 191
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Nie wiem o co Ci chodzi.
Dałem linka w pierwszym poście, więc chyba powinieneś wiedzieć skąd ten wyciąg wink.gif.
Po divie socialicons powinien być div clear i div results a w nim interesujące mnie dane. Następnie jakieś tam footerki.

Niestety metoda toHtml zwraca mi nie takie źródło, jakie jest w krzeczywistości, bo już po divie socialicons zamykane są divy, body i html.


--------------------
:)
Go to the top of the page
+Quote Post
everth
post 7.08.2012, 11:04:53
Post #7





Grupa: Zarejestrowani
Postów: 782
Pomógł: 153
Dołączył: 21.07.2010

Ostrzeżenie: (0%)
-----


Znalezione w necie:
  1. webView->settings()->setAttribute(QWebSettings::JavascriptEnabled, false);

Wyłącza parsowanie JS. Jeśli to nie pomoże to spróbuj metodę cojacka


--------------------
Już mi się ani wiedzieć, ani tym bardziej myśleć nie chce.
[Think different]!
Go to the top of the page
+Quote Post
peter13135
post 7.08.2012, 17:10:50
Post #8





Grupa: Zarejestrowani
Postów: 1 447
Pomógł: 191
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Zrobiłem inaczej. Za pomocą regexpa znalazłem pozycję (czyli od którego znaku w stringu zaczyna się ten div) obciąłem to co było wcześniej za pomocą QString::remove(), to coś wrzuciłem do QWebFrame i teraz mi hula wink.gif

Pewnie wasze sposoby są lepsze, ale póki co mój sposób działa wink.gif

Dzięki za odpowiedź, idą pochwały.


--------------------
:)
Go to the top of the page
+Quote Post
katsuo
post 8.08.2012, 02:15:39
Post #9





Grupa: Zarejestrowani
Postów: 18
Pomógł: 1
Dołączył: 1.05.2007

Ostrzeżenie: (0%)
-----


Całe api webkita jest po to, żebyś nie musiał korzystać z regexpa do takich rzeczy. W tym przypadku table.table da ten sam wynik co .table, ale.. Te ostatnie linijki debuga- gdzie wykonujesz ten kod? Ja pozwoliłbym webkitowi ściągnąć stronę i coś podobnego tego co dałeś wykonał pod sygnałem load_finished;>
Niby pytanie o banał, ale nie takie rzeczy już na forach wychodziły.
Go to the top of the page
+Quote Post
peter13135
post 8.08.2012, 16:39:56
Post #10





Grupa: Zarejestrowani
Postów: 1 447
Pomógł: 191
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Cytat
Całe api webkita jest po to, żebyś nie musiał korzystać z regexpa do takich rzeczy.

Do pewnego czasu mój program działał bez regexpa (kod z pierwszego postu działał) ale ponieważ od pewnego czasu mój program przestał działać (kończył parsowanie na pewnym kodzie js), to za pomocą regexpa wyciąłem sobie kod od interesującego mnie diva, do końca dokumentu (czyli </html> ). I ten "ucięty" html wrzuciłem tak samo jak w pierwszym poście i działa wink.gif
Daj mi działający kod nie wymagający regexpa, to chętnie użyję.
Cytat
W tym przypadku table.table da ten sam wynik co .table

Napławde ?
Cytat
ale.. Te ostatnie linijki debuga- gdzie wykonujesz ten kod? Ja pozwoliłbym webkitowi ściągnąć stronę i coś podobnego tego co dałeś wykonał pod sygnałem load_finished;>

Nie rozumiem.


--------------------
:)
Go to the top of the page
+Quote Post
katsuo
post 8.08.2012, 18:36:53
Post #11





Grupa: Zarejestrowani
Postów: 18
Pomógł: 1
Dołączył: 1.05.2007

Ostrzeżenie: (0%)
-----


Zrobiłem po swojemu, wklejając kod gdzie trzeba. Debug zwrócił dwie liczby:
0
25
Na szybko wstawiłem ramkę (ui->webView), kod:
MainWindow.h
Kod
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QWebElementCollection>
#include <QWebFrame>
#include <QDebug>
namespace Ui {
class MainWindow;
}
PS: Bez okien też jakoś się dało, ale nie pamiętam:P
class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    
private slots:
    void on_webView_loadFinished(bool arg1);

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H


mainwindow.cpp
Kod
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QUrl url("http://panoramafirm.pl/szukaj/mazowieckie,warszawa/firmy,1.html");
    ui->webView->setUrl(url);
    ui->webView->load(url);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_webView_loadFinished(bool arg1)
{
    QWebPage* page = ui->webView->page();
   QWebFrame * frame = page->mainFrame();
   QWebElement document = frame->documentElement();
     QWebElementCollection tables = document.findAll(".table");
     int numTables = tables.count();
     qDebug() << numTables;
}


Ten post edytował katsuo 8.08.2012, 18:41:48
Go to the top of the page
+Quote Post
everth
post 8.08.2012, 20:00:02
Post #12





Grupa: Zarejestrowani
Postów: 782
Pomógł: 153
Dołączył: 21.07.2010

Ostrzeżenie: (0%)
-----


@katsuo prawdopodobnie ma rację. Jeśli QWebFrame zachowuje się analogicznie jak UIWebView w iOSie to asynchroniczne ładowanie zawartości mogło powodować twój błąd. Twoje regexowanie mogło to jedynie zamaskować (poprzez opóźnienie wywołania findAll() ). Wszystko to przy założeniu że QWebFrame rzeczywiście zachowuje się asynchronicznie wink.gif


--------------------
Już mi się ani wiedzieć, ani tym bardziej myśleć nie chce.
[Think different]!
Go to the top of the page
+Quote Post
peter13135
post 8.08.2012, 20:30:35
Post #13





Grupa: Zarejestrowani
Postów: 1 447
Pomógł: 191
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Jak to debug zwrócił 0 i 25 ?
Tabelek o tej klasie jest 15 tongue.gif

Nie bardzo wiem o co wam chodzi wink.gif Mogę prosić o jakiś prostsze wyjaśnienie ? Nie roumiem jak ten regexp ma maskować błąd.


--------------------
:)
Go to the top of the page
+Quote Post
everth
post 8.08.2012, 21:08:07
Post #14





Grupa: Zarejestrowani
Postów: 782
Pomógł: 153
Dołączył: 21.07.2010

Ostrzeżenie: (0%)
-----


Jeśli moje przypuszczenie jest poprawne - metoda setHtml instruuje QWebView żeby zaczął parsować HTML. Ale on to robi asynchronicznie więc reszta kodu spokojnie się wykonuje, nawet jeśli drzewo DOM nie zostało do końca zbudowane. UIWebView w iOSie udostępnia metodę delegata (coś ala slot w Qt) żeby powiadomić nas kiedy jest on gotowy do użycia. Nie rozumiem do końca kodu @katsuo ale przypuszczam że QWebFrame udostępnia jakiś sygnał informujący o załadowaniu się htmla w który można się wpiąć.

Co do regexpa to wolne przypuszczenie. Możliwe że kiedy ty dokonujesz manipulacji regexem te parę ms wystarcza żeby drzewo DOM zostało załadowane.

* Wydaje mi się dziwne żeby samo obcięcie końcówki taga magicznie "naprawiło" HTMLa - jest niby taka możliwość, ale wtedy dokument sypałby się wszędzie.

@EDIT
Z dokumentacji Qt
Cytat
ExternalThe html is loaded immediately; external objects are loaded asynchronously.

Sam już nie wiem smile.gif niby drzewo DOM jest ładowane od razu a tylko reszta dociągana. Chyba dokument jest generowany JSem.

Ten post edytował everth 8.08.2012, 21:12:35


--------------------
Już mi się ani wiedzieć, ani tym bardziej myśleć nie chce.
[Think different]!
Go to the top of the page
+Quote Post
katsuo
post 8.08.2012, 21:24:12
Post #15





Grupa: Zarejestrowani
Postów: 18
Pomógł: 1
Dołączył: 1.05.2007

Ostrzeżenie: (0%)
-----


1. Następnym razem dołączaj cały kod, nie wróżymy z fusów
2. Poczytaj o sygnałach, slotach i event driven programming.
Wczytaj się w dokumentację samego qt- w pewnym momencie myślałem, że wklejasz html do qLineEdit który ma limit długości(patrz pkt.1)
@everth: Mimo, że dołączone są biblioteki jquery do strony, tabelki są dostępne bez js- kolega coś skopał, i nie wiadomo co(pkt. 1)
Go to the top of the page
+Quote Post
peter13135
post 8.08.2012, 21:46:13
Post #16





Grupa: Zarejestrowani
Postów: 1 447
Pomógł: 191
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


No dobra, więc przerobiłem swój kodzik na taki :

to metoda która się odpala wtedy, gdy dokument html został zassany i zapisany do zmiennej str (QString)
Kod
void Widget::httpFinished(){
    qDebug() << "httpFinished()";

    QWebPage page;
    frame = page.mainFrame();
    frame->setHtml(str);//jak debuguje str, to dostaje taki dokument html jak w oryginale (czyli jest ok)
    connect(frame, SIGNAL(loadFinished(bool)), this, SLOT(htmlParsed()));//gdy skończy się "parsowanie" dokumentu html, odpalam slot, który pobierze interesujące mnie informacje

}


Kod
void Widget::htmlParsed()
{

    QWebElement document = frame->documentElement();
    QWebElementCollection tables = document.findAll("table.table");
    int num_tables = tables.count();//to ma oczywiście wartość 0 (czyli źle);)
    qDebug() << frame->toHtml();//to wyświetla mi "niepełny" kod html, który kończy się na któryś tam divie. To co mnie interesuje nie zawiera się w tym kodzie.
    return;
//reszta kodu
}


Ale nie hula.


--------------------
:)
Go to the top of the page
+Quote Post
katsuo
post 8.08.2012, 21:51:55
Post #17





Grupa: Zarejestrowani
Postów: 18
Pomógł: 1
Dołączył: 1.05.2007

Ostrzeżenie: (0%)
-----


spakuj cały projekt i wyślij na jakiś (lekki)hosting, na prawdę będzie łatwiej.
Go to the top of the page
+Quote Post
peter13135
post 9.08.2012, 21:46:09
Post #18





Grupa: Zarejestrowani
Postów: 1 447
Pomógł: 191
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


http://www.sendspace.pl/file/b9a852801bddf23ea604782
Wywaliłem całe gui i inne rzeczy, żebyś nie musiał zbyt wiele szukać wink.gif
edit://
Co tak umilkłeś ? tongue.gif Nie chcesz mi już pomóc ? sad.gif
edit://
Zrobiłem Twoją metodą, tzn nie łąduję za pomocą QNetworkManagera, tylko za pomocą QWebPage i teraz działa. Nie wiem tylko czemu tak wolno. I nadal nie wiem czemu sposób z użyciem setHtml() nie działa.

Pozwolę nieco skomentować Twój wcześniejszy post.
Cytat
1. Następnym razem dołączaj cały kod, nie wróżymy z fusów

Jeśli by problemem miała być asynchrnicznicznie działąjąca klasa (czy o czym tam mówiłeś), to w moim kodzie wyraźnie widać, że od razu po wywołaniu setHtml, "parsuję" cały dokument.
Poza tym, tak się składa, że błąd jest właśnie gdzieś w tym kodzie, który dałem w pierwszym poście.
Cytat
2. Poczytaj o sygnałach, slotach i event driven programming.

Po co ?
Cytat
Wczytaj się w dokumentację samego qt- w pewnym momencie myślałem, że wklejasz html do qLineEdit który ma limit długości(patrz pkt.1)

Jak się ma początek tego zdania, do drugiej części ? Jak się ma moje "wczytywanie w dokumentację Qt" do tego, że myślałeś, że wklejam html do QLineEdit ?
Co zasugerowało, że wklejam html do QLineEdit ? Przecież na podstawie mojego kodu widać bardzo przejrzyście, instancją jakiej klasy jest każda ze zmniennych, bo właśnie w tej funkcji są one deklarowane. Może poza zmienną str, ale po nazwie możesz się domyśleć, że to QString, oraz po tym, że metoda QWebFrame::setHtml() przyjmuje parametr QString (a nie żadne QLineEdit).

Ten post edytował peter13135 9.08.2012, 22:16:32


--------------------
:)
Go to the top of the page
+Quote Post
zegarek84
post 10.08.2012, 00:13:30
Post #19





Grupa: Zarejestrowani
Postów: 1 332
Pomógł: 294
Dołączył: 12.10.2008
Skąd: Olkusz

Ostrzeżenie: (0%)
-----


popisz trochę więcej w JavaScript - to Ci powinno ułatwić programowanie zdarzeniowe... dodatkowo drzewo DOM w przeglądarkach zawsze renderowało się asynchronicznie (stąd były specjalnie tworzone metody pokroju .ready np. w jQuery)...
Cytat(peter13135 @ 9.08.2012, 22:46:09 ) *
edit://
Zrobiłem Twoją metodą, tzn nie łąduję za pomocą QNetworkManagera, tylko za pomocą QWebPage i teraz działa. Nie wiem tylko czemu tak wolno. I nadal nie wiem czemu sposób z użyciem setHtml() nie działa.

wyłącz obrazki i wyłącz wykonywanie JavaScript skoro to Ci nie potrzebne... w Twoim kodzie niewiele zmieniłem i działa - zdarzenie jest przypisane do QWebPage, więc musi on trochę dłużej istnieć itd... tabel z tą klasą znajduje 25...
  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3.  
  4. #include <QWidget>
  5. #include <QDebug>
  6. #include <QUrl>
  7. #include <QtNetwork>
  8. #include <QTextStream>
  9. #include <QWebElement>
  10. #include <QWebFrame>
  11. #include <QWebPage>
  12. #include <QWebView>
  13. #include <QtGui>
  14. #include <QRegExp>
  15. #include <QtXml>
  16.  
  17. class Widget : public QWidget
  18. {
  19. Q_OBJECT
  20. public:
  21. explicit Widget(QWidget *parent = 0);
  22. void startRequest(QUrl url);
  23.  
  24. private slots:
  25.  
  26. void httpFinished();
  27. void httpReadyRead();
  28. void htmlLoaded();
  29. private :
  30. QNetworkAccessManager qnam;
  31. QNetworkReply *reply;
  32. QString str;
  33. QPointer<QWebPage> page;
  34. QWebFrame * frame;
  35. //elementy gui
  36. };
  37.  
  38. #endif // WIDGET_H

  1. #include "widget.h"
  2.  
  3. Widget::Widget(QWidget *parent) :
  4. QWidget(parent),
  5. page(new QWebPage)
  6. {
  7. QUrl url("http://panoramafirm.pl/szukaj/mazowieckie,warszawa/firmy,1.html") ;
  8. startRequest(url);
  9. }
  10.  
  11.  
  12. void Widget::startRequest(QUrl url)
  13. {
  14.  
  15. str="";
  16. reply = qnam.get(QNetworkRequest(url));
  17.  
  18. connect(reply, SIGNAL(finished()),
  19. this, SLOT(httpFinished()));
  20. connect(reply, SIGNAL(readyRead()),
  21. this, SLOT(httpReadyRead()));
  22. }
  23.  
  24.  
  25.  
  26. void Widget::httpReadyRead()
  27. {
  28. str.append(QString::fromUtf8(reply->readAll()));
  29.  
  30. }
  31.  
  32. void Widget::httpFinished()
  33. {
  34. // QWebPage page;
  35. QWebSettings* s = page->settings();
  36. s->setAttribute(QWebSettings::AutoLoadImages, FALSE);
  37. s->setAttribute(QWebSettings::JavascriptEnabled, FALSE);
  38. frame = page->mainFrame();
  39. // qDebug() << 333333333;
  40. connect(page, SIGNAL(loadFinished(bool)), this, SLOT(htmlLoaded()));
  41. frame->setHtml(str);
  42. }
  43.  
  44. void Widget::htmlLoaded()
  45. {
  46. QWebElement document = frame->documentElement();
  47. QWebElementCollection tables = document.findAll("table.table");
  48. int num_tables = tables.count();
  49. qDebug() << num_tables;
  50. }


Ten post edytował zegarek84 10.08.2012, 00:30:10


--------------------
Jeśli twoja ręka rusza do przodu powstrzymaj swój gniew; gdy wyprzedza cię twój gniew - wycofaj rękę.

Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 19.04.2024 - 04:29