- English Name
- Collection of product characteristics
В этом уроке будет рассмотрен пример парсинга неизвестного количества характеристик товара.
Готовые пресеты можно посмотреть здесь
В качестве примера мы взяли сайт arcpalace.com.ua
Для того чтобы наш парсер не занял всю память, мы используем встроенную БД Sqlite для временного хранения данных.
Из-за некоторых ограничений А-Парсер'a пришлось разбить задание на 2 пресета которые объединены в цепочку.
Весь принцип работы данного пресета описан ниже.
Пресет 1:
Пресет 1
Думаю тут все понятно, в массив links заносим ссылки на товары и также реализована пагинация для перехода между страницами.
Для передачи файла результатов в пресет 2, используем опцию Запустить по завершению.
Пресет 2
titile - название товара, features - характеристики, свойства (name - название характеристики, value значение), price - цена, code - артикул.
Для лучшего понимания рассмотрим сайт донор.
Теперь разберем код в поле Формат результата.
Для работы с БД используем встроенные функции А-Парсер'a tools.sqlite.*
Создаем две таблицы products - информация о товарах, columns - уникальные название характеристик.
СALL - позволяет выполнить запрос, но не печатает возвращаемый результат.
Проверяем есть ли такой товар в базе.
Данная выборка позволяет проверить существует ли указанная колонка в таблице, в результате запроса будет 1 или 0.
pragma_table_info('products') - выводит все колонки из таблицы products.
Рассмотрим код в Конечном тексте, который выполняется в конце задания.
cols.sort - метод sort позволяет отсортировать элементы в массиве
unshift() - добавляет элементы в начало массива, а push() - в конец массива.
join() - объединяет все элементы массива в строку, в качестве параметра указывается разделитель в нашем случае это точка с запятой.
Чтобы не выгружать весь результат сразу, так как это может съесть всю память, мы будем подгружать данные блоками.
В rows записываем общее количество товаров, blockSize - размер блока, blocksCount - количество блоков.
Например в rows получилось 1501 строк, Math.int(1501/100) = 15.01 => 15 так как целое число и меньше 0.5 тогда оно округляется в меньшую сторону, 15 * 100 = 1500 а строк 1501 получается что 1 строка пропадает нужно прибавить 0.999, Math.int(1501/ 100 + 0.999) = 16 * 100 = 1600 теперь все строки попадаю в заданный диапазон 1 - 1600;
После подстановки значений вместо переменных, можно увидеть процесс работы.
Готовые пресеты можно посмотреть здесь
В качестве примера мы взяли сайт arcpalace.com.ua
Для того чтобы наш парсер не занял всю память, мы используем встроенную БД Sqlite для временного хранения данных.
Из-за некоторых ограничений А-Парсер'a пришлось разбить задание на 2 пресета которые объединены в цепочку.
Весь принцип работы данного пресета описан ниже.
Пресет 1:
- Парсим ссылки на товары.
- Используя файл результата из пресета 1 парсим информацию о товарах.
- Пишем всю информацию в БД.
- В конце задания выгружаем данные в .csv файл.
Пресет 1
Думаю тут все понятно, в массив links заносим ссылки на товары и также реализована пагинация для перехода между страницами.
Для передачи файла результатов в пресет 2, используем опцию Запустить по завершению.
Пресет 2
titile - название товара, features - характеристики, свойства (name - название характеристики, value значение), price - цена, code - артикул.
Для лучшего понимания рассмотрим сайт донор.
Теперь разберем код в поле Формат результата.
Код:
[% CALL tools.sqlite.run(db, "CREATE TABLE IF NOT EXISTS products(code TEXT PRIMARY KEY, title TEXT, price INTEGER)");
CALL tools.sqlite.run(db, "CREATE TABLE IF NOT EXISTS columns(name TEXT PRIMARY KEY)");
row = tools.sqlite.get(db, "SELECT code FROM products WHERE code = ?", p1.code);
IF !row.0.code;
CALL tools.sqlite.run(db, "INSERT INTO products(code, title, price) VALUES(?, ?, ?)", p1.code, p1.title, p1.price);
FOREACH item IN p1.features;
column = tools.sqlite.get(db, "SELECT COUNT(*) AS exist FROM pragma_table_info('products') WHERE name = ?", item.name);
IF !column.0.exist;
CALL tools.sqlite.run(db, "ALTER TABLE products add `" _ item.name _ "` TEXT");
CALL tools.sqlite.run(db, "INSERT INTO columns(name) VALUES(?)", item.name);
END;
CALL tools.sqlite.run(db, "UPDATE products SET `" _ item.name _ "` = ? WHERE code = ?", item.value, p1.code);
END;
END %]
Для работы с БД используем встроенные функции А-Парсер'a tools.sqlite.*
Код:
CALL tools.sqlite.run(db, "CREATE TABLE IF NOT EXISTS products(code TEXT PRIMARY KEY, title TEXT, price INTEGER)");
CALL tools.sqlite.run(db, "CREATE TABLE IF NOT EXISTS columns(name TEXT PRIMARY KEY)");
СALL - позволяет выполнить запрос, но не печатает возвращаемый результат.
Код:
row = tools.sqlite.get(db, "SELECT code FROM products WHERE code = ?", p1.code);
Код:
column = tools.sqlite.get(db, "SELECT COUNT(*) AS exist FROM pragma_table_info('products') WHERE name = ?", item.name);
pragma_table_info('products') - выводит все колонки из таблицы products.
Рассмотрим код в Конечном тексте, который выполняется в конце задания.
Код:
[%
cols = [];
FOREACH col IN tools.sqlite.all(db, "SELECT * FROM columns");
cols.push(col.name);
END;
cols = cols.sort;
cols.unshift('title', 'price');
cols.join(';') _ "\n";
USE Math;
rows = tools.sqlite.get(db, "SELECT COUNT(*) AS count FROM products");
blockSize = 100;
blocksCount = Math.int(rows.count / blockSize + 0.999);
FOREACH b IN [1..blocksCount];
block = tools.sqlite.all(db, "SELECT * FROM products WHERE rowid > ? AND rowid <= ?", (b - 1) * blockSize, b * blockSize);
FOREACH row IN block;
FOREACH col IN cols;
row.${col} _ ';';
END;
"\n";
END;
END %]
Код:
cols = cols.sort;
cols.unshift('title', 'price');
cols.join(';') _ "\n";
Код:
list = [ 'c', 'b', 'a' ]
list.sort = > [ 'a', 'b', 'c' ]
join() - объединяет все элементы массива в строку, в качестве параметра указывается разделитель в нашем случае это точка с запятой.
Чтобы не выгружать весь результат сразу, так как это может съесть всю память, мы будем подгружать данные блоками.
Код:
rows = tools.sqlite.get(db, "SELECT COUNT(*) AS count FROM products");
blockSize = 100;
blocksCount = Math.int(rows.count / blockSize + 0.999);
Например в rows получилось 1501 строк, Math.int(1501/100) = 15.01 => 15 так как целое число и меньше 0.5 тогда оно округляется в меньшую сторону, 15 * 100 = 1500 а строк 1501 получается что 1 строка пропадает нужно прибавить 0.999, Math.int(1501/ 100 + 0.999) = 16 * 100 = 1600 теперь все строки попадаю в заданный диапазон 1 - 1600;
Код:
FOREACH b IN [1..16];
block = tools.sqlite.all(db, "SELECT * FROM products WHERE rowid > ? AND rowid <= ?", (1 - 1) * 100, 1 * 100);