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

четверг, 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('’' => '’',         // Right-apostrophe (eg in I'm)
'“' => '“', // Opening speech mark
'–' => '—', // Long dash
'â€' => '”', // Closing speech mark
'é' => 'é', // e acute accent
chr(226) . chr(128) . chr(153) => '’', // Right-apostrophe again
chr(226) . chr(128) . chr(147) => '—', // Long dash again
chr(226) . chr(128) . chr(156) => '“', // Opening speech mark
chr(226) . chr(128) . chr(148) => '—', // M dash again
chr(226) . chr(128) => '”', // Right speech mark
chr(195) . chr(169) => 'é', // 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. Структура рубрикатора — двухуровневая. То есть в корне находится несколько разделов, в каждом из которых могут находиться подразделы. Доступ к подразделам можно осуществить и с главной страницы и с внутренней страницы раздела. Нам, естественно, удобнее собрать все с главной.

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

четверг, 10 июня 2010 г.

Delphi: пример поиска в структуре веб-страницы значения нужного элемента

Привет! Этот пост — ответ на вопрос читателя блога. Конкретный ответ на конкретный вопрос. Именно им я хочу положить начало акции "Разберу на вашем примере". Подробнее об акции и ее условиях читайте в конце этой статьи.


Цитата из письма:

Мне нужно с сайта http://stock.rbc.ru/demo/micex.0/intraday/eod.rus.shtml скачать хоть одну ячейку например: цену открытия акций Газпрома, и сохранить это значение в какую-нибудь БД или таблицу (например в таблицу PARADOX7) или в EXCEL (лучше PARADOX7). И все, мне больше ничего не требуется, Ваша программа будет служить мне эталонным примером, а дальше я сам разберусь.
...
Я пытаюсь работать в среде С++Builder6 и пробовал использовать компонент XMLDocument, но кроме того как вытащить его на форму ничего не могу с ним сделать. Буду рад если вы напишите мне на С++Builder, но насколько я знаю, что С++Builder и DELPHI имеют множество сходств то и программе написанной на DELPHI буду благодарен...


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

Итак, код для поиска элемента:

воскресенье, 6 июня 2010 г.

User-Agent и идентификация. Взгляд с разных сторон

Думаю, что все, кто занимается программированием для web, знают, что такое User-Agent и с чем его едят. Я решила немного обобщить знания и собрать их в одной статье. Сначала определение (Википедия в помощь).

User Agent — это клиентское приложение, использующее определённый сетевой протокол. Термин обычно используется для приложений, осуществляющих доступ к веб-сайтам, таким как браузеры, поисковые роботы (и другие «пауки»), мобильные телефоны и другие устройства.
При посещении веб-сайта клиентское приложение обычно посылает веб-серверу информацию о себе. Это текстовая строка, являющаяся частью HTTP запроса, начинающаяся с User-agent: или User-Agent:, и обычно включающая такую информацию, как название и версию приложения, операционную систему компьютера и язык. У «пауков» эта строка часто содержит URL и email-адрес, по которым веб-мастер может связаться с оператором «паука».


User-Agent и вебмастер


Что дает вебмастеру и оптимизатору знание о таком понятии как User-Agent? Если знать названия поисковых роботов (и роботов различных ресурсов, краулеров и т.д.), то можно самостоятельно регламентировать доступ этих роботов к различным частям сайта. Это делается в небезызвестном файле robots.txt, который должен находиться в корневой папке сайта.

Вот как описан механизм работы робота Яндекса в зависимости от настроек в robots.txt (полная версия мануала по использованию robots.txt):

В роботе Яндекса используется сессионный принцип работы, на каждую сессию формируется определенный пул страниц, которые планирует закачать робот. Сессия начинается с закачки robots.txt сайта, если его нет, он не текстовый или на запрос робота возвращается HTTP-код отличный от '200', считается, что доступ роботу не ограничен. В самом robots.txt проверяется наличие записей, начинающихся с 'User-agent:', в них ищутся подстроки 'Yandex', либо '*' (регистр значения не имеет), причем, если обнаружено 'User-agent: Yandex', директивы для 'User-agent: *' не учитываются. Если записи 'User-agent: Yandex' и 'User-agent: *' отсутствуют, считается, что доступ роботу не ограничен.


Итак, для "управления" зоной видимости определенного робота надо добавить в robots.txt несколько строк. "Распознаются" директивы Allow и Disallow, соответственно разрешающие и запрещающие доступ роботу/краулеру/и т.д. к определенным частям вашего ресурса.

Списки названий роботов поисковиков открыты, их можно без проблем найти в интернете. Вот, например, совсем недавно, буквально месяц назад (6 мая 2010 года), на блоге Яндеска был опубликован свеженький список User-Agent-ов его роботов.

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

User-agent: Googlebot-News
Disallow: /archives


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

User-agent: Googlebot
Disallow: /

User-agent: Googlebot-News
Disallow:


Первая группа определит правило для всех гуглеботов, а вторая изменит установленные ранее правила конкретно для Googlebot-News.

Помимо роботов поисковых систем по сети шарят множество всяких краулеров, собирающих контент для разных нужд. В буржунете их наблюдается больше, по крайней мере больше жалоб :) Краулеры могут поднимать нагрузки на ваш сервак на нежелательный уровень. А "палятся" некоторые из них, как вы уже, наверное, догадались, своими User-Agent-ами. В буржунете я не раз встречала целые списки юзерагентов для блокировки, выложенные в паблик. При желании вы можете их найти. Например: The top 10 spam bot user agents you MUST block. NOW. ("Десять User-agent-ов спам-ботов, которые вы ДОЛЖНЫ заблокировать. НЕМЕДЛЕННО.") Или, как вариант, можете посмотреть сайт Bots vs Browsers, на котором в момент написания статьи собрана информация о 499551 юзерагентах, из которых ботов - 4439. Или уже известный многим сайт www.user-agents.org.

