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

понедельник, 19 января 2026 г.

He Is Alive! или Блог-феникс :)

Всем привет. С момента последней записи прошло так много лет! Но вот я вернулась. Программисты, как и блогеры, бывшими не бывают :)

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

Вот и подумала, может, и этот блог принесет какой-никакой траффик? Шальной, залетный...

Ну и расскажу о себе немного.

Я Маша. Раньше я специализировалась на парсинге, а сейчас - на автоматизации в Telegram. Пишу ботов для себя и на заказ. Могу кодить, могу собрать бюджетненько на ноу-код платформе.

Люблю, чтобы все было по полочкам. Много идей (а с ними - и пет-проектов).

Сейчас обитаю в основном в Telegram. Вот мой канал про ботов - Боты на работе @bots_at_work

Создала и продвигаю бота Держи карту - он выдает карту или текстовую подсказку по ключевому слову в комментариях канала/группах. Подходит для проведения интерактивов. Бесплатно 2 слота под колоды, 2 слота под тексты.

понедельник, 8 июля 2013 г.

Как отобразить данные SQLite в DBGrid

TSQLMonitor поддерживает SQLite, начиная с версии RAD Studio XE3 (использовать его, естественно, вместе с TSQLConnection). У меня Delphi старенькие, поэтому покажу, как старыми дедовскими методами отобразить выборку данных в DBGrid (с помощью обертки DISQLite, о которой я писала тут).

Пример работает как в Delphi 7, так и в Delphi 2010. В других версиях просто не пробовала.

Следуя шаг за шагом инструкции, приведенной ниже, вы добьетесь желаемого результата — отобразите данные из запроса к БД SQLite в стандартной таблице DBGrid.

1. Разместите на форме:
- DBGrid
- ClientDataSet
- DataSetProvider
- DataSource
Если используете визуальные компоненты, то: DISQLite3Database и DISQLite3UniDirQuery. Если визуальными компонентами от DISQLite не пользуетесь, то экземпляры этих классов создадите динамически.

2. У DISQLite3UniDirQuery в поле Database := DISQLite3Database. И заполните SelectSQL.

3. У DataSetProvider: DataSet := DISQLite3UniDirQuery.

4. У ClientDataSet: ProviderName := DataSetProvider.

5. У DataSource: DataSet := ClientDataSet.

6. У DBGrid: DataSource := DataSource. Соответственно, заполните Columns, которые бы хотели видеть отображенными в таблице.

Вот и все.

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

четверг, 21 февраля 2013 г.

TChromium: заполнение и сабмит формы

Опишу самый простой способ заполнения и отправки формы с использованием компонента TChromium. С доступом к DOM-элементам по id в нем дела обстоят не так хорошо, как в Webbrowser-е, но зато очень просто исполнять любые java-скрипты.

JavaScript может пригодится не только для заполнения форм, он вообще достаточно широко используется.

Исполнение скрипта осуществляется с помощью ExecuteJavaScript. При этом обязательно проверять, чтобы Chromium.Browser и Chromium.Browser.Mainframe были отличны от nil.

Вот как будет выглядеть заполнение и сабмит формы логина на сайте vk.com.

procedure TfrmMain.btnLoginClick(Sender: TObject);
var
  CodeStr : string;
begin
  if Assigned(Chromium.Browser) and Assigned(Chromium.Browser.Mainframe) then
    begin
      CodeStr := 'document.forms[0].quick_email.value="UserEmail";';
      Chromium.Browser.MainFrame.ExecuteJavaScript(CodeStr, 'about:blank', 0);
      CodeStr := 'document.forms[0].quick_pass.value="UserPass";';
      Chromium.Browser.MainFrame.ExecuteJavaScript(CodeStr, 'about:blank', 0);
      CodeStr := 'document.forms[0].submit();';
      Chromium.Browser.MainFrame.ExecuteJavaScript(CodeStr, 'about:blank', 0);
    end;
end;

На практике столкнулась с необъяснимой ситуацией: если этот код попробовать запустить в Delphi 7, то Chromium.Browser.Mainframe почему-то будет равен nil (а если проверку убрать, то вываливается ошибка доступа). На каком-то форуме нашла, что это общая проблема для Семерки. В 2010 все работает отлично.

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

суббота, 9 февраля 2013 г.

Как удалить кукисы (cookies) в TChromium

В комментариях к статье о начале работы с TChromium спросили, как удалить в нем кукисы? Скажу сразу, решение не мое, нашла в свое время на СтэкОверфлоу, скопировала и с тех пор удачно использую.

