В этом уроке будет рассмотрен пример парсинга неизвестного количества характеристик товара.
Готовые пресеты можно посмотреть здесь
В качестве примера мы взяли сайт arcpalace.com.ua
Для того чтобы наш парсер не занял всю память, мы используем встроенную БД Sqlite для временного хранения данных.
Из-за некоторых ограничений А-Парсер'a пришлось разбить задание на 2 пресета которые объединены в цепочку.
Весь принцип работы данного пресета описан ниже.
Пресет 1:
Пресет 2:
- Парсим ссылки на товары.
- Используя файл результата из пресета 1 парсим информацию о товарах.
- Пишем всю информацию в БД.
- В конце задания выгружаем данные в .csv файл.
Пресет 1
Думаю тут все понятно, в массив links заносим ссылки на товары и также реализована пагинация для перехода между страницами.
Для передачи файла результатов в пресет 2, используем опцию Запустить по завершению.
Пресет 2
titile - название товара, features - характеристики, свойства (name - название характеристики, value значение), price - цена, code - артикул.
Для лучшего понимания рассмотрим сайт донор.
Теперь разберем код в поле Формат результата.
Для работы с БД используем встроенные функции А-Парсер'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)"); 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 %]
Создаем две таблицы products - информация о товарах, columns - уникальные название характеристик.Код: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);
Данная выборка позволяет проверить существует ли указанная колонка в таблице, в результате запроса будет 1 или 0.Код: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.sort - метод sort позволяет отсортировать элементы в массивеКод:cols = cols.sort; cols.unshift('title', 'price'); cols.join(';') _ "\n";
unshift() - добавляет элементы в начало массива, а push() - в конец массива.Код:list = [ 'c', 'b', 'a' ] list.sort = > [ 'a', 'b', 'c' ]
join() - объединяет все элементы массива в строку, в качестве параметра указывается разделитель в нашем случае это точка с запятой.
Чтобы не выгружать весь результат сразу, так как это может съесть всю память, мы будем подгружать данные блоками.
В rows записываем общее количество товаров, blockSize - размер блока, blocksCount - количество блоков.Код: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);
-
Вступайте в наш Telegram чат: https://t.me/a_parser Нас уже 2600+ и мы растем!Скрыть объявление
Сбор характеристик товара
Сбор неизвестного количества характеристик товара
Метки: