Files
crm.clientright.ru/court_parser_function_n8n.js
Fedor 01c4fe80b5 chore: snapshot current working tree changes
Save all currently accumulated repository changes as a backup snapshot for Gitea so no local work is lost.
2026-03-26 14:19:01 +03:00

308 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Готовый код для вставки в ноду "парсим суд" в n8n workflow
// Скопируйте весь этот код в поле Body ноды HTTP Request
export default async function ({ page, context }) {
// Получаем данные из переменных n8n workflow
// ВАЖНО: шаблоны n8n должны быть в кавычках!
const url = '{{ $json.link }}';
const status = '{{ $json.status }}';
if (!url || url === '') throw new Error('❌ Не передан url');
const sleep = ms => new Promise(r => setTimeout(r, ms));
// Определяем тип суда по URL
const isMoscowCourt = /mos-(gorsud|sud)\.ru/.test(url);
const isRegionalCourt = /\.sudrf\.ru/.test(url) && !isMoscowCourt;
// Установка заголовков и поведения браузера
await page.setViewport({ width: 1920, height: 1080 });
await page.setExtraHTTPHeaders({
"Referer": isMoscowCourt ? "https://mos-sud.ru/" : "https://sudrf.ru/",
"Origin": isMoscowCourt ? "https://mos-sud.ru" : "https://sudrf.ru",
"Accept-Language": "ru,en;q=0.9",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Upgrade-Insecure-Requests": "1",
});
await page.setUserAgent(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
);
await page.goto(url, { waitUntil: "networkidle2", timeout: 60000 });
// Закрыть баннеры cookies, если есть
try {
await page.waitForSelector("#cookie-disclaimer .cd-close-button, .cookie-accept, .cookie__close", { timeout: 3000 });
const btns = await page.$$("#cookie-disclaimer .cd-close-button, .cookie-accept, .cookie__close");
if (btns[0]) await btns[0].click();
} catch (_) {}
await sleep(2000);
// ========================================
// ПАРСИНГ РЕГИОНАЛЬНЫХ СУДОВ (*.sudrf.ru)
// ========================================
if (isRegionalCourt) {
// Определяем div для парсинга (аналогично parscourt.php)
const divId = (status === 'представительство в суде 1й инстанции' ||
status === 'выдача листа' ||
status === 'исполнительное производство' ||
status === 'заявление на лист') ? 'cont2' : 'cont3';
const events = await page.evaluate((divId) => {
const clean = (str) => (str ? str.replace(/\s+/g, ' ').trim() : '');
const div = document.querySelector(`#${divId}`);
if (!div) return [];
const rows = Array.from(div.querySelectorAll('tr'));
const events = [];
rows.forEach((row) => {
const tds = row.querySelectorAll('td');
if (tds.length < 2) return;
const event_name = clean(tds[0]?.textContent || '');
const event_date = clean(tds[1]?.textContent || '');
const event_time = clean(tds[2]?.textContent || '');
const location = clean(tds[3]?.textContent || '');
const event_result = clean(tds[4]?.textContent || '');
const event_basis = clean(tds[5]?.textContent || '');
const note = clean(tds[6]?.textContent || '');
const publication_date = clean(tds[7]?.textContent || '');
// Пропускаем записи, если название события не указано или дата неверная
if (!event_name || !event_date || event_date === '1970-01-01') {
return;
}
events.push({
event_name,
event_date,
event_time,
location,
event_result,
event_basis,
note,
publication_date
});
});
return events;
}, divId);
// Возвращаем последнее событие (аналогично parscourt.php)
if (events.length > 0) {
const lastEvent = events[events.length - 1];
// Форматируем даты (аналогично parscourt.php)
const formatDate = (dateStr) => {
if (!dateStr) return '';
try {
const date = new Date(dateStr);
if (isNaN(date.getTime())) return dateStr;
return date.toISOString().split('T')[0]; // YYYY-MM-DD
} catch {
return dateStr;
}
};
return {
url,
source: new URL(url).hostname,
court_type: 'regional',
last_event: {
event_name: lastEvent.event_name,
event_date: formatDate(lastEvent.event_date),
event_time: lastEvent.event_time,
location: lastEvent.location,
event_result: lastEvent.event_result,
event_basis: lastEvent.event_basis,
note: lastEvent.note,
publication_date: formatDate(lastEvent.publication_date),
// Для совместимости с parscourt.php (кириллические ключи)
Наименование: lastEvent.event_name,
Дата: formatDate(lastEvent.event_date),
Время: lastEvent.event_time,
Место: lastEvent.location,
Результат: lastEvent.event_result,
Основание: lastEvent.event_basis,
Примечание: lastEvent.note,
'Дата размещения': formatDate(lastEvent.publication_date)
},
all_events: events
};
}
return {
url,
source: new URL(url).hostname,
court_type: 'regional',
last_event: null,
message: 'События не найдены'
};
}
// ========================================
// ПАРСИНГ МОСКОВСКИХ СУДОВ (mos-gorsud.ru)
// ========================================
if (isMoscowCourt) {
// Ждём карточку
await page.waitForSelector(
".detail-cart .row_card, .case-card, .case-details, .content, main .wrapper_innercontent",
{ timeout: 20000 }
);
// Активируем вкладки
try {
for (const id of ["#ui-id-1", "#ui-id-2", "#ui-id-3"]) {
if (await page.$(id)) await page.click(id);
}
const tabLinks = await page.$$(`a[href^="#tabs-"], .tabs_wrapper a.ui-tabs-anchor`);
if (tabLinks.length) for (const a of tabLinks) await a.click();
await page.waitForTimeout(300);
} catch (_) {}
const data = await page.evaluate(() => {
const norm = (el) => (el ? el.textContent.replace(/\s+/g, " ").trim() : "");
const qsa = (sel) => Array.from(document.querySelectorAll(sel));
// Таблицы
function tableToRows(tbody) {
return Array.from(tbody.querySelectorAll("tr")).map((tr) => {
const tds = tr.querySelectorAll("td");
return Array.from(tds).map((td) => norm(td.querySelector("div") || td));
});
}
const sessionsTbody = document.querySelector("#tabs-2 table tbody");
const hearingsRows = sessionsTbody ? tableToRows(sessionsTbody) : [];
const hearings = hearingsRows.map((cols) => ({
datetime: cols[0] || null,
hall: cols[1] || null,
stage: cols[2] || null,
result: cols[3] || null,
basis: cols[4] || null,
}));
const stTbody = document.querySelector("#tabs-1 #state-history table tbody");
const stateRows = stTbody ? tableToRows(stTbody) : [];
const states = stateRows.map((cols) => ({
date: cols[0] || null,
state: cols[1] || null,
basis_doc: cols[2] || null,
}));
return {
hearings,
history: { states },
};
});
// Извлекаем последнее событие (аналогично MoscowCourtParser)
let lastEvent = null;
// Проверяем заседания (hearings)
if (data.hearings && data.hearings.length > 0) {
const hearing = data.hearings[data.hearings.length - 1];
if (hearing.datetime) {
const datetime = hearing.datetime;
let event_date = '';
let event_time = '';
// Формат: "27.10.2025 09:30" или "27.10.2025"
const match1 = datetime.match(/(\d{2}\.\d{2}\.\d{4})\s+(\d{2}:\d{2})/);
if (match1) {
event_date = match1[1];
event_time = match1[2];
} else {
const match2 = datetime.match(/(\d{2}\.\d{2}\.\d{4})/);
if (match2) {
event_date = match2[1];
}
}
if (event_date) {
// Форматируем дату для БД (DD.MM.YYYY -> YYYY-MM-DD)
const formatDate = (dateStr) => {
const parts = dateStr.split('.');
if (parts.length === 3) {
return `${parts[2]}-${parts[1]}-${parts[0]}`;
}
return dateStr;
};
lastEvent = {
event_name: hearing.stage || 'Судебное заседание',
event_date: formatDate(event_date),
event_time: event_time,
location: hearing.hall || '',
event_result: hearing.result || '',
event_basis: hearing.basis || '',
note: '',
publication_date: formatDate(event_date),
// Для совместимости с parscourt.php
Наименование: hearing.stage || 'Судебное заседание',
Дата: event_date,
Время: event_time,
Место: hearing.hall || '',
Результат: hearing.result || '',
Основание: hearing.basis || '',
Примечание: '',
'Дата размещения': event_date
};
}
}
}
// Если заседаний нет, проверяем историю состояний
if (!lastEvent && data.history?.states && data.history.states.length > 0) {
const state = data.history.states[data.history.states.length - 1];
if (state.date && state.state) {
const formatDate = (dateStr) => {
const parts = dateStr.split('.');
if (parts.length === 3) {
return `${parts[2]}-${parts[1]}-${parts[0]}`;
}
return dateStr;
};
lastEvent = {
event_name: state.state,
event_date: formatDate(state.date),
event_time: '',
location: '',
event_result: '',
event_basis: state.basis_doc || '',
note: '',
publication_date: formatDate(state.date),
// Для совместимости с parscourt.php
Наименование: state.state,
Дата: state.date,
Время: '',
Место: '',
Результат: '',
Основание: state.basis_doc || '',
Примечание: '',
'Дата размещения': state.date
};
}
}
return {
url,
source: new URL(url).hostname,
court_type: 'moscow',
last_event: lastEvent,
all_hearings: data.hearings,
all_states: data.history?.states || []
};
}
// Если тип суда не определён
throw new Error(`Неизвестный тип суда для URL: ${url}`);
}