Анализ наиболее посещаемых страниц портала

Материал из Поле цифровой дидактики

Код

library(httr)
library(jsonlite)
library(dplyr)
library(lubridate)
library(tidyr)
library(ggplot2)
library(patchwork)

# Корректный URL API
api_url <- "https://digida.mgpu.ru/api.php"

# Безопасное определение функции (если ещё не существует)
if (!exists("get_mw_data")) {
  get_mw_data <- function(action, params) {
    query_params <- c(action = action, format = "json", params)
    response <- GET(api_url, query = query_params)
    
    # Дополнительная проверка типа ответа
    if (http_type(response) != "application/json") {
      warning("Ответ не в формате JSON")
    }
    
    stop_for_status(response)
    fromJSON(content(response, "text"))
  }
}

# === ДИАГНОСТИКА API ===
print("=== ДИАГНОСТИКА API DIGIDA ===")
print("Проверяем доступность API...")


# Шаг 1: базовый запрос для проверки API
data_loaded <- FALSE
page_views <- NULL

tryCatch({
  test_response <- get_mw_data("query", list(
    meta = "siteinfo",
    siprop = "general"
  ))
  print("✓ API доступно!")
  print(paste("Название сайта:", test_response$query$general$sitename))
}, error = function(e) {
  stop(paste("❌ API недоступно:", e$message, "\nПроверьте URL:", api_url))
})

# Шаг 2: пробуем получить данные через recentchanges (косвенный показатель активности)
tryCatch({
  print("Пробуем получить данные о недавних изменениях...")
  page_views <- get_mw_data("query", list(
    list = "recentchanges",
    rclimit = "1000",
    rcprop = "title|timestamp|user|comment",
    rcshow = "!bot",
    rcend = format(Sys.Date() - 365, "%Y%m%d%H%M%S")
  ))
  
  if (!is.null(page_views$query$recentchanges)) {
    print("✓ Данные получены через recentchanges")
    data_loaded <- TRUE
  } else {
    warning("В ответе API нет данных recentchanges")
  }
}, error = function(e) {
  print(paste("Ошибка при запросе recentchanges:", e$message))
})

if (!data_loaded) {
  stop("Не удалось получить данные. Проверьте доступность API и параметры запроса.")
}

# Проверка прав на запись в текущей директории
can_write <- file.access(getwd(), mode = 2) == 0
if (!can_write) {
  stop("Нет прав на запись в текущую рабочую директорию. Выберите другую папку.")
}

# === ОЧИСТКА ДАННЫХ ===
clean_data <- page_views$query$recentchanges %>%
  as_tibble() %>%
  mutate(
    timestamp = parse_date_time(
      timestamp,
      orders = c("YmdHMS", "YmdHM", "ymdHMS", "ymdHM", "U"),
      quiet = TRUE
    ),
    date = as.Date(timestamp),
    day_of_week = wday(timestamp, label = TRUE, abbr = FALSE),
    hour_of_day = hour(timestamp),
    month = month(timestamp, label = TRUE)
  ) %>%
  filter(!is.na(timestamp), date >= Sys.Date() - 365) %>%
  select(title, timestamp, date, day_of_week, hour_of_day, month, user)

# Проверка на пустые данные
if (nrow(clean_data) == 0) {
  stop("Очищенные данные пусты. Проверьте параметры запроса к API и формат дат.")
}

print(paste("Обработано записей о действиях:", nrow(clean_data)))

# === АГРЕГАЦИЯ И АНАЛИЗ ===
page_summary <- clean_data %>%
  group_by(title) %>%
  summarise(
    total_actions = n(),
    unique_users = n_distinct(user),
    first_action = min(timestamp),
    last_action = max(timestamp)
  ) %>%
  arrange(desc(total_actions))

top_pages <- page_summary %>% head(10)

monthly_views <- clean_data %>%
  group_by(month) %>%
  summarise(total_actions = n())

weekly_views <- clean_data %>%
  group_by(day_of_week) %>%
  summarise(actions = n())

hourly_views <- clean_data %>%
  group_by(hour_of_day) %>%
  summarise(actions = n())

