Поиск по блогу

среда, 26 ноября 2008 г.

Парсинг RSS на PHP. Простой пример

В комментариях спрашивали про парсинг RSS на PHP. Так как этот вопрос напрямую относится к теме блога, то я его решила немного изучить и осветить.

Для начала я прочитала в интернете про разные способы парсинга на PHP (почитайте обязательно, очень полезный материал). Все оказалось просто, синтаксис очень понятный и удобный. Особенно мне понравился SimpleXML :)

Полученные знания нужно закреплять на практике.

Вы все знаете про Яндекс-блоги. И знаете, что там можно подписаться на RSS по любому запросу. Причем синтаксис запросов (такой же, как к самому Яндексу) предоставляет достаточно широкие возможности. Можно следить за всем, что происходит в блогосфере.

Составляем запрос и визуально убеждаемся, что в результате запроса получаем валидный XML.


Внутри скрипта пишем:

<?
function utf8_convert($str, $type)
{
static $conv = '';
if (!is_array($conv))
{
$conv = array();
for ($x=128; $x <= 143; $x++)
{
$conv['utf'][] = chr(209) . chr($x);
$conv['win'][] = chr($x + 112);
}
for ($x=144; $x<= 191; $x++)
{
$conv['utf'][] = chr(208) . chr($x);
$conv['win'][] = chr($x + 48);
}
$conv['utf'][] = chr(208) . chr(129);
$conv['win'][] = chr(168);
$conv['utf'][] = chr(209) . chr(145);
$conv['win'][] = chr(184);
}
if ($type == 'w')
{
return str_replace($conv['utf'], $conv['win'], $str);
}
elseif ($type == 'u')
{
return str_replace($conv['win'], $conv['utf'], $str);
}
else
{
return $str;
}
}

echo '<h1><font color="red">Конфузы блогосферы</font></h1>';
$url = 'http://blogs.yandex.ru/search.rss?text="наложил в штаны"'; //адрес RSS ленты

$rss = simplexml_load_file($url); //Интерпретирует XML-файл в объект

//цикл для обхода всей RSS ленты
foreach ($rss->channel->item as $item) {
echo '<a href="'.$item->link.'">';
echo '<h2>'.utf8_convert($item->title,"w").'</h2>'; //выводим на печать заголовок статьи
echo '</a>';
echo utf8_convert($item->description,"w"); //выводим на печать текст статьи
}

?>


Вот и все, любуемся результатом.

Если вы хотите парсить "в накопительном режиме", то у записей достаточно обрабатывать и сравнивать дату публикации pubDate. В зависимости от этой даты — записывать или не записывать в базу.

воскресенье, 23 ноября 2008 г.

Работа с MySQL в Delphi

Я не буду подробно останавливаться на технических аспектах работы с MySQL в Delphi. Об этом можно почитать в сети.

Умение работать с MySQL в Delphi вам может пригодиться, а может и не пригодиться. Все зависит от проекта, который вы собрались реализовать. Если, допустим, ваша программа будет работать с определенной базой (например, с базой WordPress или форума), то некоторые удобства есть в том, чтобы работать с локальной копией проекта, а потом изменения довносить на базу на сервере.

Для проекта по полуавтоматическому наполнению форума я как раз выбрала вариант с работой с MySQL. В первую очередь для того, чтобы облегчить себе задачу. Ведь в этом случае не надо будет создавать базу для форума: достаточно просто установить форум на локальной машине и работать с ним. Однако, проект наполнения форума отличается тем, что он динамический. То есть помимо данных, которые будет публиковать моя программа, на сайте (надеюсь) будут регистрироваться и реальные посетители. Для того, чтобы данные были синхронизованы, придется некоторым образом модифицировать структуру таблиц. Я, например, в таблицах с темами и сообщениями, добавила столбик IS_PUBLISHED. Значение данных в этом столбике для неопубликованных тем и сообщений будет равно нулю, а для опубликованных — единице.

Ну и дальше все в таком духе: разрабатываем программу исходя в первую очередь из задачи и алгоритма синхронизации.
___

UPD: На этом же блоге вы можете прочитать про "экспресс-метод" работы с MySQL из Delphi через ADO.

понедельник, 17 ноября 2008 г.

Парсинг ников пользователей для форумов