User-Agents vs browsers

Информацию о юзерагентах ваших "посетителей" вы можете посмотреть в лог-файле статистики. Если увидите что-нибудь подозрительное — уже знаете, как поступить :)

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


User-Agent и программист парсеров :)


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

Итак, рассмотрю вопрос применения знаний о User-Agent-ах со стороны создателя парсеров. Все более-менее серьезные библиотеки работы с HTTP поддерживают возможность подстановки в заголовки формируемых запросов "левой" информации о браузере. Не забудьте поменять установленные по умолчанию значения на что-нибудь более правдоподобное. (Отсутствие информации о браузере подозрительно в первую очередь). У Indy, например, по умолчанию стоит

Mozilla/3.0 (compatible; Indy Library)


Ну как тут не спалиться? Это первый претендент на добавление в black-list.

libwww, lwp-trivial, curl, PHP/, urllib, GT::WWW, Snoopy, MFC_Tear_Sample, HTTP::Lite, PHPCrawl, URI::Fetch, Zend_Http_Client, http client, PECL::HTTP — все это может вас выдать с головой.

Самый простой способ, это создать файлик со всевозможными браузерами, а потом при организации запроса подставлять рандомно одну из записей. Ресурсов с базами подходящих User-Agent-ов - масса, ссылки на них я приводила в первой части статьи.
___

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

понедельник, 31 мая 2010 г.

PHP: построчное чтение и обработка больших CSV-файлов

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

В предыдущей статье были рассмотрены разные варианты импорта CSV-файла в базу данных MySQL. Там же я отметила, что работа с большими файлами требует особого подхода. Основным ограничением для импорта большого объема данных является время выполнения скрипта, которое задается хостером (как правило 30 секунд).

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

Когда я прочитала в описании утилиты BigDump (в предыдущей статье я на нее ссылалась) о принципе работы:

The script executes only a small part of the huge dump and restarts itself. The next session starts where the last was stopped. (Перевод: Скрипт выполняет лишь небольшую часть SQL-команд из файла и перезапускает сам себя. В следующий раз импорт начинается с того места, в котором скрипт прервал свою работу.)


я поняла, что мне обязательно нужно попробовать такое решение. Поиски в инете чего-то похожего окончились успешно.

четверг, 27 мая 2010 г.

Запись данных из CSV-файлов в базу MySQL

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