Сначала надо отметить, что у интерфейса ICefCookieManager есть метод DeleteCookies, но он почему-то не работает. То есть в результате выполнения кода:

procedure TfrmMain.btnDeleteCookiesClick(Sender: TObject);
var
  CookieManager: ICefCookieManager;
begin
  CookieManager := TCefCookieManagerRef.GetGlobalManager;
  if not CookieManager.DeleteCookies('', '') then
    ShowMessage('Кукисы не удалены!');
end;

заведомо появится сообщение, что удаление кукисов провалилось. Не знаю, может, это только у меня так...

Решение же таково: надо обойти все хранящиеся кукисы с помощью VisitAllCookiesProc и внутри visitor-а установить их свойство deleteCookie равным True (1).

procedure TfrmMain.btnDeleteCookiesClick(Sender: TObject);
var
  CookieManager: ICefCookieManager;
begin
  CookieManager := TCefCookieManagerRef.GetGlobalManager;
  CookieManager.VisitAllCookiesProc(
    function(const name, value, domain, path: ustring; secure, httponly,
      hasExpires: Boolean; const creation, lastAccess, expires: TDateTime;
      count, total: Integer; out deleteCookie: Boolean): Boolean
    begin
      deleteCookie := True;
      ShowMessage('Кукисы для домена ' + domain + ' удалены!');
    end
  );
end;


суббота, 26 января 2013 г.

SQLite и Delphi 7: работа с БД с помощью DISQLite

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

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

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

Чем руководствовалась при выборе БД?
  • Максимальная простота и легкость.
  • Минимум телодвижений для работы приложения на другой машине: надо просто скопировать все содержимое папки к себе (кроме файлов БД нужна только dll).

понедельник, 14 января 2013 г.

Компонент TChromium: начало работы, установка

Сегодня речь пойдет о компоненте TChromium (dcef3). Что это за компонент и в чем его преимущества перед стандартным TWebbrowser?

Я могу назвать 2 главных преимущества, например, в привязке к разработке утилиты для Вконтакта. Во-первых, он пошустрее будет. Во-вторых, в нем очень удобная и простая работа с cookies.

Поясню второй пункт. Например, нам надо, чтобы через одну форму можно было работать с несколькими аккаунтами vk.com без постоянного "перелогинивания". В Webbrowser-е это можно организовать только шаманскими методами, а вот в Chromium-e решение выглядит очень красиво и просто.

Установка DCEF3 в Delphi7 (компонент TChromium)

На Googlecode можно найти 2 версии: старую (http://code.google.com/p/delphichromiumembedded/) и поновее (http://code.google.com/p/dcef3/). Рекомендую вторую.
  1. Скачиваем свежий дистрибутив с помощью SVN в папку c:\Program Files\Borland\Delphi7\Lib\dcef3.
  2. Загружаем Delphi, выбираем через "Open" пакет для D7, компилируем и инсталлируем. Если все хорошо, покажут TChromium в списке доступных компонентов на отдельной новой вкладке.
  3. Закрываем пакет, не сохраняя изменения в проекте.
  4. Проверяем Chromium в работе.

Тестирование работы компонента

Для теста создадим на форме 2 браузера, которые будут работать с независимыми друг от друга кукисами. С компонентом TWebbrowser такого так просто не добиться.

Размещаем на форме компонент TChromium и 2 кнопки.

В папку с проектом (или туда, куда компиллируется программа) копируем dll-ки из c:\Program Files\Borland\Delphi7\Lib\dcef3\bin\Win32\.

В uses дописываем библиотеку ceflib.

В обработчиках нажатия кнопок пишем:

const
  DefaultCookiesDir = 'Cookies/';
...
procedure TForm1.Button1Click(Sender: TObject);
var
  CookieManager: ICefCookieManager;
  CookiesPath  : String;
begin
  CookiesPath := ExtractFilePath(Application.ExeName) + DefaultCookiesDir + 'User1';
  CookieManager := TCefCookieManagerRef.Global;
  CookieManager.SetStoragePath(CookiesPath);
  Chromium1.Load('vk.com');
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  CookieManager: ICefCookieManager;
  CookiesPath  : String;
begin
  CookiesPath := ExtractFilePath(Application.ExeName) + DefaultCookiesDir + 'User2';
  CookieManager := TCefCookieManagerRef.Global;
  CookieManager.SetStoragePath(CookiesPath);
  Chromium1.Load('vk.com');
end;

Не ждите, что это уже получилось супер-приложение :) Я просто привожу пример, как для TChromium можно с легкостью переключать папки, в которых браузер хранит кукисы.

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


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

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

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

