fix(sf): pravo.gov66 law_type числовой код =1 Постановление (#1149)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 1m30s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 2m21s
Deploy / deploy (push) Successful in 1m15s

Co-authored-by: bot-backend <bot-backend@gendsgn.local>
Co-committed-by: bot-backend <bot-backend@gendsgn.local>
This commit is contained in:
bot-backend 2026-06-07 14:17:52 +00:00 committed by bot-reviewer
parent a6e100b52a
commit e2faab801c
2 changed files with 18 additions and 3 deletions

View file

@ -28,8 +28,12 @@ _SEARCH_URL = f"{_BASE_URL}/search/"
# Тайм-аут щедрый: сервер иногда медленный. # Тайм-аут щедрый: сервер иногда медленный.
_TIMEOUT = httpx.Timeout(60.0, connect=15.0) _TIMEOUT = httpx.Timeout(60.0, connect=15.0)
# Числовые коды типов документов (select#id_law_type на сайте).
# Текстовое значение «Постановление» — неверный параметр, сервер не матчит → 0 хитов.
_LAW_TYPE_POSTANOVLENIE = "1" # Постановление Правительства Свердловской области
# Паттерны для извлечения ссылок. # Паттерны для извлечения ссылок.
# Числовой doc_id в пути: /35496/ # Числовой doc_id в пути: /35496/ (НЕ /documents/35496/ — у сайта такой структуры нет).
_RE_DOC_PATH = re.compile(r"^/(\d+)/$") _RE_DOC_PATH = re.compile(r"^/(\d+)/$")
# PDF в /media/pravo/ (не ecp-вариант: ecp — подписанная копия, не всегда парсится). # PDF в /media/pravo/ (не ecp-вариант: ecp — подписанная копия, не всегда парсится).
_RE_PDF_PATH = re.compile(r"/media/pravo/(?!ecp/)[^\s\"']+\.pdf", re.IGNORECASE) _RE_PDF_PATH = re.compile(r"/media/pravo/(?!ecp/)[^\s\"']+\.pdf", re.IGNORECASE)
@ -39,14 +43,16 @@ _RE_PDF_ECP_PATH = re.compile(r"/media/pravo/ecp/[^\s\"']+\.pdf", re.IGNORECASE)
def search_documents( def search_documents(
query: str, query: str,
law_type: str = "Постановление", law_type: str = _LAW_TYPE_POSTANOVLENIE,
since: str | None = None, since: str | None = None,
) -> list[dict[str, Any]]: ) -> list[dict[str, Any]]:
"""Поиск документов на pravo.gov66.ru. """Поиск документов на pravo.gov66.ru.
Args: Args:
query: поисковый запрос (2-3 слова; 1 или 4+ слов 0 результатов на сервере). query: поисковый запрос (2-3 слова; 1 или 4+ слов 0 результатов на сервере).
law_type: тип документа, напр. «Постановление». law_type: числовой код типа документа (см. select#id_law_type). По умолчанию
``_LAW_TYPE_POSTANOVLENIE="1"`` (Постановление). НЕ передавать текст вроде
«Постановление» сервер игнорирует нечисловые коды 0 хитов.
since: дата начала периода в формате «DD.MM.YYYY» (поле signed_start_date). since: дата начала периода в формате «DD.MM.YYYY» (поле signed_start_date).
Returns: Returns:
@ -161,6 +167,7 @@ def fetch_pdf(url: str) -> bytes:
__all__ = [ __all__ = [
"_LAW_TYPE_POSTANOVLENIE",
"fetch_pdf", "fetch_pdf",
"get_document_pdf_url", "get_document_pdf_url",
"search_documents", "search_documents",

View file

@ -7,6 +7,7 @@
from __future__ import annotations from __future__ import annotations
from app.services.scrapers.pravo_gov66_client import ( from app.services.scrapers.pravo_gov66_client import (
_LAW_TYPE_POSTANOVLENIE,
_extract_pdf_url, _extract_pdf_url,
_parse_search_html, _parse_search_html,
) )
@ -94,6 +95,13 @@ _DOC_HTML_NO_PDF = """
""" """
class TestLawTypeConstant:
def test_postanovlenie_is_numeric_string(self) -> None:
"""Числовой код — сервер игнорирует текстовые значения типа «Постановление»."""
assert _LAW_TYPE_POSTANOVLENIE == "1"
assert _LAW_TYPE_POSTANOVLENIE.isdigit()
class TestParseSearchHtml: class TestParseSearchHtml:
def test_extracts_doc_ids_and_titles(self) -> None: def test_extracts_doc_ids_and_titles(self) -> None:
results = _parse_search_html(_SEARCH_HTML_FIXTURE) results = _parse_search_html(_SEARCH_HTML_FIXTURE)