Итак, у вас есть CSV-файл, и перед вами встала задача записать содержимое этого файла в базу.

Импорт CSV-файла через PHPMyAdmin


Первый и самый простой способ — воспользоваться готовым инструментом. Например, функция импорта данных из csv-файла в базу есть в PHPMyAdmin-е.

Выбираем нужную таблицу, на вкладке "Структура" внизу нажимаем на "Вставить текстовые файлы в таблицу". Указаваем настройки импорта.




Внимание! Если после нажатия "Выполнить" у вас вылезли ошибки типа

ldi_check.php: Missing parameter: db
ldi_check.php: Missing parameter: table


это может объясняться разными причинами.

1. Возможно, файл, предназначенный для импорта, слишком большой. В старых версиях PHPMyAdmin (младше 2.7.0) был баг с импортом больших файлов. Так что, возможно, выходом из ситуации будет обновление PHPMyAdmin-а.

(Ссылка на пункт 1.16 FAQ) Начиная с версии 2.7.0 функция импорта была переписана и проблем с импортом больших файлов не должно возникать.

Следующее, что можно проверить (или спросить у провайдера), - это значения параметров upload_max_filesize, memory_limit и post_max_size в конфигурационном файле php.ini. Эти три настройки ограничивают максимальный размер данных, которые могут быть переданы и обработаны PHP.


Там же, в документации, приводится описание нескольких "обходных путей", которые подойдут, если вы импортируете не scv-файл, а заливаете дамп базы, а ваш провайдер не хочет менять настройки:

а) Проверьте настройку $cfg['UploadDir']. Она позволяет настроить загрузку файла на сервер через scp, ftp или другим методом. PhpMyAdmin может работать с файлами, расположенными во временном каталоге. Более подробную информацию читайте в разделе Настройки документации.

б) Используйте сторонние утилиты (например, BigDump) для того, чтобы разбить файл перед загрузкой.

в) Если у вас есть прямой shell доступ, используйте MySQL для импорта файлов напрямую. Вы можете это сделать с помощью команды "source":
source filename.sql

2. Если файл небольшой, но эти ошибки все же появляются, то вам может помочь вот эта тема на форуме.

Парсинг CSV-файла с помощью PHP


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

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

четверг, 20 мая 2010 г.

PHP Simple HTML DOM Parser

Сегодня я немного расскажу про библиотеку для парсинга HTML под названием PHP Simple HTML DOM Parser. В последнее время частенько ей пользовалась: нравятся ее возможности и простота. Скачать библиотеку можно со страницы. В комментарии к сказано:

A simple PHP HTML DOM parser written in PHP5+, supports invalid HTML, and provides a very easy way to handle HTML elements.


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

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

С помощью этой библиотеки вы можете обращаться к элементам и атрибутам элементов, искать определенного уровня вложенные элементы, фильтровать их, искать текст и комментарии(!).

Приведу примеры из документации:

// Найти ссылки и возвратить массив найденных объектов
$ret = $html->find('a');

// Найти (N)-ую по счету ссылку и возвратить найденный объект или null в случае, если объект не найден
$ret = $html->find('a', 0);

// Найти все элементы <div>, у которых id=foo
$ret = $html->find('div[id=foo]');

// Найти все элементы <div>, имеющие атрибут id
$ret = $html->find('div[id]');

// Найти все элементы, имеющие атрибут id
$ret = $html->find('[id]');


Ну и, конечно, стандарто - в библиотеку заложена возможность перемещения по списку элементов объектного дерева. Для этого используются:
$e->children( [int $index] ), 
$e->parent(),
$e->first_child(),
$e->last_child(),
$e->next_sibling(),
$e->prev_sibling().


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

вторник, 27 апреля 2010 г.

Работа с комбобоксами (SELECT) в TWebbrowser

В интернете достаточно материала о том, как работать с элементом SELECT в TWebBrowser. У себя на блоге я мельком уже задевала уже этот вопрос, но вот решила написать отдельный пост.
Тем, для кого этот материал вновинку, сначала советую ознакомиться со статьями:

1. TWebBrowser, OleObject и его свойства.
2. Работа с формами в TWebBrowser.

