Анализ целевой аудитории сообщества VK
Анализ аудитории сообществ ВКонтакте
Автор: Сабитова Алина
Группа: АДЭУ-221
Дисциплина: Работа с API социальных сетей и облачных сервисов
Статус проекта: Выполнен
| Параметр | Описание |
|---|---|
| Описание | Веб-приложение для анализа аудитории сообществ ВКонтакте. Инструмент собирает данные о подписчиках (пол, возраст, география) и постах (типы контента, вовлечённость), визуализирует статистику в виде графиков и формирует рекомендации по оптимизации контент-стратегии. Проект решает задачу автоматизации SMM-аналитики и помогает администраторам сообществ понимать свою целевую аудиторию. |
| Область знаний | Веб-разработка, анализ данных, работа с API социальных сетей, визуализация данных, SMM-аналитика, Python-программирование. |
| Близкие понятия | SMM-аналитика, парсинг VK API, дашборд для сообществ, анализ целевой аудитории (ЦА), вовлечённость (ER), демографический портрет аудитории, контент-стратегия, репрезентативная выборка, Flask-приложение. |
| Среда разработки | Python 3.8+, Flask, vk_api, matplotlib, pandas |
Цель проекта
Разработать веб-приложение для автоматического анализа аудитории сообществ ВКонтакте с целью получения демографической статистики и рекомендаций по оптимизации контент-стратегии. Приложение должно предоставлять наглядную визуализацию данных в виде графиков и формировать практические советы для администраторов сообществ.
Задачи
- Интеграция с VK API — реализовать сбор данных о подписчиках и постах сообщества.
- Обработка данных — агрегировать информацию о поле, возрасте, географии и вовлечённости.
- Визуализация — построить 4 графика:
- Распределение по полу (круговая диаграмма)
- Возрастное распределение (гистограмма)
- Топ-5 городов (горизонтальная столбчатая диаграмма)
- Вовлечённость по типам контента (столбчатая диаграмма)
- Формирование рекомендаций — на основе полученных данных выдать текстовые советы по контент-стратегии.
- Создание веб-интерфейса — разработать удобную форму для ввода ссылки на сообщество и отображения результатов.
Диаграмма работы приложения
Структура проекта
Структура проекта в VS Code:
- 📄 app.py
- основной Python-скрипт приложения. Обеспечивает интеграцию с VK API, сбор данных о подписчиках и постах, генерацию 4 графиков, формирование рекомендаций и работу веб-сервера на Flask.
- 📁 templates/index.html
- HTML-шаблон главной страницы. Содержит форму для ввода ссылки, область для отображения результатов и JavaScript-логику.
- 📁 static/style.css
- файл стилей для веб-интерфейса. Адаптивный дизайн, анимации, градиентный фон, сетка графиков.
Код приложения
app.py
- Папка для статики
- Настройка стиля seaborn
- ВСТАВЬТЕ ВАШ ТОКЕН СЮДА
| Показать код |
|---|
templates/index.html
| Показать код |
|---|
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Анализ аудитории сообществ VK</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="container">
<div class="card">
<h1>📱 Анализ аудитории сообществ VK</h1>
<p class="subtitle">Анализ аудитории сообщества и рекомендации по контенту</p>
<div class="input-group">
<input type="text" id="groupUrl" placeholder="Введите ссылку или ID сообщества">
<button onclick="analyze()" id="analyzeBtn">🔍 Анализировать</button>
</div>
<div class="loader" id="loader">
<div class="loader-spinner"></div>
<p>Анализируем сообщество... Это может занять до 30 секунд</p>
</div>
<div class="results" id="results">
<div class="stats" id="stats"></div>
<div class="chart-grid" id="charts"></div>
<div class="recommendations" id="recommendations"></div>
</div>
</div>
</div>
<script>
async function analyze() {
const groupUrl = document.getElementById('groupUrl').value;
if (!groupUrl) {
alert('Введите ссылку или ID сообщества');
return;
}
const btn = document.getElementById('analyzeBtn');
const loader = document.getElementById('loader');
const results = document.getElementById('results');
btn.disabled = true;
loader.style.display = 'block';
results.style.display = 'none';
try {
const response = await fetch('/analyze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ group_url: groupUrl })
});
const data = await response.json();
if (data.success) {
displayResults(data);
} else {
showError(data.error);
}
} catch (error) {
showError('Ошибка соединения с сервером');
} finally {
btn.disabled = false;
loader.style.display = 'none';
}
}
function displayResults(data) {
const statsHtml = `
<div class="stat">
<div class="stat-value">${data.community_name}</div>
<div class="stat-label">Название сообщества</div>
</div>
<div class="stat">
<div class="stat-value">${data.members_count.toLocaleString()}</div>
<div class="stat-label">Подписчиков</div>
</div>
${data.stats.avg_age ? `
<div class="stat">
<div class="stat-value">${data.stats.avg_age.toFixed(1)} лет</div>
<div class="stat-label">Средний возраст</div>
</div>
` : ''}
${data.stats.avg_er ? `
<div class="stat">
<div class="stat-value">${data.stats.avg_er.toFixed(2)}</div>
<div class="stat-label">Средняя вовлечённость (ER)</div>
</div>
` : ''}
`;
document.getElementById('stats').innerHTML = statsHtml;
let chartsHtml = '';
if (data.charts.sex) {
chartsHtml += `
<div class="chart-card">
<h3>👥 Распределение по полу</h3>
<img src="data:image/png;base64,${data.charts.sex}" alt="Распределение по полу">
</div>
`;
}
if (data.charts.age) {
chartsHtml += `
<div class="chart-card">
<h3>🎂 Возрастное распределение</h3>
<img src="data:image/png;base64,${data.charts.age}" alt="Возраст">
</div>
`;
}
if (data.charts.cities) {
chartsHtml += `
<div class="chart-card">
<h3>🏙️ Топ-5 городов</h3>
<img src="data:image/png;base64,${data.charts.cities}" alt="Города">
</div>
`;
}
if (data.charts.engagement) {
chartsHtml += `
<div class="chart-card">
<h3>📈 Вовлечённость по типам контента</h3>
<img src="data:image/png;base64,${data.charts.engagement}" alt="ER">
</div>
`;
}
document.getElementById('charts').innerHTML = chartsHtml;
let recHtml = '<h3>💡 Рекомендации по контент-стратегии</h3><ul>';
data.recommendations.forEach(rec => {
recHtml += `<li>${rec}</li>`;
});
recHtml += '</ul>';
document.getElementById('recommendations').innerHTML = recHtml;
document.getElementById('results').style.display = 'block';
}
function showError(message) {
const results = document.getElementById('results');
results.style.display = 'block';
results.innerHTML = `<div class="error">❌ Ошибка: ${message}</div>`;
}
</script>
</body>
</html>
|
static/style.css
| Показать код |
|---|
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
min-height: 100vh;
padding: 40px 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
.card {
background: rgba(255, 255, 255, 0.98);
backdrop-filter: blur(10px);
border-radius: 32px;
padding: 40px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
h1 {
font-size: 2.5rem;
font-weight: 700;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
margin-bottom: 12px;
}
.subtitle {
font-size: 1.1rem;
color: #6b7280;
margin-bottom: 35px;
border-left: 4px solid #667eea;
padding-left: 16px;
}
.input-group {
display: flex;
gap: 12px;
margin-bottom: 30px;
flex-wrap: wrap;
}
input {
flex: 1;
padding: 16px 20px;
border: 2px solid #e5e7eb;
border-radius: 20px;
font-size: 16px;
background: #f9fafb;
}
input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
}
button {
padding: 16px 32px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 20px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.loader {
display: none;
text-align: center;
padding: 50px;
}
.loader-spinner {
width: 50px;
height: 50px;
border: 4px solid #e5e7eb;
border-top-color: #667eea;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.results {
display: none;
animation: fadeInUp 0.5s ease;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.stat {
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
padding: 24px 20px;
border-radius: 24px;
text-align: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.stat-value {
font-size: 32px;
font-weight: 800;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.stat-label {
color: #6b7280;
font-size: 14px;
font-weight: 500;
}
.chart-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
gap: 30px;
margin: 40px 0;
}
.chart-card {
background: #ffffff;
border-radius: 24px;
padding: 24px;
text-align: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.chart-card h3 {
font-size: 1.3rem;
font-weight: 600;
margin-bottom: 20px;
color: #1f2937;
}
.chart-card img {
max-width: 100%;
height: auto;
border-radius: 16px;
}
.recommendations {
background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
border-left: 5px solid #22c55e;
padding: 28px;
border-radius: 24px;
margin-top: 30px;
}
.recommendations h3 {
color: #15803d;
margin-bottom: 20px;
font-size: 1.3rem;
font-weight: 700;
}
.recommendations ul {
list-style: none;
padding-left: 0;
}
.recommendations li {
padding: 12px 0;
color: #166534;
border-bottom: 1px solid #bbf7d0;
}
.recommendations li:last-child {
border-bottom: none;
}
.error {
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
color: #dc2626;
padding: 20px;
border-radius: 20px;
text-align: center;
}
@media (max-width: 768px) {
body { padding: 20px 15px; }
.card { padding: 24px; }
h1 { font-size: 1.8rem; }
.input-group { flex-direction: column; }
.chart-grid { grid-template-columns: 1fr; }
.stats { grid-template-columns: 1fr; }
}
|
Ход выполнения
Устанавливаем необходимые библиотеки:

Запускаем основной скрипт приложения:

После запуска приложение доступно по адресу: http://127.0.0.1:5000
Результат
Перейдем в браузер и воспользуемся приложением. Главный экран выглядит следующим образом:

Введем ссылку на сообщество "Афиша" и посмотрим результат:

В приложении выводятся:
Ключевые метрики

График, отображающий распределение подписчиков сообщества по полу

График, показывающий распределение подписчиков по возрасту с указанием среднего значения

График, выводящий 5 городов с наибольшим количеством подписчиков

График сравнения вовлеченности подписчиков в зависимости от типа контента

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

Выводы
- Разработано полноценное веб-приложение для анализа сообществ ВКонтакте, работающее на localhost.
- Реализована интеграция с VK API — приложение успешно получает данные о подписчиках (пол, возраст, город) и постах (типы контента, вовлечённость).
- Создана система визуализации — 4 информативных графика, отображающих ключевые метрики аудитории:
- Распределение по полу (круговая диаграмма)
- Возрастное распределение (гистограмма)
- Топ-5 городов (горизонтальная столбчатая диаграмма)
- Вовлечённость по типам контента (столбчатая диаграмма)
- Автоматическое формирование рекомендаций — на основе анализа данных приложение выдаёт практические советы по оптимизации контент-стратегии.
- Удобный пользовательский интерфейс — адаптивный дизайн, анимации загрузки, понятная навигация.

