Поиск RSS новостных сайтов

в 8:49, , рубрики: c++, Qt Software, Программирование

Покопался я ещё в своих старых и не очень проектах и нашёл одну интересную программку. Она ищет RSS ссылки новостных сайтов. Задача которая стояла — это найти как можно больше новостных RSS лент и собрать их всех в одну базу.

Когда встал вопрос о том как искать новостные сайты, пришла мысль о использовании сервиса new.google.com. От туда можно выдёргивать ссылки на новостные сайты, к тому же они постоянно добавляются и отсортированы по регионам, темам и т.д. Осталось пройтись по всем разделам news.google.com, выдернуть ссылки новостных сайтов, а затем найти все RSS каждого из них.

Сначала код. Он состоит из следующих файлов: main.cpp LinksReader.cpp LinksReader.h LinksReader.pro Sources.txt и файл который создастся автоматически и в котором сохранится результат RssLinks.txt. Вся логика содержится в файлах LinksReader.h и LinksReader.cpp, остальные файлы вспомогательные, для использования класса и компилирования проекта. Компилировал проект в с помощью компилятора g++, среда Qt creator, версия библиотек 5.1

LinksReader.h

#ifndef LINKSREADER_H
#define LINKSREADER_H

#include <QStringList>
#include <QFile>
#include <QNetworkReply>
#include <QEventLoop>
#include <QDebug>

class LinksReader: public QObject
{
    Q_OBJECT

private:
    void loadSources();
    void loadRssLinks();
    void readPage(QString url);
    void takeLinks();
    void takeRssLinks();
    void saveRssLinks();

    QNetworkAccessManager mNAManager;
    QString               mPage;
    QString               mPageUrl;
    QStringList           mSources;
    QStringList           mLinks;
    QStringList           mRssLinks;

private slots:
    void onReplyFinished(QNetworkReply *pReply);

public:
    LinksReader(QObject *pParent = 0);
    void run();
};

#endif

LinksReader.cpp

#include "LinksReader.h"

void LinksReader::loadSources()
{
    QString fileName = "Sources.txt";

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "File " << fileName << " not found";
        return;
    }

    QTextStream in(&file);

    while(!in.atEnd())
        mSources.push_back(in.readLine());

    file.close();

    qDebug() << mSources.size() << " sources loaded";
    return;
}

void LinksReader::loadRssLinks()
{
    QString fileName = "RssLinks.txt";

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    QTextStream in(&file);

    while(!in.atEnd())
        mRssLinks.push_back(in.readLine());

    file.close();

    qDebug() << mRssLinks.size() << " rss links loaded";
    return;
}

void LinksReader::readPage(QString url)
{
    mPage    = "";
    mPageUrl = url;

    mNAManager.get(QNetworkRequest(QUrl(url)));

    QEventLoop loop;
    QObject::connect(&mNAManager, SIGNAL(finished(QNetworkReply *)), &loop, SLOT(quit()));
    loop.exec();
}

void LinksReader::takeLinks()
{
    QStringList fullLinks;
    QString links  = "";

    QString beginTN    = "<link>";
    QString endTN      = "</link>";
    QString tagContent = "";

    int beginTP = 0;
    int endTP   = 0;

    while(1)
    {
        beginTP = mPage.indexOf(beginTN);
        endTP   = mPage.indexOf(endTN);
        if (beginTP == -1 || endTP == -1) break;

        tagContent = mPage.mid(beginTP + beginTN.length(), endTP - beginTP - endTN.length() + 1);

        links += tagContent;
        mPage.remove(0, endTP + endTN.length());
    }

    fullLinks = links.split("http://");
    fullLinks.removeFirst();

    for(int i = 0; i < fullLinks.size(); i++)
    {
        fullLinks[i].remove(fullLinks[i].indexOf("/"), fullLinks[i].length());
        mLinks.push_back(fullLinks[i]);
    }
}