Обычно я делаю так: сначала ищу на форме нужный селект по имени (тип искомого объекта - IHTMLSelectElement (не забудьте подключить библиотеку MSHTML)). Селект можно находить по id или по name, в зависимости от требований. Вот пример функции, возращающей требуемый элемент (проверяется и по id, и по name):

function FindCBByName(CBName: String) : IHTMLSelectElement;

function TMainF.FindCBByName(CBName: String): IHTMLSelectElement;
var
i : integer;
DocSelect : IHTMLElementCollection;
DocElement : IHtmlElement;
Doc : IHTMLDocument2;
begin
Result := nil;
WB.Document.QueryInterface(IHTMLDocument2, Doc);
DocSelect := Doc.all.tags('SELECT') as IHTMLElementCollection;

for i := 0 to DocSelect.length-1 do
begin
DocElement := DocSelect.Item(i, 0) as IHtmlElement;
if (UpperCase(DocElement.id) = UpperCase( CBName )) or
(UpperCase(DocElement.getAttribute('name',0)) = UpperCase( CBName )) then
begin
Result := DocElement as IHTMLSelectElement;
exit;
end;
end;
end;


В случае, если объект не найден, возвращается nil. В данном примере у меня привязка к объекту TWebBrowser (WB) на форме. Можно избавиться от нее, добавив TWebBrowser в качестве параметра функции (я так обычно и делаю).

Когда элемент найден, в нем надо будет выбрать значение. В зависимости от задачи, требуется обычно выбрать option по тексту или по value.

В качестве примера привожу процедурку, которая уже "светилась" в статьях на этом блоге.

пятница, 23 апреля 2010 г.

Установка web-сервера (XAMPP) на Ubuntu на Eee PC

install xampp on eee pc
Чтобы в дороге и в отпуске заниматься программированием, решила на нетбук установить сервер. Порывшись в инете, остановилась на XAMPP. Скачала дистрибутив последней версии с официального сайта. При попытке установить пакет на Eee PC, вылезло сообщение о том, что на диске недостаточно места. Меня это удивило, так как места было вполне достаточно. Но, как потом оказалось, не там, где надо :) С линуксом я до этого момента практически не имела дела, поэтому на разбирательства ушло какое-то время.

Сначала пришлось познакомиться с некоторыми базовыми командами.
Консоль можно вызвать с помощью сочетания горячих клавиш "Ctrl+Alt+T". Если оно не срабатывает (было, что один раз сглючило, и положение исправилось только после перезагрузки), то можно загрузить диспетчер файлов и при открытом окне нажать "Ctrl+T".

cd - смена текущей директории
ls - листинг каталога
chmod - изменение прав доступа на файл/директорию


и так далее. В принципе, тех, которые мне потребовались, с полдесятка.

четверг, 1 апреля 2010 г.

RSSAdder. Свежий конфиг

Сегодня возникла необходимость прогнать один фид по RSS-агрегаторам. RSSAdder я все еще не до конца переделала, поэтому прогоняла старой версией. Попутно решила обновить данные в конфиге. Результаты обновления были, мягко говоря, "не очень": из 65 каталогов в списке осталось только 51. Остальные так или иначе покинули всемирную паутину или переродились во что-нибудь еще более говнистое :) Потом я вспомнила о конфигах, давным-давно присланных одним из читателей блога, добавила в общий список еще 5 каталогов. Получилось 56 проверенных ресурсов.

Выкладываю свежий список и еще конфиг со списком пинг-сервисов, так же предоставленный этим благородным читателем %D. Сразу скажу, что пинг-сервисы не проверены, если заметите ошибки — пишите. Хотя, судя по тому, что в старом списке со временем появилось столько битых каталогов, но никто об этом не написал, обратной связи особо ждать не следует :) В общем, еще раз гранд мерси читателю, подписавшемуся как LookUp, все остальным — свежие конфиги. (Для обновления просто скопируйте файл в папку поверх старого).

___

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

вторник, 23 марта 2010 г.

Вопросы-ответы

Вдогонку к предыдущему посту (и отвечая на вопрос, заданный по почте):