Тенденции применения парсинга и автоматизации в вебмастеринге и SEO

Думаю, все уже отошли от праздников и вовсю трудятся на свое собственное материальное благо. Вот и мне удается немного посидеть за компьютером.

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

Vk.com

Началось с того, что посмотрела небольшое видео по продвижению пабликов в Vkontakte. Оказывается, уже немало софта написано для автоматизации постинга, парсинга чужих пабликов, проставления лайков и т.д..
Отступление: если есть хороший софт с нужными функциями и поддержкой, то я предпочитаю заплатить. Так гораздо проще, чем самой писать с нуля. Именно поэтому я уже давно не занимаюсь парсингом выдачи, а использую KeyCollector. Для работы с социальной сетью vkontakte.ru многие используют Viking Botovod (я не тестировала, рекомендовать не могу, но видела промо-ролик).

Наполнение сайтов

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

Я сама против подобного наполнения сайтов. К тому же есть множество альтернатив использования автоматизации при их создании. Ведь если подумать хорошенько, можно найти варианты гораздо лучше, чем тырить чужие статьи. Тем более, что в этом случае и совесть спокойна, и конфликты с недовольными владельцами ресурсов исключены.

Мои эксперименты и их освещение на этом блоге

Всем вебмастерам, кто только начинает заниматься своими проектами, хочется найти заветную кнопку "Бабло". Кнопки такой не существует, но есть масса способов, которые могут сработать и принести хоть какую-никакую, но прибыль.

Скажу честно, я читала о всяких вариантах, но никогда их не пробовала реализовывать — всегда находились дела поважнее и, как большинство фрилансеров, испытывала нехватку свободного времени. Но сейчас решила немного себя перебороть и сделать что-нибудь "новенькое" для себя. Конечно же, нехватка времени в настоящий момент тоже остро стоит, но что делать...

Эксперимент №1

Программка для работы с Vkontakt-ом. С функционалом пока точно не определилась, решу по ходу. Пока приблизительно буду ориентироваться на тот же Viking. Конечно, будет не точь-в-точь.

Как настоящий динозавр, буду писать ее на своем любимом Delphi7.

Эксперимент №2

В рамках эксперимента №2 хочу создать какой-нибудь сайт из разряда "сделал и забыл" или хотя бы "сделал и подзабыл".

Как можно заработать на таком сайте?
  • Контекст. Ну, это мне знакомо, с этим я работаю.
  • Сапа. Никогда не пробовала использовать, почему-то жалко 2 своих основных сайтика :) — можно попробовать.
  • Партнерские программы.
Выбор тематики
Сайт будет заточен под региональные запросы. Тематика — недвижимость. Статьи и новости — закажу рерайт. База по риэлторам, база по предложениям (с досок объявлений). За счет большого числа объявлений можно добиться большого количества страниц в выдаче. Только объявления надо будет чем-нибудь дополнить, что ли. Каждое предложение можно также сопроводить отметкой на Яндекс.Карте.

Особенности
Буду делать не на привычных CMS, а напишу свои скриптики — читала о наблюдениях, что самописные сайты лучше воспринимаются поисковиками, чем на Wordpress/Joomla!.

Работу над этими проектами буду вести неспешно (опять же, из-за невозможности долго сидеть за компьютером). Статьи будут чередоваться как попало :) Но, думаю, будет интересно. По крайней мере — мне. Если есть желание следить за ходом дел, приглашаю подписаться на RSS. :)

понедельник, 31 декабря 2012 г.

C новым годом!

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

Дальше несколько слов лытдыбра, можно не читать (а можно и прочесть).

четверг, 10 марта 2011 г.

Delphi: Как удалить cookies из TWebBrowser?

В этой статье не будет ничего скандально нового :) Просто уже 2 комментатора спросили в заметке о cookies в TWebBrowser, как их удалять. В гугле, ясно дело, решение найти просто, но почему-то для кого-то проще спросить и ждать :)

В общем, если на мой блог о парсинге приходят по этому запросу, то надо на него ответить. :)

Это готовое решение, взятое из инета и опробованное мной. В результате будут подчищены все файлы с куками, хранящиеся в c:\Documents and Settings\Имя_пользователя\Cookies.

uses
WinInet;