# === ПОСТРОЕНИЕ ГРАФИКОВ ===
p1 <- ggplot(monthly_views, aes(x = month, y = total_actions)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  labs(title = "Динамика активности по месяцам",
       x = "Месяц", y = "Количество действий") +
  theme_minimal()

p2 <- ggplot(weekly_views, aes(x = day_of_week, y = actions)) +
  geom_bar(stat = "identity", fill = "darkgreen") +
  labs(title = "Активность по дням недели",
       x = "День недели", y = "Количество действий") +
  theme_minimal()

p3 <- ggplot(hourly_views, aes(x = hour_of_day, y = actions)) +
  geom_line(color = "red", size = 1) +
  labs(title = "Активность по часам суток",
       x = "Час дня", y = "Количество действий") +
  scale_x_continuous(breaks = 0:23) +
  theme_minimal()

combined_plot <- (p1 | p2) / p3

# === СОХРАНЕНИЕ РЕЗУЛЬТАТОВ ===
# Создаём папку для сохранения графиков
output_dir <- "saved_plots_page_views"
if (!dir.exists(output_dir)) {
  dir.create(output_dir)
  print(paste("Создана папка для графиков:", output_dir))
}

# Функция для безопасного сохранения графиков
safe_save_plot <- function(plot_obj, filename, width, height, dpi = 300) {
  if (!inherits(plot_obj, "ggplot")) {
    print(paste("Предупреждение: объект не является графиком ggplot — пропуск сохранения", filename))
    return(FALSE)
  }
  
  full_path <- file.path(output_dir, filename)
  
  tryCatch({
    ggsave(
      filename = full_path,
      plot = plot_obj,
      width = width,
      height = height,
      dpi = dpi,
      device = "png"
    )
    print(paste("График сохранён:", normalizePath(full_path)))
    TRUE
  }, error = function(e) {
    print(paste("Ошибка сохранения", filename, ":", e$message))
    FALSE
  })
}

# Сохранение всех графиков
print("Начинаем сохранение графиков...")

# Объединённый график
safe_save_plot(
  combined_plot,
  "activity_analysis_2023_2024.png",
  width = 12,
  height = 8
)

# График по месяцам
safe_save_plot(
  p1,
  "monthly_activity_2023_2024.png",
  width = 8,
  height = 6
)

# График по дням недели
safe_save_plot(
  p2,
  "weekly_activity_2023_2024.png",
  width = 8,
  height = 6
)

# График по часам
safe_save_plot(
  p3,
  "hourly_activity_2023_2024.png",
  width = 8,
  height = 6
)

# Экспорт топ‑10 страниц в CSV
write.csv(top_pages,
          file.path(output_dir, "top_10_most_active_pages_2023_2024.csv"),
          row.names = FALSE)
print("Топ‑10 самых активных страниц сохранён в CSV.")


# Дополнительно: сохраняем полную статистику по страницам
write.csv(page_summary,
          file.path(output_dir, "full_page_activity_summary_2023_2024.csv"),
          row.names = FALSE)
print("Полная статистика активности страниц сохранена в CSV.")

# === ВЫВОД РЕЗУЛЬТАТОВ В КОНСОЛЬ ===
print("\n=== РЕЗУЛЬТАТЫ АНАЛИЗА ===")

print("Топ-10 самых активных страниц:")
print(top_pages)

print("\nОбщая статистика:")
print(paste("Всего обработано действий:", nrow(clean_data)))
print(paste("Уникальных страниц:", n_distinct(clean_data$title)))
print(paste("Уникальных пользователей:", n_distinct(clean_data$user)))
print(paste("Период анализа:", min(clean_data$date), "по", max(clean_data$date)))

print("\nАктивность по месяцам:")
print(monthly_views)

print("\nАктивность по дням недели:")
print(weekly_views)

print("\nАктивность по часам суток:")
print(hourly_views)

# === ДОПОЛНИТЕЛЬНАЯ ДИАГНОСТИКА ===
print("\n=== ДОПОЛНИТЕЛЬНАЯ ДИАГНОСТИКА ===")
print("Первые 10 записей исходных данных:")
print(head(page_views$query$recentchanges, 10))

print("\nСтруктура очищенных данных:")
str(clean_data)

print("\nСтатистика пропущенных значений:")
print(sapply(clean_data, function(x) sum(is.na(x))))

# === ПРОВЕРКА СОХРАНЁННЫХ ФАЙЛОВ ===
print("\n---")
print("Проверка сохранённых файлов:")
saved_files <- list.files(output_dir, pattern = ".png|.csv", full.names = TRUE)
if (length(saved_files) > 0) {
  print("Успешно сохранены файлы:")
  for (file in saved_files) {
    file_info <- file.info(file)
    print(paste(basename(file), "-", file_info$size, "байт"))
  }
} else {
  print("Файлы не найдены в папке", output_dir)
}

# === ФИНАЛЬНОЕ СООБЩЕНИЕ ===
print("\n" + "="*50)
print("АНАЛИЗ АКТИВНОСТИ СТРАНИЦ ЗАВЕРШЁН УСПЕШНО!")
print("="*50)

# Дополнительная информация для пользователя
print("\nИНФОРМАЦИЯ ДЛЯ ДАЛЬНЕЙШЕЙ РАБОТЫ:")
print("- Графики сохранены в папке:", output_dir)
print("- Основные результаты:")
print("  * top_10_most_active_pages_2023_2024.csv — топ-10 страниц")
print("  * full_page_activity_summary_2023_2024.csv — полная статистика")
print("- Для повторного запуска скрипта:")
print("  * проверьте актуальность URL API")
print("  * при необходимости измените параметры запросов (лимиты, даты)")
print("  * убедитесь в наличии прав на запись в рабочую директорию")

# === ОЧИСТКА ПАМЯТИ (опционально) ===
# Удаляем большие объекты, если они больше не нужны
rm(page_views, clean_data)
gc()  # сборщик мусора — освобождает память

print("\nПамять очищена. Скрипт завершён.")

Результат

1)Проверяет доступность API — выполняет тестовый запрос к серверу

2) Загружает данные о недавних изменениях на страницах из API за последний год (365 дней) — собирает сведения о действиях пользователей (редактирование страниц) с фильтрацией ботов.

3) Очищает и структурирует данные.

4) Анализирует активность по разным временным периодам.

5) Выполняет агрегацию по страницам — группирует данные по названию страницы и рассчитывает.

6) Строит и сохраняет 4 графика в папке saved_plots_page_views.