Чтобы просмотреть в Google Chrome код страницы (например, xml, сгенерированного с помощью php), нужно написать в адресной строке префикс "view-source:". Например:
view-source:http://site.ru/xml.php?id=262.

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

Могу порекомендовать сервис вопросов-ответов help.sander.su, о котором уже недавно упоминала в комментариях к одному из сообщений. Я буду перенаправлять туда вопросы, с решением которых сама не сталкивалась и на разбор которых нет времени. И, соответственно, отвечать там на те, с которыми сталкивалась :)

Польза от исследования кода в разных браузерах

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

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

Пример страницы: http://med-edu.ru/basic-science/biohim/shnol1/262. При клике на заставку открывается плеер, в котором можно посмотреть и видео, и слайды презентации:

parsing video

В Goodle Chrome находим javascript-функцию, отвечающую за показ видео. Не очень очевидно, не правда ли? :)

function loadVideo() {

scroll(0,0);

darDiv.id = 'darkDiv';
newDiv.id = 'divVideo';
newDivCont.id = 'contVideo';

document.body.appendChild(darDiv);
document.body.appendChild(newDiv);
newDiv.appendChild(newDivCont);

so = new SWFObject("/pl/player7v_n_api_y.swf", "sotester", "1047", "711", "8", "0");
so.addVariable("xml_php", "/");
so.addVariable("php_seek", "http://www.medvideo.org/video/flvid/");
so.addVariable("id", "262");
so.addParam("scale", "noscale");
so.addParam("salign", "ct");
so.addParam("bgcolor", "#333333");
so.addParam("wmode", "transparent");
so.addParam("allowFullScreen", "true");
so.write("contVideo");
}


А вот как та же самая функция loadVideo выглядит в никем не любимом IE:

function loadVideo() {
scroll(0,0);
$("body").prepend('<div id="embedplayer" style="position: absolute; z-index: 99; top: 10px; width: 100%;" align="center">
<embed width="1047" height="711" flashvars="xml_php=/xml.php?id=262&amp;php_seek="
allowfullscreen="true" wmode="transparent" salign="ct" scale="noscale" quality="high" bgcolor="#333333" name="video" id="123" style=""
src="/pl/player7v_n_api_y.swf" type="application/x-shockwave-flash" base="/"/></div>');
$("body").prepend('<div id="darklayer" style="position: absolute; z-index: 98; width: 100%; height: 1300px;
background: none repeat scroll 0 0 #444444; filter:alpha(opacity=60); -moz-opacity: 0.6; opacity: 0.6;"></div>');
}


Итак, стало все намного очевиднее, flashvars открывают завесу тайны :)

Заходим по ссылке http://med-edu.ru/xml.php?id=262 и видим:
parsing xml src video

То есть непосредственно нужный нам файл с видео имеет такой адрес:
http://www.medvideo.org/video/flvid/00000178.flv.

Ну и, соответственно, для скачивания других роликов с этого сервиса алгоритм определился:
- узнаем id видео (парсингом исходного кода страницы)
- загружаем xml.php?id=...
- парсим полученный xml и находим значение атрибута File.

Удачи в исследованиях! :)
___

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

среда, 10 марта 2010 г.

Пример парсинга вопросов с labs.wordtracker.com (Synapse, Delphi)

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

Первым делом посмотрела наработки Сергея (либу IngHTTPSend), предложенные им в комментарии к моей первой статье о Synapse. Безусловно, у него в обертку включены очень полезные функции (в том числе уделено большое внимание кодировкам). Но у каждого программиста есть еще ряд функций, которые он таскает с собой в голове и дописывает к любым своим либам :) Например, у меня есть некоторые заморочки по поводу хэдеров запросов. Я обычно создаю несколько функций для формирования заголовков с одинаковым названием, но с разным набором входных параметров. Например, в функцию может передаваться UserAgent, а может и не передаваться (если не передается, то берется случайный из списка возможных). Обработчики кодов ответа (в частности, 3XX) я тоже обычно выношу.

А потом пришла к выводу, что ни для чего "глубокомысленного" я сегодня не готова, глянула в списочек ссылок ресурсов, подходящих для демонстрации написания простейших парсеров, и решила поместить в блоге пример с кодом парсера вопросов с http://labs.wordtracker.com/keyword-questions/.
parsing keyword SEO questions from wordtracker