procedure DeleteIECache;
var
lpEntryInfo: PInternetCacheEntryInfo;
hCacheDir: LongWord;
dwEntrySize: LongWord;
begin
dwEntrySize := 0;
FindFirstUrlCacheEntry(nil, TInternetCacheEntryInfo(nil^), dwEntrySize);
GetMem(lpEntryInfo, dwEntrySize);
if dwEntrySize > 0 then lpEntryInfo^.dwStructSize := dwEntrySize;
hCacheDir := FindFirstUrlCacheEntry(nil, lpEntryInfo^, dwEntrySize);
if hCacheDir <> 0 then
begin
repeat
DeleteUrlCacheEntry(lpEntryInfo^.lpszSourceUrlName);
FreeMem(lpEntryInfo, dwEntrySize);
dwEntrySize := 0;
FindNextUrlCacheEntry(hCacheDir, TInternetCacheEntryInfo(nil^), dwEntrySize);
GetMem(lpEntryInfo, dwEntrySize);
if dwEntrySize > 0 then lpEntryInfo^.dwStructSize := dwEntrySize;
until not FindNextUrlCacheEntry(hCacheDir, lpEntryInfo^, dwEntrySize);
end;
FreeMem(lpEntryInfo, dwEntrySize);
FindCloseUrlCache(hCacheDir);
end;


Для чего может пригодиться очистка кукисов? Ну, например, вы написали какое-то свое приложение с TWebBrowser и заходите на определенный сайт через список прокси... ;)
___

Сегодня объявляю гранд мерси akkadites, автору блога "Обзор полезного софта", и Seorit.ru за обзоры RSSAdder-а.
___
Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

пятница, 25 февраля 2011 г.

Delphi XE Starter за 199$ (5900 рублей)

Delphi XEТолько ленивый программист-блоггер не написал еще об этой акции, проводимой Embarcadero. Продукт Delphi XE Starter Edition можно купить за 199 баксов (или за 5900 рублей — ссылка на прайс).

Естественно, что у такой лицензии есть ограничения (и для кого-то они критические). Например, она может быть использована только в том случае, если годовой профит от разработанного программного обеспечения не превышает $ 1000. То есть практически никакого профита ;) Но почему-то мне эта акция приглянулась и я хочу ей воспользоваться. Тем более, что при покупке Delphi XE покупатель автоматически получает Delphi 2010, 2009, 2007 и 7.

Буду использовать эту лицензию конкретно дома (на работе все есть).

А вы как думаете, стоит оно того?
___

P.S. Всем дельным комментаторам большое спасибо за комментарии. И вообще большое спасибо всем читателям блога за то, что вы есть. Как только работы поубавится — все разберу.
___

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

четверг, 16 декабря 2010 г.

Delphi: работа с классами, унаследованными от TList

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

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

Самый простой пример такой объектной организации:
TBASetting  = class
BA : string;
MM_CONST : integer;
STRIKESTEP,
MIN_STRIKE,
MAX_STRIKE : double;
public
constructor Create(const aPath: string; const aParams: TStrings); overload;
...
end;

TBASettings = class(TList)
...
function LoadFromINI (IniFile : TIniFile) : boolean;
function SaveToINI (IniFile: TIniFile) : boolean;
procedure Clear; override;
end;

Остановлюсь подробнее на следующих пунктах:
- создание объектов, заполнение списка;
- освобождение памяти при "очистке" списка.

понедельник, 15 ноября 2010 г.

Delphi: работа с cURL с помощью библиотеки-обертки Curlpas

Indy и Synapse вам надоели? Самое время попробовать что-нибудь новенькое :)

Если кто-нибудь, начитавшись статей про cURL (я писала не раз про работу с cURL в PHP), решит попробовать работать с этой библиотекой и в Delphi, то ничего сложного в этом нет.

Установка CURL и работа с этой библиотекой в Delphi 7


1. Скачиваем файлы библиотеки libcurl с сайта разработчика по ссылке. Из всего разнообразия выбираем те, что подходят для нашей операционки. В моем случае это:
libcurl для Windows

Содержимое папки bin из скачанного архива копируем в C:\WINDOWS\system32\. Там несколько файлов dll:
Файлы библиотеки libcurl

2. Скачиваем готовую библиотеку-обертку CurlPas для работы с libcurl.

3. Распаковываем архив куда-нибудь, например, в C:\Program Files\Borland\Delphi7\Source\Curlpas\. Обратите внимание, в архиве есть еще документация и примеры использования (папка demo).

4. Запускаем батник Makewin.bat с параметром src (или all, чтобы уж не мелочиться :) ).

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

5. Можно приступать к тестированию библиотеки. Создаем приложение.

В uses прописываем:
uses
... curlobj;


