Шаг 3 — Структура данных и алгоритм
Итак, мы обходимся без БД, значит, данные будем хранить только во время сеанса. Создадим для описания наших классов отдельный юнит (допустим, uKeyWordClass). В объекте TKeyWord будем хранить само ключевое слово, количество запросов и флаг посещения (если по слову проверялся список ключевиков — true). Список всех кейвордов, TKeyWordList, наследник TList, будет содержать ссылки на объекты TKeyWord. Определим для него несколько функций и процедур.
TKeyWord = class
KeyWord : string;
RequestCnt : integer;
Checked : boolean;
end;
TKeyWordList = class(TList)
MaxCount : integer; // ограничение на количество слов в списке
UseMaxCount : boolean; // использовать ограничение
function AddKeyWord(KW : TKeyWord) : boolean;
procedure MakeKeyCheked(KW : string);
function CountNotChecked : integer;
function FindNextNotCheckedKeyWord : string;
constructor Create;
end;
Алгоритм:
1. При загрузке программы из ini-файла считывается регулярное выражение для парсинга. Кстати, что касается регулярного выражения. Его надо отлаживать не просто на содержимом страницы, скопированном через буфер обмена, а на содержимом, сохраненном в процессе загрузки через программу. Так, например, вместо \n в работающем варианте пришлось использовать (?:\x0D\x0A), чтобы правильно идентифицировать переводы строк. Итоговое выражение получилось: \d{1,}">(.*?)</a></td>(?:\x0D\x0A|).*?(\d{1,})</td>.
2. После нажатия на кнопку "Старт" программа начинает парсинг: тупо, без всяких заморочек загружаем первую страницу, выбираем слова, заносим их в список. Отмечаем слово, которое проверили. Ищем следующее непроверенное слово и загружаем его. Выбираем слова, добавляем в список (дубли не добавляем). Если количество слов в списке не превысило желаемое (или допустимое), то продолжаем цикл.
Если программа прошлась по всем ссылкам, но нужного количества слов не набралось, — она все равно останавливается.
У меня обработчик получился таким:
procedure TfrmMain.btnStartClick(Sender: TObject);
var
i, j, cnt : integer;
flagStop : boolean;
tmpKW : TKeyWord;
currWord,
sFileName,
UTF8Str,
LinkStr : String;
SLBody : TStringList;
currBody : string;
RE : TRegExp;
mc : MatchCollection;
sm : SubMatches;
mm : Match;
f : TextFile;
begin
flagStop := false;
cnt := seCNT.Value;
currWord := edtKeys.Text;
StatusBar1.Panels[5].Text := 'В процессе';
while (KeyWordList.Count <= cnt) and (flagStop = false) do
begin
// загрузка страницы
LinkStr := 'http://direct.yandex.ru/stat/wordsstat.pl?text='+currWord;
// загружаем страницу
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;
UTF8Str := UTF8ToAnsi(currBody);
DeleteFile(sFileName);
// ищутся слова
RE.Pattern := RegExpr;
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;
tmpKW := TKeyWord.Create;
tmpKW.KeyWord := sm.Item[0];
tmpKW.RequestCnt := sm.Item[1];
if KeyWordList.AddKeyWord(tmpKW) = false then
tmpKW.Free;
end;
finally
begin
SLBody.Free;
RE.Free;
end;
end;
// отметить, что курВорд - посещено
KeyWordList.MakeKeyCheked(currWord);
// найти следующий кейворд
currWord := KeyWordList.FindNextNotCheckedKeyWord;
if currWord = '' then flagStop := true;
if (KeyWordList.CountNotChecked = 0) then flagStop := true;
if (KeyWordList.UseMaxCount=true) and (KeyWordList.Count >= KeyWordList.MaxCount) then flagStop := true;
StatusBar1.Panels[1].Text := IntToStr(KeyWordList.Count);
StatusBar1.Panels[3].Text := IntToStr(StrToInt(StatusBar1.Panels[3].Text) + 1);
actShowWords.Execute;
Sleep(1000*seSec.Value);
end;
actShowWords.Execute;
StatusBar1.Panels[5].Text := 'Парсинг завершен';
end;
Да, обратите внимание: так как страница загружается в UTF-8, то надо осуществлять ее перевод с помощью UTF8ToAnsi.
В прототипе, который выкладываю, поставила ограничение на 500 слов :)
Комментариев нет:
Отправить комментарий
Комментарии модерируются, вопросы не по теме удаляются, троллинг тоже.
К сожалению, у меня нет столько свободного времени, чтобы отвечать на все частные вопросы, так что, может, свой вопрос лучше задать на каком-нибудь форуме?