Напарсить где-нибудь ников пользователей еще проще, чем напарсить аватаров. Для этого достаточно зайти на форум или сайт, на котором есть поиск пользователей. Желательно, чтобы там был выбор по полу. Вот, например, на сайте НайтПати зарегистрированы тысячи ночных тусовщиков из разных городов России. Идем на страницу поиска юзеров http://msk.nightparty.ru/users.php.

Изучаем get-запрос скрипта поиска, смотрим, что передается, смотрим идентификатор России и города Москвы. Смотрим идентификатор пола. Смотрим, как организована пагинация. В принципе, больше ничего и не надо.

Потом составляем какое-нибудь регулярное выражение для нахождения ников на конкретном сайте.

Рисуем формочку:
Кроме двух кнопок больше ничего и не надо. Вторая кнопка тоже исключительно для самых нетерпеливых, которым лень подождать, когда появится сообщение "Все сделано".

Привожу полностью рабочий код всего юнита целиком:

unit UserFinderU;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, StdCtrls, Urlmon;

const
GirlUserListFileName = 'g_users.txt';
BoyUserListFileName = 'b_users.txt';
GirlSearchURL = 'http://msk.nightparty.ru/users.php?action=dosearch&country_id=103&city_id=1043&user_sex=2&page=[PageNum]';
BoySearchURL = 'http://msk.nightparty.ru/users.php?action=dosearch&country_id=103&city_id=1043&user_sex=1&page=[PageNum]';
FindUserRegExp = 'style="padding-left:8px;"><a href="http://(?:.*?)\.at\.nightparty\.ru/"><b>(.*?)</b>';

function DownloadFile(SourceFile, DestFile: string): Boolean;

type
TForm1 = class(TForm)
btnStart: TButton;
btnStop: TButton;
cbGender: TComboBox;
Label1: TLabel;
procedure btnStartClick(Sender: TObject);
procedure btnStopClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
vStop : boolean;

implementation

uses
VBScript_RegExp_55_TLB;

{$R *.dfm}

procedure TForm1.btnStartClick(Sender: TObject);
var
i, j, t,
PageNum : integer;
FName,
SearchURL,
LinkStr,
sFileName,
currBody
: string;
NextPage : boolean;
SLBody : TStringList;
RE : TRegExp;
mc : MatchCollection;
sm : SubMatches;
mm : Match;
f : TextFile;
UsersList : TStringList;
begin
if cbGender.ItemIndex = 0 then
begin
FName := GirlUserListFileName;
SearchURL := GirlSearchURL;
end;
if cbGender.ItemIndex = 1 then
begin
FName := BoyUserListFileName;
SearchURL := BoySearchURL;
end;

PageNum := 0;
NextPage := true;
UsersList := TStringList.Create;

//======================

vStop := false;
while NextPage and not vStop do
begin
LinkStr := StringReplace(SearchURL,'[PageNum]',IntToStr(PageNum),[rfIgnoreCase]);
try
SLBody:=TStringList.Create;
RE := TRegExp.Create(Self);

sFileName:=ExtractFilePath(Application.ExeName) + 'cache.txt';
currBody:='';
if DownloadFile(LinkStr,sFileName) then
SLBody.LoadFromFile(sFileName);
currBody:=SLBody.Text;
DeleteFile(sFileName);

// ищутся пользователи
RE.Pattern := FindUserRegExp;
RE.Global := true;
RE.IgnoreCase := true;
RE.Multiline := true;

mc := RE.Execute(currBody) as MatchCollection;
for j := 0 to mc.Count-1 do
begin
mm := mc[j] as Match;
sm := mm.SubMatches as SubMatches;
UsersList.Add(sm.Item[0]);
end;
if mc.Count = 0 then NextPage := false;

finally
SLBody.Free;
mm := nil;
sm := nil;
mc := nil;
RE.Free;
end;
inc(PageNum);

for t := 0 to 10 do
begin
Sleep(100);
Application.ProcessMessages;
end;
end;

UsersList.SaveToFile(ExtractFilePath(Application.ExeName)+FName);

UsersList.Clear;
UsersList.Free;
ShowMessage('Все сделано.');
end;

procedure TForm1.btnStopClick(Sender: TObject);
begin
vStop := true;
end;

function DownloadFile(SourceFile, DestFile: string): Boolean;
begin
try
Result := UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0,
nil) = 0;
except
Result := False;
end;
end;