Помещаем на форму кнопку, в обработчике нажатия пишем код:
procedure TForm1.Button1Click(Sender: TObject);
var
Curl: TCurl;
begin
Curl := TCurl.Create(nil);
Curl.URL := 'http://parsing-and-i.blogspot.com/';
Curl.OutputFile := 'curl.html';
if not Curl.Perform then
ShowMessage(Curl.ErrorString);
Curl.Free;
end;

Запускаем. Все должно без проблем скомпилиться, в итоге после нажатия кнопки в папке с проектом появится файл curl.html с html-кодом главной страницы моего блога :)

Возможные ошибки при установке Curlpas


По каким-то причинам могут не "подхватиться" библиотеки. Тогда после запуска приложения может появиться что-то типа такого сообщения:
Приложению не удалось запуститься, поскольку libcurl-3.dll не был найден. Повторная установка приложения может решить эту проблему.

Ошибка при установке libcurl в Delphi
Если компилятор запрашивает файл libcurl-3.dll, а в скачанном пакете libcurl у вас файл называется libcurl.dll (зависит от версии библиотеки), то найдите файл curl_h.pas (из папки C:\Program Files\Borland\Delphi7\Source\Curlpas\src\, если вы устанавливали по моей инструкции) и в нем исправьте название файла.

Потом перекомпилируйте библиотеку.

Если не находятся какие-то другие dll — еще раз проверьте их наличие в System32 (или другом каталоге, как у вас принято).

Вот, в общем-то, и все — установка завершена, можете работать с библиотекой дальше. В папке doc — достаточно полная документация. А онлайн документация есть здесь.
___

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

среда, 10 ноября 2010 г.

И снова с вами...

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

Начало осени было очень насыщенным: периоды интенсивной работы чередовались с интенсивным же отдыхом. Съездили с мужем отдохнуть в Таиланд. Несколько фоток.

Одно из "обычных состояний" — с картой в руках. Я — навигатор :)
Тайланд, Бангкок
Я и кузнечик: кто кого?
Паттайя. Кузнечик
Ну и широко известные тайские мальчики-девочки. Это самые "очевидные". Большинство же такие, что для идентификации надо приглядеться :)
Тайские девочки (в кавычках)
Фотографий привезли — море. Но здесь им, конечно, не место :)

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

Парсеры на заказ в настоящее время не пишу, обращаться не стоит. Пишу приложения для торговли на бирже с использованием QuikOrdersDOM SDK (SDK для работы с Квиком). Занимаюсь своими проектами (это как раз относится к "налаживанию источников дохода", о котором упоминалось в предыдущем абзаце). Для своих проектов программирую по мелочам, так что, в принципе, писать на блоге есть о чем — в ближайшем будущем посты ожидаются :)

Товарищи! По поводу RSSAdder-а. В свое время я обещала постовые всем, кто напишет обзор у себя на блогах. Я про это не забыла, только вот вычислить написавших мне трудно: blogger не показывает, а самой мне искать совсем некогда. Оставляйте в комментах ссылки на обзоры — все обещанные постовые будут размещены в новых записях на этом блоге.

___

Зачем тянуть с объявлением благодарностей? :) Спасибо artcher-у, автору блога "Web как философия жизни" за прекрасный обзор RSSAdder-а с картинками!

Так же спасибо SeoZIP-у ) Желаю удачи в развитии блога!
___

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

вторник, 24 августа 2010 г.

RSSAdder: обновление конфига

Приветствую всех, кто пользуется утилитой RSSAdder для полуавтоматического добавления RSS-лент в RSS-агрегаторы.

Выкладываю новый конфиг. Этот конфиг "увидел свет" благодаря Никите, который прислал свои исправления (из списка удалено 2 неработающих агрегатора) и добавления (добавлено аж 27 новых агрегаторов!), за что ему огромное спасибо :)

Сама я новый список еще не тестировала, но, наверное, вскоре пройдусь по нему.

Ссылка для скачивания: новый конфиг для RSSAdder-а (82 агрегатора).

Надеюсь, всем пригодится :)

понедельник, 16 августа 2010 г.

Delphi: работа с RegExp в dll

Как работать с RegExp в библиотеках? Дело в том, что библиотека VBScript_RegExp_55_TLB — майкрософтская, без проблем тут не обошлось.

Вроде экземпляр объекта TRegExp создается, но при попытке с ним поработать вылазит ошибка:

Не был произведен вызов CoInitialize.


Если честно, столкнулась с этим впервые, пошла в интернет искать. Пришлось подключать ActiveX и использовать CoInitialize/CoUninitialize.

Нашла статью про подобную проблему. Попробовала так:

