Использование Azure CLI и ИИ-агентов для парсинга данных о гадалках в 2026 году

Автоматизируйте парсинг API, ботов и маркетплейсов. Получите актуальные рейтинги, цены и специализации магов без рутины.

Дата публикации: 19 августа 2026 г. | Категория: DevOps‚ Data Engineering‚ Azure Automation


Рынок эзотерических услуг в 2026 году — это не только газеты с объявлениями‚ но и тысячи API-агрегаторов‚ телеграм-ботов‚ профилей на маркетплейсах (Авито‚ Профи.ру‚ Яндекс.Услуги) и закрытых сообществ. Сбор данных о гадалках (рейтинги‚ отзывы‚ цены‚ специализация: таро‚ руны‚ нумерология‚ астрология‚ геолокация‚ доступность онлайн/офлайн) требует обработки гетерогенных‚ часто неструктурированных и защищенных источников.

Классические парсеры на Python/Node.js ломаються при смене верстки или появлении капчи. Современный подход 2026 года, использование Azure CLI в среде Bash для оркестрации инфраструктуры и ИИ-агентов для парсинга‚ отдающих чистый JSON‚ который дальше обрабатывается нативно средствами Azure (JMESPath‚ jq‚ Azure Stream Analytics).

Ключевая идея: Разделяй и властвуй. Azure CLI управляет инфраструктурой и транспортом (скачивание блобов‚ запуск контейнеров‚ управление Key Vault)‚ а специализированные инструменты (jq‚ JMESPath‚ ИИ-агенты) занимаются семантикой данных.


Архитектура решения: от источника до Data Lake

  1. Сбор (Ingestion): Azure CLI скрипты‚ запускаемые по расписанию (Cron в Container Apps / Timer Trigger в Functions)‚ скачивают сырые данные в Raw Zone (ADLS Gen2 / Blob Storage).
  2. Трансформация (Transformation): Потоковая обработка (Azure Stream Analytics / Flink) или батчевая (Azure CLI + jq / JMESPath) для приведения к единой модели: FortuneTellerProfile.
  3. Хранилище и аналитика (Serving): Azure SQL / Cosmos DB / Synapse для BI-отчетов (Power BI: «Топ-10 тарологов по ЦА в Москве за неделю»).

Часть 1. Фундамент: Azure CLI в Bash для автоматизации ресурсов

Согласно документации Microsoft Learn (Практическое руководство по использованию Azure CLI в среде Bash)‚ Azure CLI оптимизирован для автоматизации и скриптинга. Главные преимущества для нашей задачи:

  • Выходные форматы: --output json (по умолчанию)‚ table‚ tsv‚ yaml‚ jsonc (с комментариями).
  • JMESPath Query (--query): Мощный язык запросов для фильтрации JSON прямо в терминале без внешних зависимостей.
  • Идемпотентность: Команды az storage blob download‚ az container create безопасны для перезапуска в CI/CD.

Настройка окружения (Best Practices 2026)

#!/bin/bash


set -euo pipefail

RESOURCE_GROUP="rg-esoterics-data-prod"
STORAGE_ACCOUNT="stesotericsrawdata"
CONTAINER_RAW="raw-fortune-tellers"
CONTAINER_PARSED="parsed-profiles"
AI_PARSER_IMAGE="ghcr.io/myorg/ai-fortune-parser:v2.4.1" # ИИ-агент для парсинга

az config set extension.use_dynamic_install=yes_without_prompt

Часть 2. Сбор сырых данных: Скрипты загрузки и запуска парсеров

Сценарий А: Скачивание выгрузок от партнеров (Blob Storage)

Партнеры скидывают дампы профилей гадалок в JSON/CSV в контейнер raw-fortune-tellers. Скрипт синхронизирует локальную папку (или монтированную шару) с облаком.

#!/bin/bash

echo "[$(date)] Starting sync from Blob Storage..."

BLOBS_TO_DOWNLOAD=$(az storage blob list 
 --account-name "$STORAGE_ACCOUNT" 
 --container-name "$CONTAINER_RAW" 
 --query "[?properties.lastModified > `$(date -d '24 hours ago' -u +%Y-%m-%dT%H:%M:%SZ)`].name" 
 -o tsv)

