Delphi.int.ru — Портал программистов

Вход Регистрация | Забыли пароль?

События

Сегодня:
Вопросы0    Ответы0    Мини-форумы0


Последние:
Вопрос20.07, 15:06 / #6671
Ответ30.06, 12:52 / #6666
Новости30 апреля 2012


Сейчас онлайн:
На сайте — 10
На IRC-канале — 2

Ссылки

Читаем цитаты с bash.org.ru своей программой

Автор: Вадим К

I. Вступление

Интернет всё больше и больше входит в нашу жизнь. Мы часто сидим и нажимаем кнопку "обновить", ожидая новых данных на заветной страничке. Но ведь надо и работать когда-то, поэтому задачу мониторинга странички с новостями мы поручим Delphi, а сами будем работать (или заниматься другим полезным делом – жизнь ведь прекрасна). Если что – всё будет скачано и представлено в удобном для нас виде.

В качестве "подопытного кролика" я выбрал многим известный цитатник рунета – bash.org.ru. Программа будет забирать с главной странички цитаты, и складывать их в базу. А с цитатами в базе можно делать что угодно.

Эта статья отличается от моих других тем, что я даю сразу готовое приложение и комментирую интересные моменты.

II. Общие замечания

Внешний интерфейс программы не претендует на награду. Я над ним особенно не задумывался, так как основная задача в другом. Интерфейс сделаете сами, если он вам нужен.

Это приложение построено по модульно-объектной технологии (мне больше нравится название "Разделяй и властвуй"). То-есть, для каждой сущности есть объект, и эти объекты взаимодействуют между собой. Так как связи и зависимости между ними минимальные, то можно легко их заменять и модифицировать.

Чтобы легче было искать место в коде, на которое я ссылаюсь, я использую специальные маркеры. В тексте статьи они выглядят так {текст}. Чтобы найти код, который соответствует ему, нужно сделать следующее. Перейти в Delphi, выбрать в меню View » ToDo List. Найти там соответствующий текст и кликнуть дважды. А по тексту программы вы увидите их как { TODO -oVadim -cView : текст }.

III. Класс базы данных (БД)

Обзор класса

Начнём разбор с класса, который обслуживает базу данных. Только объекты этого класса имеют доступ к базе данных, только они знают как с ней работать. Остальные классы не должны ничего знать о базе данных.

В самом верху юнита BBasa объявлен абстрактный класс TBBasaCustom {B1}. Этот класс имеет только один метод для добавления цитат в базу, да и тот абстрактный. Рабочий класс будет наследоваться от него. Это сделано специально, чтобы из того объекта, который будет добавлять данные, нельзя было бы обратиться к другим методам, и ему было всё равно, какие ещё методы есть у класса. Они ему не нужны. Это выглядит дивно, но позже станет понятно.

В этом же юните объявлен класс TBBasa {B2}. Этот класс наследуется от нашего класса и реализовывает всю нужную функциональность, а именно:

Открывает БД при своем создании. Если файл базы отсутствует – он его создаст. {B6}

Умеет добавлять цитату, так как реализовывает абстрактный метод Add. {B3}

Умеет найти в базе цитату по номеру – метод GetQuotes. {B4}

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

В качестве базы данных я использую SQLite.

Рассмотрим некоторые методы детальнее.

Метод Add

Этот метод {B3} получает два параметра – Number и Text – соответственно номер цитаты и её текст. Перед добавлением вначале проверяет, а нет ли уже цитаты в базе. Для этого он делает запрос на выборку цитат с заданным номером. Если цитата не найдена (количество найденных строк равно нулю), то добавляем в базу. Конечно, теоретически может быть, что в базе будет несколько записей с одним номером (программная ошибка, к примеру), но я не усложняю. В конце метода есть вызов SendCommand. Это оповещение интерфейса о том, что есть новые цитаты.  Как это работает – будет рассказано ниже.

Метод GetQuotes

Этот метод {B4} по заданному номеру цитаты находит её и возвращает, предварительно удалив спецсимволы. Если цитата не найдена – возвращает пустую строку (оно логично). Интересно также то, что этот метод обращается к другому, который запрашивает "сырой текст" из базы.

IV. Класс потока

Обзор

Данный класс занимается основной работой – он скачивает главную страничку, парсит, и отдаёт поштучно цитаты объекту БД. Вся реализация находится в юните BTread.