var
...
RE : TRegExp;
NeedToUninitialize : Boolean;
begin
NeedToUninitialize := Succeeded(CoInitialize(nil));
try
RE := TRegExp.Create(nil);
RE.IgnoreCase := true;
RE.Multiline := true;
RE.Global := true;
...

finally
RE.Free;
if NeedToUninitialize then CoUninitialize;
end;
...
end;


Но и тут не заладилось: если CoUninitialize писать без try...except, то на нем вываливается. И что-то мне эта ситуация совсем не понравилась, как-то мутно: коинициализируется — а потом что? Не будет ли проблем, если работать с библиотекой в несколько потоков и т.д.? Даже если CoInitialize/CoUninitialize делать не в функции, а при регистрации либы.

Кто-нибудь из читателей блога сталкивался с чем-нибудь подобным? Как решали?
___

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

понедельник, 19 июля 2010 г.

Навигация по DOM-дереву в html

Сегодня статья опять будет про PHP Simple Html DOM Parser. Даже несмотря на то, что некоторым читателям эта тема могла хорошенько поднадоесть. :) Просто хочется собрать на блоге достаточное количество материала, к которому можно было бы отсылать вопрошающих по емэйлу.

Итак, навигация по DOM-дереву. Прямо здесь. Прямо сейчас. На примерах. (Так как теоретически она и так описана в инструкции к библиотеке).

Если вы читаете эту статью, то вам уже известно, что такое DOM-структура, древовидное представление данных, узлы дерева, родитель, потомок и т.д.. Структуру html-документа в виде дерева можно наглядно посмотреть в Firebug-е.
Древовидная структура html-документа в firebug
Там же есть закладка DOM, с содержимым которой советую ознакомиться новичкам. Из структуры, которая там раскрывается, вы наглядно увидите результаты обращения к дочерним элементам, отдельным узлам, свойствам, атрибутам и т.д..
DOM-структура html-документа в firebug
Но вернемся к PHP Simple Html DOM Parser.

четверг, 8 июля 2010 г.

Delphi: отладка, запись в лог

Давненько не писала про Delphi, а ведь именно в Delphi провожу большую часть дня :) Итак, сегодня расскажу о том, как я пишу логи.

Запись в лог я использую во всех более-менее серьезных проектах. Логирование помогает и на этапе отладки, и на этапе внедрения (иногда проще попросить прислать лог, чем со слов понять, в чем проблема). Давно уже использую для этих целей маленькую и удобную библиотечку uLog. Все, что от вас потребуется, это добавить ее в uses. Ну и по желанию некоторые настройки. Но даже уже без всяких настроек вы можете писать в лог с помощью процедуры sLog. Пример:
sLog ('MyProgram.log','Значение переменной ='+str);

Первый входной параметр — куда писать, второй — что писать. Если путь прописан не полностью — идет обращение к текущей директории проекта. Если файл не существует - он будет создан автоматически. В логе строчки появляются снабженные временем записи в лог. Пример части лога:
07.07.2010 16:34:11 [243] Starting...
07.07.2010 16:34:11 [243] Signature:A951D217D6B5E340 03040002 940000000500000001000000280A00000200000053657276696365205061636B2032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
07.07.2010 16:34:11 [243] LoadConf...
(в квадратных скобках после времени - миллисекунды)

Немного о настройках. Первое, что можно настраивать, - это файл по умолчанию, в который будет писаться лог. Для этого обращаемся к uLog.LogFileName.
Пример:
uLog.LogFileName := ExtractFilePath(GetModuleName(HInstance))+'TaskManager.log';

После установки LogFileName лог будет писаться в указанный файл, если первый входной параметр у sLog не будет задан:
sLog('','Инициализация прошла успешно');

Еще один параметр - EnableMessages. Он отвечает за то, будут ли появляться сообщения об ошибке в этой библиотеке (например, когда файл лога не указан и не задан по умолчанию).
uLog.EnableMessages := false;

И, наконец, самый замечательный параметр. Он передается в sLog третьим. Это "уровень логирования", LogLevel.
slog('','Starting library',2);
slog('',tmpS,3);

Вы сами проставляете этот уровень в зависимости от того, что за информацию пишете в лог. Градация, например, может быть такой:
  1. мегаважный

  2. информационный (запустился, ...)

  3. отладочный

Уровней может быть больше, сколько угодно. При приведенном в предыдущем абзаце варианте вы на этапе разработки используете LogLevel := 3, а когда устанавливаете продукт клиенту, ставите LogLevel 1 или 2. LogLevel удобно задавать в ini-файле и считывать при запуске приложения. Если вдруг у клиента внезапно начнутся какие-то сбои - под вашим руководством он сможет поменять уровень логирования на 3 и прислать вам файл с отладочной информацией, которая поможет вам выяснить причину сбоев.