Ресурс Wordtracker.com я уже брала в качестве "подопытного" для иллюстрирования возможностей cURL.

Вопросы будем добывать с использованием Synapse.

пятница, 19 февраля 2010 г.

Составление технического задания (ТЗ) на разработку парсера

Ко мне очень часто обращаются по поводу разработки парсеров. В принципе, я и стремилась именно к этому, когда заводила блог "Парсинг от А до Я". Проанализировав обращения потенциальных заказчиков, я поняла: чтобы облегчить себе жизнь - я должна написать о том, в каком виде хотелось бы получать заказы. Иначе - только четверть обращается с ТЗ, по которому нужны минимальные уточнения (либо даже не нужны совсем). Остальные - с общими фразами "нужно спарсить данные с такого-то сайта. оцените сроки и стоимость, во сколько мне обойдется это, если я закажу парсер вам?". Исходя из чего я должна оценивать сложность и объем работ при такой формулировке?

Итак, грамотное техническое задание - залог того, что не понадобится недельная переписка, чтобы клещами вытянуть из заказчика описание того, чего именно он хочет. Даже если вы заказываете парсер не у меня :) , ТЗ будет полезно. В первую очередь - вам самим, бо вы поймете и сформулируете в письменном виде свои пожелания.

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

1) Название ресурса, ссылка. Если необходим парсер только определенного раздела или разделов - указываете здесь же с перечислением всех ссылок (или с перечислением тех ссылок, которые надо исключить).

2) Данные или инструмент? Что вы хотите получить в итоге? Может, вам просто единоразово требуется получить данные? Или вам нужна программа/скрипт для того, чтобы самостоятельно получать требующиеся вам данные в любое время?

3) Если вам нужен "инструмент"
3.1. Это должен быть скрипт, парсер в виде десктопного приложения или все равно? У каждого вида есть определенные особенности. Скрипты обычно заказывают те, кто хочет запускать их по расписанию на хостинге, чтобы, например, регулярно обновлять данные на своем сайте. Вам подойдет десктопное приложение, если данные, полученные в результате парсинга, будут вами как-нибудь обрабатываться (возможно, автоматизированно) и анализироваться, прежде чем "пойдут" дальше. Причины выбора того или иного исполнения могут быть разными.

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

3.3. Нужна ли поддержка работы через прокси-листы? Или какой-нибудь иной метод преодоления защиты от ботов, если таковая имеется на сайте?

4) Формат данных.
В каком виде вы хотите получить результирующие данные? Текстовый файл или база данных? У вас разработана структура базы (в этом случае следует ее приложить) или вы хотели бы, чтобы я сама ее разработала? Когда дело доходит до обсуждения этого пункта, я обычно прошу прислать скрины страниц ресурса-"донора" с выделенными (или каким-то другим образом помеченными) в графическом редакторе блоками. Это еще и играет роль гаранта, что клиент потом не скажет, что имел в виду другое и что мы друг друга не поняли. Если требуемая информация состоит из перечня "параметр - значение" (в большинстве интернет-магазинов), то следует оговорить, надо ли каким-то образом разбивать ее на поля или "выдирать" одним целым, прямо с версткой (например, в виде таблицы). Естественно, что от всего этого напрямую будет зависеть цена.

5) Оплата.
Для кого-то это очень щекотливая тема. Ничего щекотливого в ней не вижу. Свое рабочее время оцениваю 10$/час, прикидываю, сколько потрачу "чистого" времени, определяю сумму, потом по времени буру период с небольшим запасом, чтобы можно было потестировать. Если требуются только данные - пишу парсер и запускаю. Данные предоставляю после отработки программы (когда сайты большие - заранее время определить не могу, тут уж как все сложится - так сложится). Предоплата - 50%.

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


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

Желаю удачи всем заказчикам! Ну и фрилансерам заодним :))
____

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

четверг, 4 февраля 2010 г.

Работа с библиотекой Synapse в Delphi - начало

