Минфин: данные по исполнению бюджетов субъектов РФ и местных бюджетов (perfomance/regions/operational)
| Признак | Значение |
|---|---|
| Уровень и охват | Субнациональный контур: сводные материалы по исполнению бюджетов субъектов РФ и местных бюджетов (формулировка раздела на сайте Минфина) |
| Тип доступа | Файлы по ссылке: HTML-каталог документов с кнопкой «Скачать» на каждый PDF |
| Основные форматы | PDF (в т.ч. файлы с подписью «Презентация…» в имени); обёртка — HTML |
| Оператор | Минфин России |
| Режим доступа | Открытый (типовое скачивание без регистрации с официальной страницы) |
Коротко: архив PDF-документов и презентаций Минфина по исполнению бюджетов субъектов и местных бюджетов — удобен для обзорных материалов и визуальных сводок; для машинной обработки и сопоставления с агрегированными таблицами по субъектам в первую очередь смотрите краткую информацию subbud/execute (XLSX), для регламентированного контура — отчёты Казначейства и муниципальные источники.
Описание
Карточка описывает витрину Данные по исполнению бюджетов субъектов Российской Федерации и местных бюджетов в разделе сайта Минфина «Деятельность → Межбюджетные отношения с регионами и муниципалитетами». На странице перечислены документы с датами публикации и ссылками на вложения; типичное вложение — PDF объёмом порядка 1,5–2,5 МБ, часть файлов именуется как презентации (Prezentatsiya_…pdf), часть — как аналитические материалы (Analiz_…pdf и др.).
Канонический путь в URL содержит историческую опечатку perfomance (не performance); при ручном наборе адреса используйте именно её.
Сюда не входят краткие XLSX-своды по консолидированным бюджетам субъектов (раздел statistics/subbud/execute) и каталог открытых наборов Минфина — иной раздел сайта и иной формат публикаций.
Оператор
Минфин России — канонический URL раздела: https://minfin.gov.ru/ru/perfomance/regions/operational/
- Карточка ИС: Сайт Министерства финансов РФ — публикация материалов подраздела «Межбюджетные отношения с регионами и муниципалитетами» и вложений к документам.
URL и точки доступа
| Тип доступа | URL | Формат |
|---|---|---|
| Каталог документов (список, «Скачать» для каждого файла) | https://minfin.gov.ru/ru/perfomance/regions/operational/ | HTML; вложения PDF |
| Родительский раздел «Межбюджетные отношения с регионами и муниципалитетами» | https://minfin.gov.ru/ru/perfomance/regions/ | HTML (навигация по смежным материалам) |
Прямые URL PDF при обновлении вложений меняются; для автоматизации ориентируйтесь на актуальную ссылку «Скачать» в карточке документа на странице каталога.
Объекты данных и показатели
Состав слайдов и таблиц задаётся конкретным PDF; по смыслу заголовков каталога это:
- Сводные показатели по исполнению местных бюджетов в РФ на отчётные даты (квартальные срезы в названиях документов: 01.01, 01.04, 01.07, 01.10 и т.п. — проверяйте шапку файла на дату скачивания).
- Материалы по субъектам в логике раздела (совокупность «субъекты + местные» — уточняйте по содержанию выбранного PDF: оглавление, подписи к графикам и таблицам).
Пробелы: нет стабильного CSV/XML/API; извлечение цифр требует OCR или парсинга PDF и ручной валидации. Это не замена форм исполнения и не дублирует построчно 0503317 по субъектам.
Структура данных
Ниже описан реально проверенный шаблон двух последних файлов из каталога: «Анализ» на 01.04.2022 и «Презентация» на 01.01.2022. Это описание не следует переносить на более ранние PDF без первичной проверки шапки и страниц: архив начинается в 2015 году.
Что является записью
| Логический объект | Гранулярность и строка | Поля, реально видимые в PDF | Подтверждение |
|---|---|---|---|
| Сводный показатель местных бюджетов | Одна строка на показатель по Российской Федерации и отчётной дате | название показателя, исполнено на две даты, темп изменения; отдельно встречаются доли в процентах | Таблица «Основные показатели…», с. 2 «Анализа» |
| Показатель по федеральному округу | Столбец/подпись графика на федеральный округ | название округа, значение на две даты или доля; явного кода округа нет | Графики на с. 3, с. 5 и с. 8 |
| Субъект в выборке профицита/дефицита | Не полный реестр, а список пяти крупнейших значений на слайде | русское название субъекта, дефицит; для дефицитных субъектов — изменение остатков и кредитные средства | с. 7 «Анализа» |
| Структура расходов или муниципального долга | Категория на диаграмме по РФ; на с. 8 также разрез федеральных округов | текстовая категория, значение, доля; кода БК/КБК в подписи нет | Расходы — с. 6, долг — с. 8 |
Следовательно, строкой выгрузки нельзя делать отдельное муниципальное образование: в проверенных файлах нет перечня муниципалитетов и нет ОКТМО. Базовая гранулярность — вся РФ; дополнительные измерения — федеральный округ и небольшая выборка субъектов.
Поля записи
| Русское поле | Латинский slug | Тип | Единица / значения | Примечание |
|---|---|---|---|---|
| Отчётная дата | reporting_date | date | YYYY-MM-DD | Из титула и шапок «Исполнено на …»; например, 2022-04-01 в «Анализе». |
| Сравнительная дата | comparison_date | date или null | YYYY-MM-DD | В таблице с. 2 это аналогичная дата предыдущего года. |
| Уровень географии | geography_level | string | russia, federal_district, subject | Не путать с уровнем бюджета. |
| Наименование географии | geography_name | string | «Российская Федерация», ЦФО, название субъекта | Для субъектов есть только название в выборке на с. 7. |
| Уровень бюджета | budget_level | string | только local в проверенных PDF | Титул и таблица прямо говорят о местных бюджетах. |
| Наименование показателя | metric_name_ru | string | как в PDF | Храните исходную русскую подпись вместе с нормализованным slug. |
| Нормализованный показатель | metric_slug | string | например, revenue_total, tax_revenue, interbudget_transfer, expenditure_total, budget_balance, municipal_debt | Сопоставление строится по подписи, а не по напечатанному коду: кодов нет. |
| Группа показателя | metric_group | string | revenue, transfer, expenditure, balance, debt, debt_service, share | Группы выведены из заголовков и легенд слайдов 2–8. |
| Значение | value | number | обычно rub_billions; для строк-долей — percent | В шапке и на графиках проверенных файлов указано «млрд. руб.»; темпы и доли — проценты. |
| Значение за сравниваемую дату | comparison_value | number или null | та же единица | С. 2 и большинство графиков содержат две даты. |
| Темп изменения | growth_percent | number или null | проценты | На с. 2 это отношение исполнения на текущую дату к предыдущей, а не процентный пункт. |
| Доля | share_percent | number или null | проценты | Для структуры доходов, расходов, трансфертов и долга. |
| Срез / тип периода | period_kind | string | year_to_date или stock_as_of | Доходы, расходы и трансферты подписаны «исполнено на …»; муниципальный долг — остаток на дату. |
| Источник в документе | source_page, source_table | integer, string или null | номер страницы, название таблицы/графика | Нужны для повторной проверки извлечённого числа. |
| Нативный идентификатор субъекта | subject_code, oktmo, okato, inn | всегда null в проверенных PDF | — | Не придумывайте код из названия субъекта. |
Ниже — JSON Schema для одной нормализованной записи. Она намеренно допускает null для чисел, которых нет на конкретном слайде, и не объявляет несуществующие идентификаторы обязательными.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Наблюдение из PDF Минфина о местных бюджетах",
"type": "object",
"additionalProperties": false,
"required": [
"source_file",
"reporting_date",
"geography_level",
"geography_name",
"budget_level",
"metric_name_ru",
"metric_slug",
"metric_group",
"value",
"unit",
"source_page",
"extraction_status"
],
"properties": {
"source_file": {
"type": "string",
"description": "Имя локально скачанного PDF; прямой URL хранится отдельно из каталога."
},
"reporting_date": {
"type": "string",
"format": "date",
"description": "Отчётная дата (дата среза)."
},
"comparison_date": {
"type": ["string", "null"],
"format": "date",
"description": "Аналогичная дата предыдущего года, если она есть в шапке."
},
"period_kind": {
"enum": ["year_to_date", "stock_as_of"]
},
"geography_level": {
"enum": ["russia", "federal_district", "subject"]
},
"geography_name": {
"type": "string"
},
"subject_code": {
"type": ["string", "null"],
"description": "Заполняется только внешним справочником; PDF его не публикует."
},
"budget_level": {
"const": "local"
},
"metric_name_ru": {
"type": "string"
},
"metric_slug": {
"type": "string",
"examples": ["revenue_total", "tax_revenue", "municipal_debt"]
},
"metric_group": {
"enum": ["revenue", "transfer", "expenditure", "balance", "debt", "debt_service", "share"]
},
"value": {
"type": ["number", "null"]
},
"comparison_value": {
"type": ["number", "null"]
},
"growth_percent": {
"type": ["number", "null"]
},
"share_percent": {
"type": ["number", "null"]
},
"unit": {
"enum": ["rub_billions", "percent"]
},
"source_page": {
"type": "integer",
"minimum": 1
},
"source_table": {
"type": ["string", "null"]
},
"raw_label": {
"type": "string",
"description": "Подпись в PDF до нормализации."
},
"extraction_status": {
"enum": ["native_table", "chart_or_text", "manual_review"]
}
}
}
Измерения, период и категории
- В обоих проверенных PDF единственный уровень бюджета — местные бюджеты, а не консолидированный бюджет субъекта. Формулировка повторяется на титуле и в заголовке таблицы на с. 2 «Презентации».
- Для доходов выделены общие, собственные, налоговые и неналоговые доходы; для безвозмездных поступлений — дотации, субсидии, иные межбюджетные трансферты и субвенции (с. 2). Для расходов используются текстовые названия разделов, включая образование, общегосударственные вопросы и национальную экономику (с. 6); числовых кодов БК/КБК на слайдах нет.
- Для исполнения читайте «на дату» как накопленный с начала года результат, пока шапка конкретного PDF не говорит иного: на с. 2 сопоставлены 01.04.2021 и 01.04.2022. Срез 01.01 в «Презентации» отражает итог предыдущего календарного года. Муниципальный долг, напротив, является остатком на дату (с. 8).
- Современная часть каталога показывает квартальные срезы 01.01, 01.04, 01.07, 01.10 за 2020–2022 годы; записи 2015–2019 годов встречаются также ежемесячно. Не навязывайте квартальную периодичность всему архиву.
Ключи связки
В проверенных PDF нет ОКТМО, ОКАТО, кода субъекта, ИНН, кода БК или КБК. Поэтому автоматическая стыковка с XLSX subbud/execute, данными Казначейства или ФНС по нативному ключу невозможна.
Допустимый, но внешний шаг — нормализовать лишь опубликованное русское subject_name из выборки на с. 7 к отдельному справочнику субъектов РФ и хранить результат как subject_code с признаком происхождения external_mapping. Он не превращает этот PDF в полный региональный или муниципальный набор и не создаёт ОКТМО. Названия федеральных округов также остаются текстовыми категориями без кода.
Эвристики имени файла и шапки
from datetime import date
from pathlib import Path
from urllib.parse import unquote, urlparse
import re
SLICE_RE = re.compile(
r"(?<!\d)(?P<day>0[1-9]|[12]\d|3[01])[._-]"
r"(?P<month>0[1-9]|1[0-2])[._-](?P<year>20\d{2})(?!\d)"
r"|(?<!\d)(?P<compact>01(?:0[1-9]|1[0-2])20\d{2})(?!\d)"
r"|(?<!\d)(?P<compact_short>01(?:0[1-9]|1[0-2])\d{2})(?!\d)",
re.IGNORECASE,
)
def slice_from_filename_or_title(value: str) -> date | None:
name = unquote(Path(urlparse(value).path).name) if "://" in value else value
match = SLICE_RE.search(name)
if not match:
return None
if match.group("compact"):
compact = match.group("compact")
return date(int(compact[4:8]), int(compact[2:4]), int(compact[:2]))
if match.group("compact_short"):
compact = match.group("compact_short")
return date(2000 + int(compact[4:6]), int(compact[2:4]), int(compact[:2]))
return date(
int(match.group("year")),
int(match.group("month")),
int(match.group("day")),
)
def document_kind(filename: str) -> str:
name = unquote(filename).lower()
if "prezentatsiya" in name or "презентац" in name:
return "presentation"
if "analiz" in name or "анализ" in name:
return "analysis"
return "document"
UNIT_RE = re.compile(r"(?i)\b(млрд\.?\s*руб\.?|тыс\.?\s*руб\.?|руб\.?)")
def table_header_hints(page_text: str) -> dict[str, str | None]:
lower = page_text.lower()
if "местных бюджетов" in lower:
budget_scope = "local"
elif "консолидирован" in lower:
budget_scope = "consolidated"
else:
budget_scope = "unknown"
unit = UNIT_RE.search(page_text)
return {
"budget_scope": budget_scope,
"unit_text": unit.group(1) if unit else None,
}
Для данного источника сначала ищите дату и тип файла в имени, затем подтверждайте их титулом и шапкой с. 2. В проверенных PDF Prezentatsiya и Analiz отличаются именем и датой каталога, но имеют один восьмислайдовый шаблон. Слово «Отчёт» или «Документ» в карточке каталога — отдельная метка сайта, а не надёжный тип вложения.
Периодичность обновления
Новые карточки документов появляются по мере публикации Минфином; у каждой записи на странице указаны даты «Опубликовано» и «Изменено». На дату проверки 18.07.2026 каталог содержит 68 материалов за 2015–2022 годы; наиболее поздняя карточка опубликована 13.05.2022. Перед аналитикой сверяйте актуальность раздела и при необходимости дополняйте данными Казначейства и ГИИС «Электронный бюджет».
Ограничения и особенности
- Материалы официального сайта Минфина распространяются на условиях Creative Commons Attribution 4.0 (блок в подвале страниц
minfin.gov.ru); при переработке указывайте источник. - PDF-презентации удобны для чтения человеком, но плохо подходят для автоматического конвейера без доработки (верстка, сканы, разные шаблоны по годам).
- Показатели в PDF не обязаны совпадать с XLSX subbud/execute и открытыми наборами Минфина — сверяйте определение показателя, срез и методику в тексте документа.
Примеры доступа
Сохранить HTML-страницу каталога для ручного или последующего разбора ссылок «Скачать»:
curl -sS "https://minfin.gov.ru/ru/perfomance/regions/operational/" -o minfin-regions-operational.html
Примеры работы с данными
Инвентаризация каталога
Снимок каталога от 18.07.2026 содержит 68 карточек и восемь страниц Ajax-пагинации. В таблице ниже «карточка» ведёт на запись каталога, а «вложение» — на прямой URL, полученный из её ссылки «Скачать». Это именно снимок: прямой URL не является контрактом и при следующей публикации может измениться. Знак «—» в графе изменения означает, что соответствующая карточка каталога не вывела дату «Изменено».
Структура одной записи каталога для сохранения снимка:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Запись каталога PDF Минфина",
"type": "object",
"additionalProperties": false,
"required": [
"title",
"catalog_document_type",
"published_date",
"catalog_item_url",
"attachments"
],
"properties": {
"title": {
"type": "string"
},
"catalog_document_type": {
"type": ["string", "null"],
"description": "Метка карточки сайта: «Документ» или «Отчёт»; не тип файла."
},
"published_date": {
"type": ["string", "null"],
"format": "date"
},
"modified_date": {
"type": ["string", "null"],
"format": "date"
},
"catalog_item_url": {
"type": "string",
"format": "uri"
},
"attachments": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["label", "url", "format_size"],
"properties": {
"label": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"format_size": {
"type": "string",
"examples": ["pdf, 1.76 mb"]
}
}
}
}
}
}
Ниже рабочий пример сохраняет HTML и проходит все страницы, не хардкодя имена или URL PDF. Перед первым запуском установите зависимости командой python -m pip install requests beautifulsoup4.
curl -L --fail --silent --show-error --compressed \
-A "Mozilla/5.0 (compatible; minfin-catalog-parser/1.0)" \
-H "Accept-Language: ru-RU,ru;q=0.9" \
"https://minfin.gov.ru/ru/perfomance/regions/operational/" \
-o minfin-regions-operational.html
from __future__ import annotations
from datetime import datetime
from urllib.parse import urljoin
import json
import requests
from bs4 import BeautifulSoup
CATALOG_URL = "https://minfin.gov.ru/ru/perfomance/regions/operational/"
HEADERS = {
"User-Agent": "Mozilla/5.0 (compatible; minfin-catalog-parser/1.0)",
"Accept-Language": "ru-RU,ru;q=0.9",
}
def decode_catalog(raw: bytes) -> str:
# На текущей странице указан UTF-8; fallback нужен для старых ответов/зеркал.
for encoding in ("utf-8", "cp1251"):
try:
text = raw.decode(encoding)
except UnicodeDecodeError:
continue
if "document_card" in text:
return text
return raw.decode("utf-8", errors="replace")
def get_soup(session: requests.Session, url: str) -> BeautifulSoup:
response = session.get(url, timeout=30)
response.raise_for_status()
return BeautifulSoup(decode_catalog(response.content), "html.parser")
def parse_date(text: str | None) -> str | None:
if not text:
return None
text = text.strip()
for prefix in ("Опубликовано:", "Изменено:"):
if text.startswith(prefix):
text = text.removeprefix(prefix).strip()
try:
return datetime.strptime(text, "%d.%m.%Y").date().isoformat()
except ValueError:
return None
def parse_card(card) -> dict:
title = card.select_one("a.document_title")
doc_type = card.select_one("a.document_type")
dates = {"published_date": None, "modified_date": None}
for node in card.select(".document_info .date"):
text = node.get_text(" ", strip=True)
if text.startswith("Опубликовано:"):
dates["published_date"] = parse_date(text)
elif text.startswith("Изменено:"):
dates["modified_date"] = parse_date(text)
attachments = []
for file_item in card.select(".files_list a.file_item"):
attachments.append(
{
"label": file_item.select_one(".file_title").get_text(" ", strip=True),
"url": urljoin(CATALOG_URL, file_item["href"]),
"format_size": file_item.select_one(".file_info").get_text(" ", strip=True),
}
)
return {
"title": title.get("title", title.get_text(" ", strip=True)),
"catalog_document_type": doc_type.get_text(" ", strip=True) if doc_type else None,
"catalog_item_url": urljoin(CATALOG_URL, title["href"]),
**dates,
"attachments": attachments,
}
def collect_catalog() -> list[dict]:
with requests.Session() as session:
session.headers.update(HEADERS)
first = get_soup(session, CATALOG_URL)
pager = first.select_one(".ajax-pagination-div a[data-page-count]")
page_count = int(pager["data-page-count"]) if pager else 1
pages = [first]
for page in range(2, page_count + 1):
pages.append(get_soup(session, "{}?page_65={}".format(CATALOG_URL, page)))
records = []
seen = set()
for soup in pages:
for card in soup.select("#ajax-pagination-content-10391-65 .document_card"):
record = parse_card(card)
if record["catalog_item_url"] not in seen:
seen.add(record["catalog_item_url"])
records.append(record)
return records
records = collect_catalog()
if not records or any(not item["attachments"] for item in records):
raise RuntimeError("Не найдены карточки или ссылки «Скачать»; проверьте HTML-каталог.")
print(json.dumps(records, ensure_ascii=False, indent=2))
Репрезентативные PDF
| Файл | Карточка и размер в каталоге | Метаданные файла | Структура и преобладающий контент |
|---|---|---|---|
| Analiz_01.04.2022.pdf | «Данные… на 01.04.2022», «Документ», опубликовано и изменено 13.05.2022, 1.76 mb | 1 849 499 байт, 8 страниц, 720 × 540 pt; PDF создан 13.05.2022 в PowerPoint 2016; metadata title «Налоговые и неналоговые доходы», author «Домбровский Е.А.»; титул даёт срез 01.04.2022 | Титул; сводная таблица; доходы; структура доходов; трансферты; расходы; дефицит/профицит; муниципальный долг. На 6 из 8 страниц преобладают диаграммы, на с. 2 — таблица, на с. 7 — график и таблица; карт нет. |
| Prezentatsiya_na_01.01.2022.pdf | «Данные… на 01.01.2022», «Отчёт», опубликовано и изменено 05.03.2022, 1.91 mb | 2 000 259 байт, 8 страниц, 720 × 540 pt; PDF создан 05.03.2022 в PowerPoint 2016; те же title и author; титул даёт срез 01.01.2022 | Тот же порядок восьми слайдов и та же вёрстка: титул, одна основная таблица, затем текстовые пояснения и столбчатые/круговые диаграммы; карт нет. |
Это презентационные PDF, поэтому обычного оглавления нет. Слайды 3–8 совмещают русский пояснительный текст и диаграммы; терминология официальная финансовая: доходы, межбюджетные трансферты, субвенции, дефицит/профицит, муниципальный долг. Не принимайте визуально подписанные графики за полноценные таблицы: их числовые подписи могут требовать отдельной ручной проверки.
Извлечение основной таблицы PDF
Первый рабочий шаг — извлечь нативную таблицу со с. 2. Он не пытается автоматически угадать все числа на диаграммах: для них запись получает статус manual_review.
from __future__ import annotations
from datetime import date, datetime
from pathlib import Path
import re
from typing import Any
import pandas as pd
import pdfplumber
DATE_RE = re.compile(r"(?<!\d)(\d{2})\.(\d{2})\.(20\d{2})(?!\d)")
SLUGS = {
"доходы, всего": ("revenue_total", "revenue"),
"собственные доходы": ("own_revenue", "revenue"),
"налоговые и неналоговые доходы": ("tax_and_nontax_revenue", "revenue"),
"налоговые доходы": ("tax_revenue", "revenue"),
"неналоговые доходы": ("nontax_revenue", "revenue"),
"межбюджетные трансферты": ("interbudget_transfer", "transfer"),
"в том числе: дотации": ("grant", "transfer"),
"субсидии": ("subsidy", "transfer"),
"иные межбюджетные трансферты": ("other_interbudget_transfer", "transfer"),
"другие безвозмездные поступления": ("other_gratuitous_receipts", "revenue"),
"субвенции": ("subvention", "transfer"),
"расходы, всего": ("expenditure_total", "expenditure"),
"расходы на решение вопросов местного значения": ("local_issues_expenditure", "expenditure"),
"дефицит/профицит": ("budget_balance", "balance"),
}
def parse_pdf_number(value: str | None) -> float | None:
if not value:
return None
value = value.replace("\xa0", "").replace(" ", "").replace(",", ".").strip()
if value in {"", "-", "—"}:
return None
return float(value.rstrip("%"))
def to_date(value: str) -> date:
return datetime.strptime(value, "%d.%m.%Y").date()
def metric_meta(label: str) -> tuple[str, str]:
normalized = " ".join(label.lower().split())
for prefix, result in SLUGS.items():
if normalized.startswith(prefix):
return result
if normalized.startswith("в %"):
return ("share_of_parent_metric", "share")
return ("unmapped_metric", "share" if "%" in normalized else "revenue")
def parse_minfin_regions_pdf(path: str | Path) -> list[dict[str, Any]]:
path = Path(path)
with pdfplumber.open(path) as pdf:
if len(pdf.pages) < 2:
raise ValueError("Ожидался PDF со сводной таблицей на второй странице.")
page = pdf.pages[1]
table = page.extract_table()
if not table or len(table) < 3:
raise ValueError("Сводная таблица не извлечена; проверьте файл вручную.")
header = " ".join(
cell.replace("\n", " ") for row in table[:2] for cell in row if cell
)
header_dates = [to_date(".".join(match)) for match in DATE_RE.findall(header)]
unique_dates = list(dict.fromkeys(header_dates))
if len(unique_dates) < 2:
raise ValueError("Не найдены обе даты в шапке таблицы.")
comparison_date, reporting_date = unique_dates[:2]
observations = []
for row in table[2:]:
row = (row + [None] * 4)[:4]
raw_label = " ".join((row[0] or "").split())
if not raw_label:
continue
metric_slug, metric_group = metric_meta(raw_label)
is_percent = raw_label.lower().startswith("в %") or "%" in (row[2] or "")
observations.append(
{
"source_file": path.name,
"reporting_date": reporting_date.isoformat(),
"comparison_date": comparison_date.isoformat(),
"period_kind": "year_to_date",
"geography_level": "russia",
"geography_name": "Российская Федерация",
"subject_code": None,
"budget_level": "local",
"metric_name_ru": raw_label,
"metric_slug": metric_slug,
"metric_group": metric_group,
"value": parse_pdf_number(row[2]),
"comparison_value": parse_pdf_number(row[1]),
"growth_percent": parse_pdf_number(row[3]),
"share_percent": parse_pdf_number(row[2]) if is_percent else None,
"unit": "percent" if is_percent else "rub_billions",
"source_page": 2,
"source_table": "Основные показатели местных бюджетов",
"raw_label": raw_label,
"extraction_status": "native_table",
}
)
return observations
records = parse_minfin_regions_pdf("Analiz_01.04.2022.pdf")
frame = pd.DataFrame(records)
print(frame[["metric_slug", "value", "comparison_value", "growth_percent", "unit"]])
На проверенном «Анализе» функция возвращает 20 строк со с. 2. Для воспроизводимой сверки проверьте, что для строки «Доходы, всего» получаются 1 132.8 и 1 011.5, а для «Дефицит/профицит» — 59.7 и 58.7. Диаграммы на с. 3–8 и таблица дефицитных субъектов на с. 7 требуют отдельного извлекателя или ручной разметки; не смешивайте эти результаты с нативной таблицей без поля source_page.
Ограничения при автоматизации
- Это не XLSX subbud/execute: здесь опубликованы презентационные PDF об исполнении местных бюджетов с визуальными агрегатами, тогда как тот источник содержит табличные своды по консолидированным бюджетам субъектов. Не переносите значения, уровни бюджета, дату среза или методику из одного контура в другой без проверки.
- PDF содержит текстовый слой в двух проверенных файлах, но архивные шаблоны меняются: имя вложения, число слайдов, объединённые заголовки, подписи осей и расположение таблиц не стабильны. Скан или «развалившаяся» таблица должны переключать обработку на OCR или manual_review, а не на тихое заполнение нулями.
- На с. 3–8 много графиков. Ошибки типичны для десятичной запятой, пробелов-разделителей, процентов, перекрывающихся подписей и 3D-диаграмм. Сумму доходов, расходов и баланс из с. 2 проверяйте арифметически; например, в «Анализе» 1 132.8 − 1 073.1 = 59.7 млрд руб. (с. 2).
- При первой загрузке каждого нового PDF вручную сопоставьте URL из свежего HTML-каталога, заголовок и дату титула, единицу «млрд. руб.», уровень «местные бюджеты», две даты в шапке и количество извлечённых строк. Затем отдельно проверьте, не является ли долг остатком на дату вместо накопленного исполнения.
- В подвале проверенной страницы Минфина указана лицензия Creative Commons Attribution 4.0. При использовании указывайте Минфин России, название и дату документа, URL карточки каталога и дату обращения; не выдавайте извлечённую или нормализованную таблицу за исходную официальную выгрузку.
Сводка для машинной обработки
primary_url: "https://minfin.gov.ru/ru/perfomance/regions/operational/"
catalog_selector_hint: "#ajax-pagination-content-10391-65 .document_card; .files_list a.file_item[href$='.pdf']; пагинация ?page_65=N"
catalog_snapshot:
checked_on: "2026-07-18"
document_count: 68
coverage: "2015-01-01..2022-04-01 по датам среза в заголовках"
formats: [html, pdf]
update_cadence: "по мере публикации; в карточке документа видны «Опубликовано» и, если есть, «Изменено»"
reporting_slices: ["01.01", "01.04", "01.07", "01.10"]
historical_cadence_note: "в 2015–2019 встречаются и ежемесячные срезы"
budget_scope: "local_budgets"
native_join_keys: []
non_native_identifiers: [oktmo, okato, subject_code, inn, kbk]
possible_external_mapping: ["subject_name из ограниченной выборки на с. 7"]
typical_units: [rub_billions, percent]
parser_libs: [pdfplumber, pypdf, pandas, beautifulsoup4, requests]
known_caveats:
- "Прямые URL вложений меняются при переработке файла; каждый запуск начинает с HTML-каталога."
- "Шаблоны PDF различаются по годам; таблица на с. 2 и диаграммы требуют разных извлекателей."
- "В проверенных PDF нет ОКТМО, ОКАТО, ИНН, кодов субъектов и КБК."
- "Графики и 3D-диаграммы не дают надёжной машинной таблицы без ручной верификации."
license: "CC BY 4.0; указывать Минфин России и URL исходной карточки"
Связанные страницы wiki
- Минфин: краткая информация об исполнении консолидированных бюджетов субъектов (subbud/execute, XLSX) — агрегированные таблицы по субъектам в XLSX из раздела «Статистика»; не смешивать с PDF из perfomance/regions без проверки методики.
- Муниципальные бюджеты — точки входа к публичным данным местного уровня относительно сводов Минфина.
- Региональные бюджеты — плановый контур и сайты субъектов; дополняет картину относительно факта в федеральных сводах.
- Казначейство: свод по учреждениям субъектов РФ (местных бюджетов) — смежный федеральный свод по учреждениям местных бюджетов в иной логике и форматах.
- Отчёты об исполнении бюджетов (обзор) — где в цепочке источников лежит факт исполнения относительно плана.
- Отчётность об исполнении местных бюджетов — регламентированный контур отчётности местного уровня.
- Уровни бюджета — разграничение регионального и местного уровней при интерпретации сводов.
Не путать с
- Минфин: краткая информация об исполнении консолидированных бюджетов субъектов (subbud/execute) — другой URL (
/ru/statistics/subbud/execute/), формат XLSX, акцент на консолидированных бюджетах субъектов в табличном виде. - Открытые данные Минфина России — реестр наборов с
list.csvи паспортами, а не PDF-каталог раздела perfomance.
Частые вопросы
В: Можно ли стабильно скачивать последний PDF скриптом по фиксированному URL?
О: Нет: прямые ссылки на файлы в /common/upload/library/... меняются при публикации новой редакции. Ориентируйтесь на разбор HTML-каталога или ручное скачивание с проверкой даты документа.
В: Достаточно ли этих PDF для сравнения регионов в одной таблице?
О: Обычно удобнее начать с XLSX subbud/execute или выгрузок Казначейства; PDF здесь — скорее иллюстративный и методический слой.