суббота, 26 июня 2010 г.

Очистка текста от лишних html-тегов

С задачей очистки html от лишних тегов сталкиваются абсолютно все.

Первое, что приходит на ум, это использовать php-функцию strip_tags():
string strip_tags (string str [, string allowable_tags])


Функция возвращает строку, очищенную от тегов. В качестве аргумента allowable_tags передаются теги, которые не надо удалять. Функция работает, но, мягко говоря, неидеально. По ходу, там нет проверки на валидность кода, что может повлечь за собой удаление текста, не входящего в тэги.
Инициативные разработчики сложа руки не сидели — в сети можно найти доработанные функции. Хорошим примером является strip_tags_smart.

Применять или не применять готовые решения — личный выбор программиста. Так сложилось, что мне чаще всего не требуется "универсального" обработчика и бывает удобнее почистить код регулярками.

От чего зависит выбор того или иного способа обработки?

1. От исходного материала и сложности его анализа.
Если вам нужно обрабатывать достаточно простые htmp-тексты, без какой-либо навороченной верстки, ясные, как день :), то можно использовать стандартные функции.
Если в текстах есть определенные особенности, которые надо учесть, то тут-то и пишутся специальные обработчики. В одних может использоваться просто str_replace. Например:

$s = array('&acirc;&euro;&trade;' => '&rsquo;',         // Right-apostrophe (eg in I'm)
'&acirc;&euro;&oelig;' => '&ldquo;', // Opening speech mark
'&acirc;&euro;&ldquo;' => '&mdash;', // Long dash
'&acirc;&euro;' => '&rdquo;', // Closing speech mark
'&Atilde;&copy;' => '&eacute;', // e acute accent
chr(226) . chr(128) . chr(153) => '&rsquo;', // Right-apostrophe again
chr(226) . chr(128) . chr(147) => '&mdash;', // Long dash again
chr(226) . chr(128) . chr(156) => '&ldquo;', // Opening speech mark
chr(226) . chr(128) . chr(148) => '&mdash;', // M dash again
chr(226) . chr(128) => '&rdquo;', // Right speech mark
chr(195) . chr(169) => '&eacute;', // e acute again
);

foreach ($s as $needle => $replace)
{
$htmlText = str_replace($needle, $replace, $htmlText);
}


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

function getTextFromHTML($htmlText)
{
$search = array ("'<script[^>]*?>.*?</script>'si", // Remove javaScript
"'<style[^>]*?>.*?</style>'si", // Remove styles
"'<xml[^>]*?>.*?</xml>'si", // Remove xml tags
"'<[\/\!]*?[^<>]*?>'si", // Remove HTML-tags
"'([\r\n])[\s] '", // Remove spaces
"'&(quot|#34);'i", // Replace HTML special chars
"'&(amp|#38);'i",
"'&(lt|#60);'i",
"'&(gt|#62);'i",
"'&(nbsp|#160);'i",
"'&(iexcl|#161);'i",
"'&(cent|#162);'i",
"'&(pound|#163);'i",
"'&(copy|#169);'i",
"'&#(\d );'e"); // write as php

$replace = array ("",
"",
"",
"",
"\\1",
"\"",
"&",
"<",
">",
" ",
chr(161),
chr(162),
chr(163),
chr(169),
"chr(\\1)");

return preg_replace($search, $replace, $htmlText);
}

(В такие минуты как никогда радует возможность preg_replace работать с массивами в качестве параметров). Массив вы при необходимости дополняете своими регулярками. Помочь в их составлении вам может, например, этот конструктор регулярных выражений. Начинающим разработчикам может быть полезной статья "All about HTML tags. 9 Regular Expressions to strip HTML tags". Посмотрите там примеры, проанализируйте логику.

2. От объемов.
Объемы напрямую связаны со сложностью анализа (из предыдущего пункта). Большое количество текстов увеличивает вероятность, что, пытаясь предусмотреть и почистить все регулярками, вы можете что-нибудь да упустить. В этом случае подойдет метод "многоступенчатой" очистки. То есть очистить сначала, допустим, функцией strip_tags_smart (исходники на всякий случай не удаляем). Потом выборочно просматриваем некоторое количество текстов на выявление "аномалий". Ну и "зачищаем" аномалии регулярками.