end.


Далее запускаем программу и занимаемся другими делами (например, продолжаем программировать свой другой-супер-мега-проект-который-принесет-кучу-БАБЛА %D ). Паузу между запросами я поставила по секунде, так что минут 15 уйдет на полное сканирование всех страниц с пользователями одного пола. Итак, через некоторое время мы получим файлики с мужскими и женскими никами, тех и других тысяч по 12. Можем использовать их для своих чистых дел). Чтобы лишний раз не грузить всуе упомянутый мной сайт, можете взять готовые списки у меня. Обращайтесь на почту, указанную в профиле.

=====

Немного о блоге. Приятно видеть, что количество подписчиков растет. Постараюсь в ближайшее время привести его в более удобочитаемый вид. Например, прятать часть поста под кат, чтобы главная страница не разъезжалась до таких размеров, до каких она сейчас разъехалась. Даже такое элементарное действие стандартными средствами блоггера не сделать. Но я уже нашла способ, так что остается только опробовать его на практике.

=====

Если вы пришли на блог с поисковика в надежде скачать базу ников, то вам нужно в другое место :)

среда, 12 ноября 2008 г.

Парсинг и загрузка аватаров с сайтов аватаров (Delphi)

Расскажу, как напарсить аватаров.

Аватары можно парсить откуда угодно: с форумов, из дневников... Но самый простой способ — взять их с сайтов аватаров (благо, таких развелось море).

Задача разделяется на 2 подзадачи:
1. Напарсить ссылок на страницы с аватарами;
2. Напарсить аватары с этих страниц.

Первая подзадача мне уже не интересна. Я писала в блоге о том, как находить ссылки на сайте. Просто берем сайт с аватарами, смотрим, как организована пагинация, составляем регулярное выражения для парсинга ссылок (как правило, в разделах вывод разбит на страницы). На выходе получаем список ссылок, который и используем на следующем шаге.

Переходим ко второй подзадаче. Парсить аватары можно по-разному. Можно для каждого сайта составлять отдельное регулярное выражение, учитывая особенности записи значения SRC в тэге IMG. Этот способ несложный, но все-таки трудозатратный: придется анализировать код страниц всех ресурсов. Второй способ — скачать все картинки со страницы, а потом отфильтровать по заданному диапазону размеров.

Для начала нарисуем интерфейс и подберем какое-нибудь более-менее "универсальное" регулярное выражение для парсинга картинок.

Интерфейс у меня вышел следующий:

парсинг аватаров

"Общее" регулярное выражение взяла такое:

<img[^>]* src=\"([^\"]*(?:gif|jpg|png))\"[^>]*>

Жесткое указание расширения (gif, jpg, png) избавит от скачивания картинок, генерируемых скриптами (счетчиков и т.д.).

Для примера я взяла простенький сайт. SRC картинок у них там абсолютные. Это значит, что если вы захотите сделать что-нибудь уж совсем универсальное, то вам надо будет предусмотреть, чтобы скачивание картинки, у которой сорс будет указан как, например ../../imgs/1.gif, а сама страница загружается по адресу http://site.com/humor/1/ — было правильным. То есть анализировать все это и составлять правильную ссылку http://site.com/humor/imgs/1.gif.

Ну и естественно, при сохранении файла в директорию на локальной машине надо проверить, нет ли там уже файла с таким названием. Если есть — добавить суффикс "_N", где N — число по порядку (я это в примере не реализовала).

Обработчик нажатия кнопки "Сохранить" у меня получился такой:

procedure TMainF.Button1Click(Sender: TObject);
var
i, j : integer;
PicLinkStr,
LinkStr : String;
SLBody : TStringList;
currBody,
UTF8Str,
sPicFileName,
sFileName,
sRegExp,
Ext : string;
RE : TRegExp;
mc : MatchCollection;
sm : SubMatches;
mm : Match;
w,h : word;
begin
for i := 0 to Memo1.Lines.Count-1 do
begin
// загрузка страницы
LinkStr := Memo1.Lines[i];
// загружаем страницу
try
SLBody:=TStringList.Create;
RE := TRegExp.Create(Self);

sFileName:=ExtractFilePath(Application.ExeName) + 'cache.txt';
if DownloadFile(LinkStr,sFileName) then
SLBody.LoadFromFile(sFileName);
currBody:=SLBody.Text;
UTF8Str := UTF8ToAnsi(currBody);
DeleteFile(sFileName);