Обычно для работы с инетом в своих приложениях я использую компоненты Indy или сокеты. И вот решила, что неплохо было бы расширить свой кругозор и познакомиться с другими библиотеками (и будет вдвойне приятно, если это знакомство окажется полезным).

Первое, что я решила опробовать, это библиотека Synapse. Я уже не раз встречала упоминания о ней, но все как-то не доводилось поработать.

Скачиваем, устанавливаем.

Установка Synapse

(в моем случае на старенький Delphi 7).

1. Распаковать архив в какую-нибудь папку (в Source, например)
2. В меню идем Tools - Environment Options - Library и добавляем в Library Path путь к папке ..Source\SYNAPSE\LIB
3. В новосозданном проекте добавляем в Uses-ы httpsend и synacode (при надобности).

Пришло время "HelloWorld"-а.

Простые примеры кода с использованием Synapse


Давайте начнем с самых простых вещей - с получения содержимого страницы.

Поместим на форму кнопку и TMemo, добавим в uses httpsend, напишем обработчик нажатия кнопки:

procedure TMainF.Button1Click(Sender: TObject);
begin
if not HttpGetText('http://parsing-and-i.blogspot.com', Memo1.Lines) then
ShowMessage('Что-то не получилось.');
end;

После нажатия на кнопку в мемо появилось содержимое страниц. Старт взят: с помощью HttpGetText задачу выполнили.

Дальнейшее изучение библиотеки можно проводить так — заглянуть непосредственно в файл библиотеки (httpsend.pas). Главным классом является THTTPSend. Даже просто изучив его структуру, можно понять принципы работы и возможности.

Итак, HTTPSend.Document возвращает содержимое всего документа. Поэкспериментируем с использованием еще каких-нибудь элементарных функций. Например, получим заголовок страницы и отдельно код ответа.

четверг, 21 января 2010 г.

Добавление и удаление атрибутов узлов (вершин) в XML в Delphi (с использованием компонента TTreeView)

Предыдущая статья на тему — "Добавление и удаление вершин в XML (визуализация с помощью TTreeView)".

Продолжаю развивать начатую тему про редактирование XML. Сегодня будем добавлять и удалять атрибуты узлов.

Для этого создадим контекстное меню и привяжем его к объекту TValueListEditor, расположенному на закладке Attributes (исходники полученной на ранних этапах заготовки можно скачать). Напомню, что атрибуты и их значения попадают в ValueListEditor благодаря следующему участку кода в обработчике события OnClick экземпляра компонента TTreeView:

try
ValueListEditor.Strings.Clear;
for i := 0 to iNode.AttributeNodes.Count -1 do
ValueListEditor.InsertRow(iNode.AttributeNodes[i].NodeName,
iNode.AttributeNodes[i].Text,true);
except
end;


В меню создаем 2 пункта (Insert и Delete) и прописываем в их обработчиках:

среда, 13 января 2010 г.

Добавление и удаление узлов (вершин) в XML в Delphi (с использованием компонента TTreeView)

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

Сегодня появилось немного свободного времени, и я решила посвятить его развитию блога. Итак, проанализировав запросы, по которым приходят на этот ресурс, я решила дополнить его статьей о работе с XML в Delphi. Я уже затрагивала этот вопрос в материале "Отображение XML в виде дерева (TreeView): Delphi". К сожалению, тогда была невнимательной и как-то упустила комментарии о том, что в листинге отображены не все процедуры. В этот раз постараюсь исправиться и наряду с объяснениями выложить исходники того, о чем пойдет речь.

Итак, в той статье было описано отображение XML в TTreeView. А сейчас попытаемся сделать из просмотрщика редактор XML. Не сразу, постепенно. Понимаю, что как таковой самописный редактор XML вам не понадобится, тем более, что в сети можно найти много бесплатных утилит с полным набором требуемых функций, но новичкам будет полезно посмотреть, как сделать это своими руками. Вдруг в каком-нибудь вашем проекте вы решите поработать с XML... Собственно, я и решила написать этот пост про XML, так как стала переделывать RSSAdder: он будет работать не с ini-файлом, а с xml, и пользователям не придется совершать пляски с бубном, чтобы добавить в список новый агрегатор или изменить настройки у существующего.

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

Поделиться