Покопался я ещё в своих старых и не очень проектах и нашёл одну интересную программку. Она ищет 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