if [ -z "$BLOBS_TO_DOWNLOAD" ]; then
 echo "No new blobs found."
 exit 0
fi

echo "$BLOBS_TO_DOWNLOAD" | while IFS= read -r blob_name; do
 local_path="./data/raw/$(basename "$blob_name")"
 mkdir -p "$(dirname "$local_path")"
  echo "Downloading $blob_name..."
 az storage blob download 
 --account-name "$STORAGE_ACCOUNT" 
 --container-name "$CONTAINER_RAW" 
 --name "$blob_name" 
 --file "$local_path" 
 --overwrite true 
 --output none # Тихий режим для скриптов
done

echo "[$(date)] Sync complete. Triggering parsing pipeline..."

./run_parsing_batch.sh

Сценарий Б: Запуск ИИ-парсера в Azure Container Instances (ACI)

Согласно трендам 2026 года (Парсер сайтов в 2026 году — это автономный ИИ-агент)‚ мы не пишем селекторы. Мы упаковываем Playwright + LLM (например‚ Llama 3.1 / GPT-4o mini локально или через API) в Docker-образ. Azure CLI управляет жизненным циклом контейнера.

#!/bin/bash

INPUT_FILE="${1:-./data/urls_to_parse.txt}"
JOB_NAME="parser-job-$(date +%s)"

az storage blob upload 
 --account-name "$STORAGE_ACCOUNT" 
 --container-name "$CONTAINER_RAW" 
 --file "$INPUT_FILE" 
 --name "inputs/urls_${JOB_NAME}.txt" 
 --output none

az container create 
 --resource-group "$RESOURCE_GROUP" 
 --name "$JOB_NAME" 
 --image "$AI_PARSER_IMAGE" 
 --cpu 2 --memory 4 
 --restart-policy OnFailure 
 --environment-variables 
 INPUT_BLOB_URL="https://${STORAGE_ACCOUNT}.blob.core.windows.net/${CONTAINER_RAW}/inputs/urls_${JOB_NAME}.txt" 
 OUTPUT_CONTAINER="$CONTAINER_PARSED" 
 STORAGE_ACCOUNT="$STORAGE_ACCOUNT" 
 KEY_VAULT_URI="https://kv-esoterics.vault.azure.net/" 
 --secure-environment-variables 
 # Секреты лучше брать из Key Vault внутри контейнера‚ но можно и так для простоты
 AZURE_CLIENT_SECRET="$SP_SECRET" 
 --output json --query "{fqdn:ipAddress.fqdn‚ state:provisioningState}"

echo "Parser job $JOB_NAME started. Monitoring logs..."


Часть 3. Парсинг JSON: от JSON.parse к отказоустойчивым конвейерам

Как отмечено в обзоре DataLopata (2026): «Парсинг данных из JSON сегодня, это не просто вызов функции JSON.parse‚ а выстраивание отказоустойчивых конвейеров‚ способных обрабатывать гигабайты структурированного текста в секунду без утечек памяти».

В нашем стеке используется три уровня парсинга:

Уровень 1: JMESPath (Нативный в Azure CLI) — Фильтрация и проекция

Идеален для «быстрых» запросов к уже структурированным данным (например‚ ответы API агрегаторов или результат работы ИИ-парсера). Не требует установки jq.

# Пример: Из массива профилей выбрать только онлайн-тарологов с рейтингом > 4.5 в Москве

az cli invoke --local-context ./data/parsed/profiles_batch_001.json 
 --query "[?specialization=='tarot' && city=='Moscow' && format=='online' && rating > `4.5`].{name: name‚ price: price_per_min‚ rating: rating‚ profile_url: url}" 
 -o table

Продвинутый JMESPath: Группировка и агрегация (Client-side)

Azure CLI не умеет делать GROUP BY нативно в --query‚ но можно подготовить данные для jq.

Уровень 2: jq — Тяжелая артиллерия для трансформации

Стандарт де-факто для сложной манипуляции JSON в Bash. Обработка стримингом (--stream) позволяет парсить файлы размером > RAM.

#!/bin/bash

def normalize_price:
 # Приводим цену к рублям в минуту (источники дают за сеанс‚ за час‚ в у.е.)
 if .currency == "USD" then .amount * 95 / .duration_minutes
 elif .currency == "RUB" then .amount / .duration_minutes
 else .amount / .duration_minutes # fallback
 end;