if RadioButton1.Checked then
sRegExp := edRegExpr.Text
else
sRegExp := '<img[^>]* src=\"([^\"]*(?:gif|jpg|png))\"[^>]*>';

// ищутся и скачиваются изображения
RE.Pattern := sRegExp;
RE.Global := true;
RE.IgnoreCase := true;
RE.Multiline := true;

mc := RE.Execute(UTF8Str) as MatchCollection;

// сохраняются все изображения
for j := 0 to mc.Count-1 do
begin
mm := mc[j] as Match;
sm := mm.SubMatches as SubMatches;
PicLinkStr := sm.Item[0];

sPicFileName:=edDir.Text + ExtractPicName(PicLinkStr);

if DownloadFile(PicLinkStr,sPicFileName) then
begin
// если по размерам - проверяем размеры
if RadioButton2.Checked then
begin
Ext := UpperCase( ExtractFileExt(sPicFileName) );
if Ext = '.GIF' then
GetGIFSize(sPicFileName, w, h);

if Ext = '.JPG' then
GetJPGSize(sPicFileName, w, h);

if Ext = '.PNG' then
GetPNGSize(sPicFileName, w, h);

if (w < seWidthFrom.Value) or
(w > seWidthTo.Value) or
(h < seHeightFrom.Value) or
(h > seHeightTo.Value) then
DeleteFile(sPicFileName);
end;
// если по регулярке - сохраняем все

end;
end;
finally
begin
SLBody.Free;
RE.Free;
end;
end;
end;

end;


Процедуры для определения размеров картинок GetGIFSize и т.д. берем в интернете и не паримся. Например, я взяла отсюда.

Все, нажимаем на кнопку и получаем результат! Сейчас у нас будут аватары для создания армии пользователей! %D

P.S. Выражаю огромную благодарность SEOCoder-у за размещение ссылки на мой блог! Результаты мне очень понравились ;) Буду потихоньку вылазить со своим блогом и искать новых читателей. Может, кто-нибудь хочет обменяться ссылками? Вэлкам!

суббота, 8 ноября 2008 г.

Автоматизация постинга в дневники на блогхостингах с WordPress. Часть IV

Переходим к той части автоматизации, которая позволит нам постить записи. Я уже писала, что для удобства на каждой записи с данными о блоге вызывается контекстное меню. Записи в датасете берутся из запроса:
select b.n as blog_n, b.blogname,b.title,b.url as blog_url,
b.update_date,b.n_bloghosting,
b.login,b.pass,bh.*
from blog b
left join bloghosting bh on b.n_bloghosting = bh.n
where b.n_bloghosting = :n

То есть там есть нужная нам информация о блоге и блогхостинге, на котором он расположен. Кстати, информация в таблице о блогхостинге на wordpress.com у меня получилась следующая:

INSERT INTO BLOGHOSTING (N, URL, URL_LOGIN, FORM_LOGIN, FIELD_LOGIN, FIELD_PASS, BUTTON_LOGIN, URL_UNLOGIN, URL_NEW_MESS, FIELD_TITLE, FIELD_MESS, FIELD_TAGS)
VALUES (1, 'http://wordpress.com', 'http://[BlogName].wordpress.com/wp-login.php', 'loginform', 'log', 'pwd', 'wp-submit', NULL, 'http://[BlogName].wordpress.com/wp-admin/post-new.php', 'title', 'content', 'tags-input');

[BlogName] потом при формировании ссылки для каждого дневника будет заменяться на содержимое поля BLOGNAME.

Поле BUTTON_LOGIN можно не заполнять, так как тип кнопки - submit.
Для последующего упрощения процесса программирования, советую выносить часто повторяющиеся действия в отдельные процедуры и функции. А потом оформить это в библиотеку. Например, поиск формы по ее имени:
function FindFormByName ( W : TWebBrowser; FormName : string) : Variant;
var
i : integer;
formitem : variant;
S : String;
begin
Result:=Null;
for i := 0 to w.oleobject.document.forms.length - 1 do
begin
formitem := w.oleobject.document.forms.item(i);
S:= lowercase(formitem.name);
if S = lowercase(FormName) then Result:=formitem;
end;
end;

