29th Ноябрь 2007, 02:11 пп
Главным оружием любого профессионального парсера являются регулярные выражение (особенно перловые PCRE). И я, если честно, вообще не представляю как без них можно делать просто и быстро свою работу.
Одним словом просто прелесть. И эту прелесть мы каждый день используем.
Сечас я приведу 2 классических варианта использования регулярных выражений:
if (preg_match("/$price_find/Ui",$content,$m)) {
unset($m[0]);
$price=mysql_escape_string(trim($m[1]));
} else {
$price='';
}
if (preg_match_all("/$blocks_find/Ui",$content,$m)) {
unset($m[0]);
$blocks=$m[1];
} else {
$blocks=array();
}
На первый взгляд довольно таки простой код. Ни отнять, ни прибавить. А теперь представьте, что вам надо искать по 100 параметров на странице. И тогда этот код начнет непомерно расти и станет для вас настоящим наказанием. В подобных случаях я использую две небольшие функции, которые действительно упрощают мне жизнь и уменьшают время, затрачиваемое на разработку:
function pregm($what, $where, $return=1, $keys='Ui') {
$search="/$what/$keys";
if (preg_match($search,$where,$matches)) {
unset($matches[0]);
if ($return==1) {
return $matches[1];
} else {
return $matches;
}
} else {
return false;
}
}
function pregma($what, $where, $return=1, $keys='Ui') {
$search="/$what/$keys";
if (preg_match_all($search,$where,$matches)) {
unset($matches[0]);
if ($return==1) {
return $matches[1];
} else {
return $matches;
}
} else {
return false;
}
}
Благодаря этим функциям весь начальный код можно преобразовать к следующему виду:
$price=mysql_escape_string(trim(pregm($price_find,$content));
$blocks=pregma($blocks_find,$content);
Вот так все просто. Мы сократили объем кода в несколько раз и сделали его более прозрачным и простым.
Конечно же если регулярные выражения вы используете два раза в год, то прибегать к данной библиотеке нет смысла, но если регулярки - ваша повседневная работа, то вам надо максимально использовать вышеупомянутый код и даже развить его под свои нужны. Так я, например, в случаях, когда надо найти большое количество параметров, использую массивы. Вот пример:
$param=array(
'Название',
'Цена',
'Размер',
'Автор'
//...
);
$find=array();
// Получаем контент и делаем прочие преобразования
foreach ($param as $key=>$item) {
$find_it=$item."\:(.*)$";
$find[$key]=strip_tags(pregm($find_it,$block));
}
Получится, что в массиве $find у нас будут все найденные параметры. Потом можно просто сделать implode("','",$find), добавить пару кавычек и практически целиком залить эту строку в базу. Получается очень быстро и удобно.
Суть этой заметки. Регулярные выражения - мощный инструмент, а свои надстройки над ними - еще более мощный и удобный инструмент!
27th Ноябрь 2007, 01:22 пп
На днях закончил проверку новой системы GrabVIA для сбора изображений, аудио- и видеоконтента.
В течении двух суток данной системой было собрано 194 766 изображение суммарным размером около 5 ГБ.
Так что я думаю, что система вполне работоспособная и готова к выполнению даже самых сложных заданий.
27th Ноябрь 2007, 01:06 пп
Ребята, я вас очень прошу не пытаться взломать мой сайт, потому что ничего интересного на нем, даже если вы его сломаете, не найдете. На этом хостинге я свой движок не держу. Тут только блог.
Это относится к тем, кто вчера целый день в комментах писал подобные вещи:
“>alert(’xss’)
25th Ноябрь 2007, 10:13 пп
В последнее время я заметил, что очень многим заказчикам необходим сбор большого объема изображений, аудио- и видеоконтента. Поэтому я решил выделить данный вид работы в отдельную услугу.
Спецификой работы по сбору подобного контента является то, что БД имеет второстепенное значение, в то время как выдвигаются дополнительные требования к дисковой системе и скорости интернет-канала. Все эти особенности учтены в разработанной мной системе GrabVIA, предназначенной ИСКЛЮЧИТЕЛЬНО для сбора вышеуказанного контента.
ТТХ услуги:
- 2 сервера (для очень крупных заказов возможно выделение до 4 серверов);
- неограниченное время сбора информации (24/7/365);
- сбор информации блоками до 100 Гб (100 Гб собрали -> отгрузили заказчику -> приступили к сбору очередных 100 Гб).
В качестве входных параметров для начала предоставления данной услуги могут выступать:
- текстовый файл с адресами файлов для скачивания;
- парсинг страниц для нахождения контента для скачивания.
Также возможна автоматизация работы:
- вы даете мне параметры для доступа к FTP и весь собранный контент, с указанной вами регулярностью, синхронизируется с вашим сервером (также возможно настроить синхронизацию БД, если попутно со сбором контента будет собираться какая-то информация или параметры).
18th Ноябрь 2007, 04:33 пп
За прошедшие несколько месяцев парсинг, граббинг и сбор информации показали себя как достаточно актуальные и востребованные услуги на современном рынке IT-услуг.
В связи с этим я хочу еще более расширить список клиентов компании ParserPro и в качестве первого шага на этом нелегком пути я представляю партнерскую программу.
С сегодняшнего дня в нашей компании действует партнерская программа на следующих условиях:
- За каждого приведенного мне клиента участник партнерской программы получает 20% от стоимости заказа клиента.
- Если участник партнерской программы привел более 5 клиентов, то он получает 25% от стоимости заказа с каждого последующего заказа.
Для регистрации в партнерской программе вы должны отписать мне на ICQ, либо на емейл (смотрите контакты), либо оставить комментарий к данному посту. От вас требуются следующие данные: ФИО, контактные данные.
Вот так все просто. Вы приводите заказчиков для нашей компании и зарабатываете деньги!
17th Ноябрь 2007, 10:48 пп
На очередном заказе я поставил новый личный рекорд по количеству собранных данных (отдельно собранные ссылки, картинки и прочее в счет не берем):
230 000 записей!
База собиралась изначально в 2 потока, а потом в 5 в течении 3х дней. В процессе работы над этим заказом я понял:
- Что мне нужно купить новый компьютер
(что я уже удачно и сделал);
- Что для каждого проекта нужно писать контроллер процесса выполнения, чтобы случайная остановка сайта-источника на пару часов не останавливала процесс сбора информации и не привела к искривлению данных в базе;
- Что в php memory_limit нужно ставить в значение 64М и постоянно вести мониторинг ресурсов, а то кто бы что не говорил, но php “течет” и это факт, доказанный практикой;
- Что нужно проводить оптимизацию регулярных выражений (этому я думаю посвятить отдельную статью).
Думаю, что некоторые из этих мыслей могут быть полезны другим про в области сбора информации.
Особенно важным моментом является контроль процесса выполнения. В каждом конкретном случае его можно реализовать по разному и я вот сейчас работаю над созданием универсального класса. Как только будут первые наработки - я сразу же отпишу про это в очередной заметке.
10th Ноябрь 2007, 05:22 пп
В данной заметке я хочу затронуть вопрос нахождения и удаления дублирующихся записей в MySQL.
И это касается не только вопроса сбора информации. Предлагаемые методы будут очень полезны начинающих программистам, которые ищут оптимальное решение в данном вопросе.
Для того, чтобы было проще объяснять код я создам тестовую таблицу work с ней буду производить свои эксперименты.
Таблица work имеет следующую структуру:
CREATE TABLE work(
id mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT,
region varchar(255) NOT NULL,
job_mask varchar(255) NOT NULL,
job_group varchar(255) NOT NULL,
job_info text,
PRIMARY KEY(id));
Вдаваться в тонкости создания таблиц мы не будем, так как это не является целью данной статьи.
Предположим, что таблица work уже заполнена данными.
Теперь вам надо оставить в таблице только уникальные данные в поле job_info для каждого значения region, job_group, job_mask.
Первым делом вы должны определить есть ли у вас дублирующиеся данные и сколько их (ведь если их нет, то вам и делать ничего не надо). Для этого вам стоит выполнить следующий запрос:
SELECT COUNT(*) AS dub, region, job_group, job_mask, job_info
FROM work GROUP BY region, job_group, job_mask, job_info HAVING dub>1;
В результате выполнения запроса вы увидите таблицу с уже знакомыми вам полями и с дополнительным полем dub, которое будет содержать количество дублирующихся записей.
Далее удаление можно организовать следующими путями:
- Циклический обход-1.
Данный метод я называю “циклический обход-1″, потому что одну запись мы всегда оставляем не тронутой.
Реализуется данные метод следующим способом:
// соединение с БД
$query='SELECT COUNT(*) AS dub, region, job_group, job_mask, job_info
FROM work GROUP BY region, job_group, job_mask, job_info HAVING dub>1';
$res=$db->query($query);
if(!$res) {
echo $db->error();
} else {
while($row=$db->fetchAssoc($res)) {
$region=$row['region'];
$job_mask=$row['job_mask'];
$job_group=$row['job_group'];
$job_info=$row['job_info'];
$query="SELECT id FROM work
WHERE region='$region' AND job_mask='$job_mask'
AND job_group='$job_group' AND job_info='$job_info'";
$result=$db->query($query);
if(!$result) {
echo $db->error();
} else {
$i=1;
while ($subrow=$db->fetchArray($result)) {
if ($i==1) {
$i++;
continue;
}
$query="DELETE FROM work
WHERE id='{$subrow[0]}'";
$del_res=$db->query($query);
if(!$del_res) {
echo $db->error();
} else {
$deleted++;
}
$i++;
}
}
}
}
Методы объекта $db, которые используются по ходу выполнения скрипта, являются методами моего стандартного абстрактного класса для доступа к БД. Имена методов очень тесно переплетаются с именами стандартных функций для работы с MySQL, поэтому я не вижу смысла останавливаться на этом более детально.
В своих скриптах вы можете использовать привычные вам инструменты.
Главным преимуществом данного решения есть простота. Однако есть и очень большой недостаток - низкая скорость выполнения. На больших таблицах с большим количеством записей данный скрипт будет выполняться очень долго. Так что не забудьте поставить лимит времени и лимит памяти побольше.
- Использование запроса SELECT.
Второй вариант решения поставленной проблемы также достаточно распространен и предполагает некоторые знания в области SQL.Далее я приведу несколько запросов направленных на удаление дублирующихся записей и дам детальное их описание.
Выборка уникальных данных в отдельную таблицу. Реализуется данный метод следующим образом:
CREATE TABLE original
SELECT DISTINCT * FROM work ORDER BY id;
Данный запрос создаст таблицу original с оригинальными значениями, выбранными из таблицы work.
Также можно использовать следующую модификацию вышеуказанного выражения:
CREATE TABLE original
SELECT * FROM work GROUP BY region, job_group, job_mask, job_info
ORDER BY id;
Дополнительная информация:
P.S. Думаю, что для начала этого инструментария будет достаточно. Но я не оставляю данную тему и надеюсь в ближайшем будущем предоставить дополнительную информацию по обработке дублирующихся записей в MySQL.
6th Ноябрь 2007, 03:20 пп
Завершен очередной удачный проект, о котором я просто не мог не написать на этом блоге.
На этот раз мною был разработан парсер списка освобождающихся доменов. Источник сбора доменов я из личных соображений называть не буду.
Возможности парсера:
- парсинг CSV файла с параметрами доменов;
- проверка на наличие домена в Яндекс Каталоге, Каталоге Mail.RU, Каталоге DMOZ;
- проверка на дублирование доменных имен;
- почтовая рассылка доменов подпадающих под указанный пользователем фильтр.