def clean_phone:
 gsub("[^0-9]"; "") | if length == 11 then .[1:] else . end; # Приводим к 10 цифр

map(
 {
 external_id: .id // .profile_id // .uuid‚
 source: .source_system // "unknown"‚
 full_name: .name // .full_name // "Anonymous"‚
 specialization: (.specialization | lower | gsub(" "; "_"))‚ # tarot‚ runes‚ numerology
 city: .location.city // .city // "Remote"‚
 format: (if .online == true then "online" elif .offline == true then "offline" else "hybrid" end)‚
 rating: (.rating // .avg_score // 0 | tonumber)‚
 price_per_min: (normalize_price)‚
 phone: (.contacts.phone // .whatsapp // .telegram | clean_phone)‚
 skills: (.skills // .tags // [] | unique | map(lower))‚
 parsed_at: now | todateiso8601‚
 raw_payload: . # Сохраняем оригинал для аудита/репарсинга
 }
)

Уровень 3: Парсинг «грязного» JSON и Schema Evolution

ИИ-агенты иногда возвращают невалидный JSON (пропущенные скобки‚ комментарии‚ trailing commas). В 2026 году используем jsonrepair (Rust/Node) или Python dirtyjson перед подачей в jq.

# Обертка для безопасного парсинга
parse_dirty_json {
 local input_file="$1"
 # python3 -c "import dirtyjson‚ sys; print(dirtyjson.loads(sys.stdin.read))" < "$input_file" | jq .
 # Или утилита jsonrepair (быстрее)
 jsonrepair "$input_file" | jq .
}

Часть 4. Продвинутые паттерны Azure CLI для Data Engineering

Динамическое формирование JSON для команд (--body / --parameters)

Часто нужно отправить сложный JSON в Azure REST API (например‚ запуск Pipeline в Data Factory или Stream Analytics Job) из Bash-переменных. Проблема кавычек решается через jq -n.

# Не делайте так (боль в экранировании):

PIPELINE_PARAMS=$(jq -n 
 --arg date "$(date -u +%Y-%m-%d)" 
 --argjson batch_id "$BATCH_ID" 
 --arg storage_path "raw/fortune_tellers/$BATCH_ID/" 
 '{date: $date‚ batch_id: $batch_id‚ storage_path: $storage_path}')
az datafactory pipeline create-run 
 --resource-group "$RESOURCE_GROUP" 
 --factory-name "adf-esoterics-etl" 
 --name "pl_parse_fortune_tellers" 
 --parameters "$PIPELINE_PARAMS" 
 --output json --query "runId"

Обработка больших массивов: Постраничная загрузка (Pagination)

API агрегаторов гадалок часто отдают по 50-100 записей на страницу. Azure CLI не имеет встроенного пагинатора для произвольных REST API‚ пишем обертку:

fetch_all_pages {
 local base_url="$1"
 local token_var="$2" # имя переменной для next_token
 local all_results="[]"
 local next_token=""

 while : ; do
 # Формируем URL с токеном
 local url="${base_url}"
 if [ -n "$next_token" ]; then
 url="${url}&page_token=${next_token}"
 fi

 # Вызов API (через az rest или curl с токеном из Key Vault)
 # Допустим‚ ответ: { "data": [...]‚ "next_token": "abc" }
 response=$(az rest --method get --uri "$url" --headers "Authorization=Bearer $(az account get-access-token --query accessToken -o tsv)" -o json)
 
 # Сливаем данные
 all_results=$(echo "$all_results" "$response" | jq -s '.[0] + .[1].data')
 
 # Извлекаем следующий токен
 next_token=$(echo "$response" | jq -r '.next_token // empty')
 
 if [ -z "$next_token" ] || [ "$next_token" == "null" ]; then
 break
 fi
 sleep 0.2 # Rate limiting courtesy
 done
 
 echo "$all_results"
}

ALL_TAROLOGISTS=$(fetch_all_pages "https://api.esoteric-aggregator.ru/v1/professionals?specialization=tarot")
echo "$ALL_TAROLOGISTS" | jq . > ./data/raw/tarologists_full_dump.json

Параллелизация через xargs -P или GNU Parallel

Скачивание профилей 10‚000 гадалок по API по одному — медленно. Azure CLI команды можно параллелить.

# Список ID в файл ids.txt
cat ./data/ids.txt | xargs -P 10 -I {} bash -c '
 az rest --method get --uri "https://api.source.com/v1/profile/{}" 
 --headers "Authorization=Bearer $TOKEN" 
 -o json > "./data/raw/profiles/{}.json"
'


Часть 5. Оркестрация и мониторинг: Выход за пределы Bash

Bash-скрипты отлично подходят для адхок-задач‚ локальной разработки и простых крон-задач. Для продакшн-конвейера 2026 года необходима оркестрация.

Вариант А: Azure Data Factory (ADF) / Synapse Pipelines

  • Custom Activity: Запуск нашего Docker-образа с ИИ-парсером как Custom Activity в ADF.
  • Web Activity: Вызов API агрегаторов.
  • Databricks Notebook / Spark Pool: Тяжелая трансформация JSON (плоское сжатие вложенных массивов отзывов‚ дедупликация по fuzzy matching имен).
  • Плюсы: Визуальный мониторинг‚ ретраи‚ алерты‚ интеграция с Git.

Вариант Б: Azure Container Apps Jobs (Serverless Containers)

Идеально для наших Bash/CLI скриптов. Упаковываем скрипты в образ‚ определяем Job с триггером (Schedule / Event / Manual).

# containerapp-job.yaml (для `az containerapp job create`)
properties:
 configuration:
 triggerType: "Schedule"
 schedule:
 cronExpression: "0 /6  * *" # Каждые 6 часов
 replicaTimeout: 1800 # 30 мин
 replicaRetryLimit: 3
 template:
 containers:
 ─ name: etl-worker
 image: ghcr.io/myorg/esoterics-etl:latest
 env:
 ⸺ name: AZURE_CLIENT_ID
 value: ""
 resources:
 cpu: 1.0
 memory: 2Gi

Мониторинг качества данных (Data Quality Checks)

После парсинга обязательно валидация. Добавляем шаг в пайплайн:

# dq_check.sh

INPUT_FILE="./data/parsed/normalized_latest.json"

DUPES=$(jq '[.[] | .external_id] | group_by(.) | map(select(length > 1)) | length' "$INPUT_FILE")
if [ "$DUPES" -gt 0 ]; then
 echo "ALERT: Found $DUPES duplicate external_ids!" | tee -a /var/log/dq.log
 # Отправка в Azure Monitor / Log Analytics / Teams
fi

BAD_RATING=$(jq 'map(select(.rating < 0 or .rating > 5)) | length' "$INPUT_FILE")

COMPLETENESS=$(jq 'map(select(.phone != null and .price_per_min > 0)) | length / (length // 1) * 100' "$INPUT_FILE")

echo "DQ Report: Dupes=$DUPES‚ BadRating=$BAD_RATING‚ Completeness=${COMPLETENESS}%"

Часть 6. Типичные ловушки и Best Practices (Lessons Learned)

Проблема Симптом Решение (2026)
Кавычки в Bash + JSON + Azure CLI Скрипт падает на спецсимволах в отзывах (кавычки‚ бэкслеши‚ $). Никогда не конкатенируйте строки. Используйте jq -n --arg var "$VALUE" '{key: $var}' для генерации JSON. Передавайте сложные тела через @file.json.
JMESPath vs jq Пытаетесь сделать рекурсивный обход или математику в --query. JMESPath, для проекции/фильтрации плоских структур. jq — для рекурсии‚ математики‚ группировки‚ стриминга. Не смешивайте логику.
Смена схемы источника (Schema Drift) Парсер падает‚ так как API вернул новое поле или переименовал старое. Схему валидируйте после ИИ-парсера (JSON Schema / Pydantic). В Bash используйте // (альтернатива) в JMESPath/jq: .new_field // .old_field // "default". Храните raw_payload для репарсинга.
Утечки памяти при больших файлах jq съедает всю RAM на файле 5 ГБ. Используйте jq --stream или разбивайте входной файл на чанки (split -l 10000) и обрабатывайте параллельно. Azure Stream Analytics / Flink для стриминга.
Управление секретами API ключи LLM‚ прокси‚ токены агрегаторов в коде скриптов. Только Azure Key Vault + Managed Identity. Скрипт читает секреты при старте: az keyvault secret show --vault-name $KV --name $SECRET --query value -o tsv. Никаких .env файлов в репозитории.
Блокировки и Капчи ИИ-парсер банит источник. Ротация прокси (резидентные/мобильные)‚ рандомизация User-Agent / Fingerprint (Playwright Stealth)‚ задержки‚ respeto robots.txt. Логирование блокировок в отдельную таблицу для анализа.

Пример комплексного пайплайна (End-to-End)

Файл: daily_etl.sh — точка входа для Container Apps Job.

#!/bin/bash
set -euo pipefail

LOG_FILE="/var/log/daily_etl_$(date +%Y%m%d).log"
exec > >(tee -a "$LOG_FILE") ->&1

echo "=== START DAILY ETL $(date) ==="

source ./config.env # Переменные окружения

echo "Step 1: Generating target URLs..."
python3 ./scripts/generate_targets.py --output ./data/urls_today.txt --date "$(date -u +%Y-%m-%d)"

echo "Step 2: Launching AI Parser..."
JOB_ID=$(./run_ai_parser.sh ./data/urls_today.txt | jq -r '.name') # Парсим имя джобы из вывода az container create

echo "Step 3: Waiting for parser job $JOB_ID..."
while true; do
 STATE=$(az container show -g "$RESOURCE_GROUP" -n "$JOB_ID" --query "instanceView.state" -o tsv)
 if [ "$STATE" == "Succeeded" ]; then break; fi
 if [ "$STATE" == "Failed" ]; then echo "Parser FAILED"; exit 1; fi
 sleep 30
done

echo "Step 4: Downloading parsed JSON..."
az storage blob download-batch 
 -s "$CONTAINER_PARSED" 
 -d "./data/parsed_incoming" 
 --pattern "output_${JOB_ID}" 
 --account-name "$STORAGE_ACCOUNT"

echo "Step 5: Normalizing data..."
cat ./data/parsed_incoming/.json | jq -s -f ./transform_profiles.jq > ./data/normalized/full_$(date +%s).json

echo "Step 6: Running DQ checks..."
./dq_check.sh ./data/normalized/full_$(date +%s).json

echo "Step 7: Loading to Serving Layer..."

python3 ./scripts/load_to_sql.py --input ./data/normalized/full_*.json --table FortuneTellers_Staging

find ./data/raw -mtime +7 -delete
find ./data/parsed_incoming -mtime +1 -delete

echo "=== END DAILY ETL $(date) ==="

Автоматизация сбора данных о гадалках в 2026 году — это симбиоз инфраструктурного кода (Azure CLI/Bash)‚ семантического извлечения (ИИ-агенты) и потоковой обработки JSON (jq/JMESPath/Stream Analytics).

  • Azure CLI дает единый пульт управления ресурсами Azure (Storage‚ ACI‚ Key Vault‚ ADF) из терминала‚ идеально встраиваясь в CI/CD и контейнеры.
  • JMESPath (--query) — ваш первый инструмент для быстрой фильтрации ответов Azure API и простых JSON.
  • jq — индустриальный стандарт для сложных трансформаций‚ стриминга и исправления "грязного" JSON.
  • ИИ-парсинг снимает головную боль с поддержкой селекторов: меняется верстка — переобучаете промпт‚ а не код.

Главный принцип: Инфраструктура как код (IaC) + Данные как код (DaC). Храните схемы‚ скрипты парсинга‚ конфиги пайплайнов в Git. Версионируйте не только код‚ но и контракты данных (JSON Schema). Это позволит масштабировать сбор с десятков источников до тысяч‚ сохраняя качество данных и рассудок инженеров.


Полезные ссылки (Microsoft Learn / Docs)

  • Практическое руководство по использованию Azure CLI в среде Bash
  • Советы по использованию Azure CLI: JMESPath и форматы вывода
  • Документация по Фабрике данных Azure (ADF)
  • Анализ данных JSON и Avro в Azure Stream Analytics
  • Примеры парсинга JSON для Stream Analytics (GitHub)

Статья подготовлена на основе актуальных практик 2026 года: серверлесс-контейнеры‚ ИИ-агенты для извлечения данных и нативная работа с JSON в командной строке Azure.