Входные параметры: TWebBrowser, в котором загружена страница, и название формы.

Еще в отдельную функцию можно вынести заполнение поля формы:
function fillform(aformitem : variant; fieldname: string; value: string): boolean;
var
i, j: integer;
begin
result := false;
for j := 0 to aformitem.length - 1 do
begin
try
if aformitem.item(j).name = fieldname then
begin
aformitem.item(j).value := value;
result := true;
end;
except
exit;
end;
end;
end;
Входные параметры: форма, название поля и что в это поле поместить.

Сабмит (отправление) формы:
function SubmitForm( V : Variant) : boolean;
var
i : integer;
begin
Result:=false;
for i := 0 to V.length - 1 do
begin
try
if Trim(lowercase(V.item(i).type)) = 'submit' then
begin
result := true;
V.item(i).click();
exit;
end;
except
exit;
end;
end;
end;


С учетом приведенных процедур, залогиниться на блоге можно, написав следующий код в обработчик:

procedure TFMain.N2Click(Sender: TObject);
var
sURL : string;
V : Variant;
begin
// залогиниться
// формируем ссылку для логина
sURL := StringReplace(qBlogURL_LOGIN.AsString,'[BlogName]',qBlogBLOGNAME.AsString,[rfIgnoreCase]);
ShowPage(sURL);
// найти форму по имени
V:=FindFormByName(WebBrowser,qBlogFORM_LOGIN.AsString);
if VarIsNull(V) then exit;
// ввести в форму, что надо
fillform(V,qBlogFIELD_LOGIN.AsString,qBlogLOGIN.AsString);
fillform(V,qBlogFIELD_PASS.AsString,qBlogPASS.AsString);
// нажать на кнопку
try
if submitform(v) then NowLogin := qBlogBLOG_N.AsInteger;
except
end;
end;

Функция ShowPage просто загружает URL в веббраузер.
procedure TFMain.ShowPage(URL: string);
begin
vLoaded := false;
WebBrowser.Navigate(URL);
while not vLoaded do
Application.ProcessMessages;
end;


До того, как обработалась команда нажатия на кнопку, форма выглядела так:
ввод данных в форму

После автосабмита мы оказываемся уже залогиненными:

автоматический логин

Как видите, все очень просто. В переменной NowLogin будет храниться N последнего блога, в котором залогинились. Это надо для того, чтобы при публикации каждого сообщения в один и тот же блог повторно не логинились.

Не вот и все, аналогично прописать действия для помещения записи в блог:
- если не залогинены - залогиниться;
- перейти на страницу для создания новой записи;
- ввести данные в поля;
- отправить форму.

Удачных разработок ;)

четверг, 6 ноября 2008 г.

Автоматизация постинга в дневники на блогхостингах с WordPress. Часть III

Продолжу тему автоматизации постинга. Прежде чем описывать технологический процесс дальше, подробнее остановлюсь на работе с БД. Это будет не третья часть, а скорее вторая с половиной, так как я немного вернусь назад и расскажу, как я обычно работаю с базой.

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

Итак, Firebird. Работать с базой будет удобнее через специально разработанный инструмент. Например, IBExpert.

Там и многооконный режим, и дружественный интерфейс, и визуальный редактор. В Эксперте удобно отлаживать запросы.

Для начала создаются все таблицы. DDL полностью я здесь приводить не буду, в качестве примера приведу только создание двух таблиц: блогов и блогхостингов.

CREATE GENERATOR GEN_BLOG_N;

CREATE TABLE BLOG (
N INTEGER NOT NULL,
N_BLOGHOSTING INTEGER,
LOGIN VARCHAR(25),
PASS VARCHAR(25),
BLOGNAME VARCHAR(255),
TITLE VARCHAR(255),
DSC VARCHAR(500),
URL VARCHAR(255),
EMAIL VARCHAR(50),
CREATE_DATE DATE,
UPDATE_DATE DATE
);

ALTER TABLE BLOG ADD CONSTRAINT PK_BLOG PRIMARY KEY (N);

CREATE GENERATOR GEN_BLOGHOSTING_N;

CREATE TABLE BLOGHOSTING (
N INTEGER NOT NULL,
URL VARCHAR(255),
URL_LOGIN VARCHAR(255),
FORM_LOGIN VARCHAR(25),
FIELD_LOGIN VARCHAR(25),
FIELD_PASS VARCHAR(25),
BUTTON_LOGIN VARCHAR(25),
URL_UNLOGIN VARCHAR(255),
URL_NEW_MESS VARCHAR(255),
FIELD_TITLE VARCHAR(25),
FIELD_MESS VARCHAR(25),
FIELD_TAGS VARCHAR(25)
);

ALTER TABLE BLOGHOSTING ADD CONSTRAINT PK_BLOGHOSTING PRIMARY KEY (N);

Для каждой таблицы создаем ключ и генератор значения ключа (сиквенс). А также триггер BEFORE INSERT, который для каждой новой записи записывает в поле N значение сиквенса.

SET TERM ^ ;

CREATE TRIGGER BLOG_BI FOR BLOG
ACTIVE BEFORE INSERT POSITION 0
AS
begin
if (New.N is null) then
New.N = Gen_Id(gen_blog_n, 1);
end
^

SET TERM ; ^

(Я тут все привела в кодах, но в Эксперте все то же самое можно сделать через интерфейс, не заботясь о правильности синтаксиса.)

Проделав подобные шаги для всех таблиц, получим базу со структурой, напоминающей БД из первой части этой серии постов. После этого можно переходить к запросам.

Парсинг форумов

Немного отвлекусь от темы автоматизации постинга в дневники и поговорю о парсинге форумов. Все-таки тема дневника — это парсинг. А форумы представляют собой широченное поле для оттачивания навыков парсинга. Да и, — если честно, — скучно в нескольких постах подряд писать на одну тему, буду чередовать.

Итак, к теме.

Впервые я натолкнулась на дублированные ветки форума года 2 назад, когда разбиралась с CMS Joomla. Тогда я просто отметила для себя этот факт: типа, кто-то просто по-своему решает проблему непопулярности форума и наполняет его за счет других ресурсов, паразитируя на чужой аудитории. Но, по сути, первоначальное заполнение форума полезной информацией — это очень неплохо для привлечения на форум целевой аудитории. Единственно, что надо бы не полностью копировать, а хоть немного видоизменять записи (достаточно пропустить через примитивный синонимайзер или разбавить взятыми со стороны).

Я знаю, что существуют генераторы дорвеев в виде форумов. Но что если вам нужен не дорвей, а форум "для людей"? Установить PhpBB — это самое малое. Главное — привлечь пользователей. А на пустое место никого не привлечь.

Итак, попытаемся его самостоятельно наполнить. Я разберу наполнение форума на движке PhpBB. Так как параллельно занимаюсь еще парой направлений, то не знаю, с какой частотой буду публиковать статьи по этой теме. Но то, что они будут — это факт.

Большую часть работы можно автоматизировать, чтобы потом просто нажимать на кнопки. Как я себе представляю полуавтоматическое наполнение форума? Сначала надо зарегистрировать базу пользователей-ботов. Не просто напихать в базу всякого мусора, а сделать качественно: интересные ники, аватары, инфо... В инфе каких-нибудь пользователей, кстати, можно проставить ссылки на свои блоги (если их много).

Затем нужно создать разделы. Побродить в сети по форумам аналогичной тематики, посмотреть, подумать, оригинально сформулировать. В это же время надо начать думать над структурой приложения. Первое, что мне приходит в голову, это держать 2 базы MySQL: одну на локальной машине, а другую — в сети. И грамотно организовать взаимодействие этих баз.

Это общие моменты. На вопросах структуры и взаимодействия баз я подробнее остановлюсь позже.

На следующем этапе надо подыскать форумы, родственные по тематике. Желательно, чтобы они были на одном и том же движке (это освободит от необходимости составлять для парсинга разных движков отдельные регулярные выражения). Провести парсинг информации. Нам необходимо МНОГО информации, с большим запасом. Эту информацию записать на локальную базу, изменить сами записи, изменить время публикации (равномерно распределить на определенный период). А потом — автоматически публиковать ее в сети, опираясь на время записей, чтобы поисковики видели обновляющийся ресурс.

Наверное, немного плохо сформулировала. Но в голове я ясно представляю весь этот процесс.

Поэтапно буду освещать его здесь. Первые 3 вопроса будут:
1. Работа с MySQL в Delphi
2. Парсинг базы аватаров
3. Наполнение базы юзеров

Остальные пункты допишу потом.

Поделиться