3. От того, что надо получить в результате.
Алгоритм обработки может быть упрощен разными способами в зависимости от ситуации. Случай, описанный мной в одной из предыдущих статей, хорошо это демонстрирует. Напомню, текст там находился в div-е, в котором кроме него был еще div с "хлебными крошками", реклама адсенс, список похожих статей. При анализе выборки статей обнаружилось, что статьи не содержат рисунков и просто разбиты на абзацы с помощью <p></p>. Чтобы не чистить "главный" див от посторонних вещей, можно найти все абзацы (с Simple HTML DOM Parser это очень просто) и соединить их содержимое. Так что прежде чем составлять регулярки для чистки, посмотрите, нельзя ли обойтись малой кровью.

Вообще, между сторонниками парсинга html-кода, основанного чисто на регулярных выражениях, и парсинга, в основе которого лежит анализ DOM-структуры документа, в сети разгораются настоящие холивары. Вот, например, на оверфлоу. Невинный с первого взгляда вопрос вызвал очень бурное обсуждение (особенно обратите внимание на первый коммент, за который проголосовало уже более 3 тысяч человек, — чувак отжег :) ).
В общем, каждый выбирает то, что ему ближе и что лучше подходит для конкретной ситуации.

А какой способ предпочитаете вы?
___

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

среда, 23 июня 2010 г.

3 способа установки User Agent при работе с библиотекой Simple HTML DOM Parser

Про юзерагенты на этом блоге я уже рассказывала. И говорила, что "неподставление" данных о User Agent-е в заголовок вашего запроса может выйти вам боком. Как подставить данные, если вы пользуетесь библиотекой Simple HTML DOM Parser?

Есть несколько очевидных способов.

Способ 1. Используйте Simple HTML DOM Parser в связке с cURL.
Самый простой способ. И для меня — самый удобный. Для установки юзерагента используйте параметр CURLOPT_USERAGENT.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($cr, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)');
curl_setopt($ch, CURLOPT_TIMEOUT,5);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);

$html_curl = curl_exec($ch);
curl_close($ch);

$html = str_get_html($html_curl);



Способ 2. Можете установить браузер по умолчанию в php.ini или использовать ini_set().

Пример:
ini_set("user_agent","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");


Тоже достаточно простой и удобный способ. Первый я в основном использую из-за того, что, как правило, приходится работать с cURL-ом (и с его возможностями) при загрузке страниц, поэтому мне удобнее установить User Agent именно там. Если бы курл был не нужен - использовала бы ini_set.


Способ 3. Можете непосредственно внести изменения в функцию библиотеки load_file().
Я сама этот способ не пробовала, но в архивах на всякий случай записан этот способ, взятый с стэковерфлоу.

В исходном коде функция выглядит следующим образом:

// load html from file
function load_file() {
$args = func_get_args();
$this->load(call_user_func_array('file_get_contents', $args), true);
}


А ее модификация может быть, например, такой:

// load html from file
function load_file() {
$args = func_get_args();
// Added by Mithun
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n".
"Cookie: foo=bar\r\n"
)
);
$context = stream_context_create($opts);
$args[1] = FALSE;
$args[2] = $context;
// End Mithun
$this->load(call_user_func_array('file_get_contents', $args), true);
}


Еще раз напомню, для чего вам User Agent. Допустим, вы пишете парсер, краулер или бота. Некоторые вебмастеры в robots.txt запрещают доступ к материалам сайта, если в хэдэре запроса установлен User Agent, стандартный для библиотек, работающих с http (или информация о нем вообще отсутствует). Устанавливая User Agent, вы маскируете свой запрос так, словно он поступил от браузера.

Но в любом случае надо знать меру. Если вы генерируете сотни запросов в минуту, то никакой юзерагент вас не прикроет :)
___

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

вторник, 15 июня 2010 г.

Разработка парсера каталога статей на движке WordPress с использованием PHP Simple HTML DOM Parser. Пошаговая инструкция

Всем доброго дня! Сегодня я опять отвечу на вопрос читателя блога. Вопрос был задан еще до объявления об Акции "Разобрать на моем примере", тем не менее:

Маша, помогите пожалуйста спарсить http://articlet.com/, точнее расскажите что нужно делать пошагово.


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

Изучение ресурса и разработка алгоритма



Итак, первое, что мы сделаем, — посмотрим, что из себя представляет ресурс. Это каталог статей, сделанный на WordPress. Структура рубрикатора — двухуровневая. То есть в корне находится несколько разделов, в каждом из которых могут находиться подразделы. Доступ к подразделам можно осуществить и с главной страницы и с внутренней страницы раздела. Нам, естественно, удобнее собрать все с главной.

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

Поделиться