void LinksReader::takeRssLinks()
{
    QString beginTN    = "<link";
    QString endTN      = ">";
    QString tagContent = "";

    QString beginRssString = "href="";
    QString endRssString   = " ";

    int beginTP = 0;
    int endTP   = 0;

    while(1)
    {
        beginTP = mPage.indexOf(beginTN);
        endTP   = mPage.indexOf(endTN, beginTP);
        if (beginTP == -1 || endTP == -1) break;

        beginTP += beginTN.length();
        tagContent = mPage.mid(beginTP, endTP - beginTP);

        if (tagContent.indexOf("type="application/rss+xml"") != -1)
        {
            int beginRssPos = tagContent.indexOf(beginRssString);
            int endRssPos   = tagContent.indexOf(endRssString, beginRssPos);

            beginRssPos += beginRssString.size();

            QString rssString = tagContent.mid(beginRssPos, endRssPos - beginRssPos).remove(""");

            if (rssString.size() > 0 && rssString[rssString.size() - 1] == '/')
                rssString.remove(rssString.size() - 1, 1);

            if (rssString.indexOf("http://") == -1)
                rssString.push_front(mPageUrl);

            qDebug() << rssString;
            mRssLinks.push_back(rssString);
        }

        mPage.remove(0, endTP + endTN.length());
    }
}

void LinksReader::saveRssLinks()
{
    QFile file("RssLinks.txt");
    file.open(QFile::ReadWrite);
    QTextStream in(&file);

    for(int i = 0; i < mRssLinks.size(); i++)
        in << mRssLinks[i] << "n";

    file.close();
}

void LinksReader::onReplyFinished(QNetworkReply *reply) {
    mPage += reply->readAll();
}

LinksReader::LinksReader(QObject *pParent): QObject(pParent) {
    QObject::connect(&mNAManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onReplyFinished(QNetworkReply *)));
}

void LinksReader::run()
{
    loadSources ();
    loadRssLinks();

    qDebug() << "Please wait...";

    for(int i = 0; i < mSources.size(); i++)
    {
        readPage(mSources[i]);
        takeLinks();
    }

    mLinks.removeDuplicates();

    for(int i = 0; i < mLinks.size(); i++)
    {
        readPage("http://" + mLinks[i]);
        takeRssLinks();
    }

     mRssLinks.removeDuplicates();

    saveRssLinks();

    qDebug() << "Finish";
}

main.cpp

#include <QCoreApplication>
#include "LinksReader.h"

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

    LinksReader linksReader;
    linksReader.run();

    return a.exec();
}

LinksReader.pro

QT       += core
QT       += network
QT       -= gui

TARGET = LinksReader
CONFIG   += console
CONFIG   -= app_bundle

TEMPLATE = app

SOURCES += main.cpp 
    LinksReader.cpp

HEADERS += 
    LinksReader.h

Sources.txt

http://news.google.com/news?ned=au&output=rss
http://news.google.com/news?ned=in&output=rss
http://news.google.com/news?ned=en_il&output=rss
http://news.google.com/news?ned=en_my&output=rss
http://news.google.com/news?ned=nz&output=rss
http://news.google.com/news?ned=en_pk&output=rss
http://news.google.com/news?ned=en_ph&output=rss
http://news.google.com/news?ned=en_sg&output=rss
http://news.google.com/news?ned=ar_me&output=rss
http://news.google.com/news?ned=ar_ae&output=rss
http://news.google.com/news?ned=ar_lb&output=rss
http://news.google.com/news?ned=ar_sa&output=rss
http://news.google.com/news?ned=cn&output=rss
http://news.google.com/news?ned=hk&output=rss
http://news.google.com/news?ned=hi_in&output=rss
http://news.google.com/news?ned=ta_in&output=rss
http://news.google.com/news?ned=ml_in&output=rss
http://news.google.com/news?ned=te_in&output=rss
http://news.google.com/news?ned=iw_il&output=rss
http://news.google.com/news?ned=jp&output=rss
http://news.google.com/news?ned=kr&output=rss
http://news.google.com/news?ned=tw&output=rss
http://news.google.com/news?ned=vi_vn&output=rss
http://news.google.com/news?ned=nl_be&output=rss
http://news.google.com/news?ned=fr_be&output=rss
http://news.google.com/news?ned=en_bw&output=rss
http://www.google.com/news?ned=cs_cz&output=rss
http://news.google.com/news?ned=de&output=rss
http://news.google.com/news?ned=es&output=rss
http://news.google.com/news?ned=en_et&output=rss
http://news.google.com/news?ned=fr&output=rss
http://news.google.com/news?ned=en_gh&output=rss
http://news.google.com/news?ned=en_ie&output=rss
http://news.google.com/news?ned=it&output=rss
http://news.google.com/news?ned=en_ke&output=rss
http://news.google.com/news?ned=hu_hu&output=rss
http://news.google.com/news?ned=fr_ma&output=rss
http://news.google.com/news?ned=en_na&output=rss
http://news.google.com/news?ned=nl_nl&output=rss
http://news.google.com/news?ned=en_ng&output=rss
http://news.google.com/news?ned=no_no&output=rss
http://news.google.com/news?ned=de_at&output=rss
http://news.google.com/news?ned=pl_pl&output=rss
http://news.google.com/news?ned=pt-PT_pt&output=rss
http://news.google.com/news?ned=de_ch&output=rss
http://news.google.com/news?ned=fr_sn&output=rss
http://news.google.com/news?ned=en_za&output=rss
http://news.google.com/news?ned=fr_ch&output=rss
http://news.google.com/news?ned=sv_se&output=rss
http://news.google.com/news?ned=en_tz&output=rss
http://news.google.com/news?ned=tr_tr&output=rss
http://news.google.com/news?ned=en_ug&output=rss
http://news.google.com/news?ned=uk&output=rss
http://news.google.com/news?ned=en_zw&output=rss
http://news.google.com/news?ned=ar_eg&output=rss
http://news.google.com/news?ned=el_gr&output=rss
http://news.google.com/news?ned=ru_ru&output=rss
http://news.google.com/news?ned=sr_rs&output=rss
http://news.google.com/news?ned=ru_ua&output=rss
http://news.google.com/news?ned=uk_ua&output=rss
http://news.google.com/news?ned=es_ar&output=rss
http://news.google.com/news?ned=pt-BR_br&output=rss
http://news.google.com/news?ned=ca&output=rss
http://news.google.com/news?ned=fr_ca&output=rss
http://news.google.com/news?ned=es_cl&output=rss
http://news.google.com/news?ned=es_co&output=rss
http://news.google.com/news?ned=es_cu&output=rss
http://news.google.com/news?ned=es_us&output=rss
http://news.google.com/news?ned=es_mx&output=rss
http://news.google.com/news?ned=es_pe&output=rss
http://news.google.com/news?ned=us&output=rss
http://news.google.com/news?ned=es_ve&output=rss

После запуска программы, создания объекта класса LinksReader и вызова его метода run происходит следующее:
1. Загружаются источники.
2. Загружаются все найденные за прошлые разы RSS ссылки (чтобы не искать каждый раз по новой, а пополнять уже имеющуюся базу RSS).
3. Проходим по всем источником, читаем разметку и выдёргиваем все ссылки которые в разметке помечены тегом <link></link>.
4. Удаляем все повторяющиеся ссылки.
5. Проходим по всем найденным новостным сайтам, читаем разметку каждого из них и выдёргиваем значения всех RSS тегов этого сайта.
6. Удаляем все повторяющиеся RSS ссылки.
7. И наконец сохраняем результат в файл.

По стандарту все RSS ссылки сайта, должны быть помечены тегом <link rel="alternate" type="application/rss+xml" title="Моя RSS-лента" href="index.xml" />, что намного облегчает поиск RSS.

Как видно программа достаточно проста, но хорошо делает своё дело. За один запуск находит 600-700 RSS лент. Повторные запуски увеличивают это количество, так-как в news.google.com постоянно добавляются ссылки на новые новостные сайты.

Не хотел подробно рассматривать каждую строку кода, думаю что он и так хорошо читается, даже не знающим Qt. Но, если есть непонятные места — спрашивайте и я с радостью помогу разобраться. Если есть замечания, критика — пишите.

Автор: extenup

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js