Как видно из кода, у этого класса только три публичных метода – конструктор, деструктор и запрос на обновление. А больше ему и не надо.

Рассмотрим как всё это работает. Через конструктор {T1} при создании класса мы передаём ему ссылку на объект БД, чтобы потом иметь возможность добавлять цитаты.

После того, как поток будет запущен, начинает выполняться метод Execute {T2}. Он предельно прост – пока нас не завершили, повторять: скачать, распарсить и подождать. Все действия специально разделены, чтобы быть независимыми.

Скачивание страницы

Метод скачать страничку GetText {T3} просто возвращает в виде строки содержимое страницы. Если вам по каким-то идеологическим причинам не нравятся компоненты Indy, просто замените здесь на свой код, и всё.  Сам метод хорош ещё тем, что показывает, как в RunTime создавать компонент и назначать методы.

Парсинг

Вытягивать цитаты {T4} наиболее просто с помощью регулярных выражений. Откуда я взял регулярное выражение – не спрашивайте. Учитесь сами его составлять. Кстати, на сайте есть статья, посвященная им. Больше в этом методе ничего интересного.

Сон

Между скачиванием цитат надо делать паузу. Так как мы находимся в потоке, то свободно можем писать Sleep.  Никакого "подвисания интерфеса" не будет. Но эта функция плоха тем, что поток сложно пробудить из такого сна. И если мы захотим в этот момент закрыть программу, то нам придётся ждать, пока функция не отработает.

Именно по этой причине я использую немного другой метод {T5}. Я использую функцию WaitForSingleObject, которая, в отличие от Sleep, может также завершиться, если "сработал объект-событие", который ей передали. Сработал – это перешёл с SetEvent.

Поэтому, если нужно обновить раньше времени или завершить работу потока, мы "включаем событие" и метод Sleep завершается досрочно.

V. Основное приложение

Обзор

Теперь, когда мы рассмотрели все вспомогательные объекты, пора их объединить и заставить работать.

Так как основная функциональность у нас уже реализована, то код предельно прост. Первым делом мы создаём два объекта – один для БД, другой для потока. Делаем это в OnCreate формы {M2}. В OnDestroy соответственно уничтожаем. Обратите внимание на последовательность создания и удаления. Она важна.

Кнопка "обновить" тоже не должна вызвать осложнений. Она просто вызывает метод Update у объекта потока.

Обратная связь

Помните вызов SendCommand у объекта БД? Эта функция находится в юните BMessage. Сама она очень проста – она просто вызывает WinAPI функцию SendMessage для посылки сообщения главной форме, а хендл главной формы берётся из Application.MainForm.Handle. Главная форма принимает эти сообщения, и уже самостоятельно обращается к нужным объектам.

Рассмотрим для примера передачу сообщения о новой цитате. После того, как цитата была сохранена, посылается сообщение MY_NEW_QUOTES и в качестве параметра передаётся номер цитаты. Второй параметр нам не нужен, и мы пишем туда 0.

В класса формы объявлен метод {M7} для перехвата этого сообщения.  Получив его, мы обращаемся к объекту БД, по номеру получаем само сообщение и добавляем в Memo.

VI. Выводы

Конечно, это очень сырой пример, и на выставку он не годится. Но он хорош тем, что является заготовкой для различных программ подобного типа – собирать новости, выкачивать галереи картинок, собирать данные.

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

Файлы к статье »

Автор: Вадим К

Статья добавлена: 4 июня 2008

Следующая статья: Выравнивание компонентов »

Рейтинг статьи: 4.50 Голосов: 2 Ваша оценка:

Зарегистрируйтесь/авторизируйтесь,
чтобы оценивать статьи.


Статьи, похожие по тематике

 

Для вставки ссылки на данную статью на другом сайте используйте следующий HTML-код:

Ссылка для форумов (BBCode):

Быстрая вставка ссылки на статью в сообщениях на сайте:
{{a:47}} (буква a — латинская) — только адрес статьи (URL);
{{статья:47}} — полноценная HTML-ссылка на статью (текст ссылки — название статьи).

Поделитесь ссылкой в социальных сетях:


Комментарии читателей к данной статье

Пока нет комментариев к данной статье. Оставьте свой и он будет первым.

Оставлять комментарии к статьям могут только зарегистрированные пользователи.