threadbrain
@threadbrain

Как распарсить сайт с помощью QNetworkAccessManager?

Мне нужно найти на странице вот такой кусок, и достать ссылку на картинку
<div class="row-fluid">
            <strong>
                Скачать оригинал:
                <a href="pictures/originals/2014/Nature_Highway_in_the_mountains_082434_.jpg" class="original-link" download="pictures/originals/2014/Nature_Highway_in_the_mountains_082434_.jpg" title="Шоссе в сторону гор">Шоссе в сторону гор - 1920x1080</a>
            </strong>
        </div>


Пытался для начала хотя бы просто скачать Html страницу
void DownloadHtml::Download()
{
    manager = new QNetworkAccessManager(this);

    connect(manager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(replyFinished(QNetworkReply*)));

    manager->get(QNetworkRequest(QUrl("http://google.com")));
}
void DownloadHtml::replyFinished (QNetworkReply *reply)
{
    if(reply->error())
    {
        qDebug() << "Error!";
        qDebug() << reply->errorString();
    }
    else
    {
        QFile *file = new QFile("C:/wall/downloaded.txt");
        if(file->open(QFile::Append))
        {
            file->write(reply->readAll());
            file->flush();
            file->close();
        }
        delete file;
    }

    reply->deleteLater();
}

Но результат был таким
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.ru/?gfe_rd=cr&amp;ei=3cudVPqyMYTzwAOP5oCQCg">here</A>.
</BODY></HTML>
  • Вопрос задан
  • 5122 просмотра
Решения вопроса 1
Ну с этой частью у вас все верно. Если попробовать сделать это curl'ом получим ровно тоже самое.
@home-tower:~$ curl -i http://google.com
HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Location: http://www.google.ru/?gfe_rd=cr&ei=EPmeVPyRK6Or8wf5-IDABA
Content-Length: 258
Date: Sat, 27 Dec 2014 18:23:12 GMT
Server: GFE/2.0
Alternate-Protocol: 80:quic,p=0.002

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.ru/?gfe_rd=cr&amp;ei=EPmeVPyRK6Or8wf5-IDABA">here</A>.
</BODY></HTML>

Если вместо google.com поставить url который не возвращает редирект, то получите нужный html.
Дальше будет интересней, потому что этот html нужно парсить. У меня была такая задача не так давно.
Проблемма в том что в Qt нет легкого html парсера(не монструозного QtWebkit я имею ввиду). Есть парсеры для Xml, но они ломаются на многих страницах. Поэтому я использовал Gumbo - это реализация html парсера от гугла. Я для своего проекта оборачивал его, чтобы было более Qt'шно. Что получилось можно найти на github. Обратите внимание на тесты. Они как примеры использования, вместо документации.
Надеюсь это поможет

UPD по шагам:
1. в QtCreator создаем Subdirs Project
2. New subproject и выбираем тип приложения который вам нужен Qt Console Application например
3. В консоли переходим в папку с проектом и пишем
bumbaram@home-tower:~/Projects/htmlparsing$ git init
bumbaram@home-tower:~/Projects/htmlparsing$ git submodule add https://github.com/lagner/QGumboParser.git lib
	Cloning into 'QGumboParser'...
	remote: Counting objects: 96, done.
	remote: Total 96 (delta 0), reused 0 (delta 0)
	Unpacking objects: 100% (96/96), done.
	Checking connectivity... done.

bumbaram@home-tower:~/Projects/htmlparsing$ git submodule update --init --recursive

4. Идем в IDE, в корневом pro файле добавляем: SUBDIRS += lib/QGumboParser
5. Для приложения делаем Add Library -> Internal Library. Там все нужно уже будет выбрано. Плюс, в pro файл нужно добавить CONFIG += c++11
7. Открываем main.cpp и пишем:
#include <QCoreApplication>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <qgumbodocument.h>
#include <qgumbonode.h>


void requestFinished(QNetworkReply*);
void parseHtml(QString html);


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QNetworkAccessManager nm;
    QObject::connect(&nm, &QNetworkAccessManager::finished, requestFinished);

    nm.get(QNetworkRequest(QStringLiteral("http://toster.ru/q/168437")));

    return a.exec();
}


void requestFinished(QNetworkReply* rep) {
    if (rep->error() == QNetworkReply::NoError) {
        QByteArray rawdata = rep->readAll();
        QString html = QString::fromUtf8(rawdata);

        parseHtml(html);

    } else {
        qDebug() << "request failed: " << rep->errorString();
    }

    rep->deleteLater();
    QCoreApplication::quit();
}


void parseHtml(QString html) {
    try {
        QGumboDocument doc = QGumboDocument::parse(html);
        QGumboNode root = doc.rootNode();

        auto nodes = root.getElementsByTagName(HtmlTag::TITLE);
        for (auto& node: nodes) {
            qDebug() << "title: " << node.innerText();
        }

    } catch (...) {
        qCritical() << "smth wrong";
    }
}

Все должно работать.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы