From 8e7903dc347d3370257ecc00fd9798c802144535 Mon Sep 17 00:00:00 2001 From: Herzic Date: Mon, 16 Mar 2026 11:28:40 +0300 Subject: [PATCH] initial commit --- .gitignore | 20 ++++ parse/collect_dealers_autoru.js | 200 ++++++++++++++++++++++++++++++++ readme.md | 7 ++ 3 files changed, 227 insertions(+) create mode 100644 .gitignore create mode 100644 parse/collect_dealers_autoru.js create mode 100644 readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1828adf --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +.env +.env.* +!.env.example + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist +.output + +# Vite files +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +.vite/ + +# Dependency directories +node_modules/ \ No newline at end of file diff --git a/parse/collect_dealers_autoru.js b/parse/collect_dealers_autoru.js new file mode 100644 index 0000000..18c0305 --- /dev/null +++ b/parse/collect_dealers_autoru.js @@ -0,0 +1,200 @@ +(async function() { + const csrfToken = "79684b90849bec4c80846f355dd1671b48338cc739007d81"; // ← ОБНОВИ! + const url = "https://auto.ru/krasnodar/dilery/cars/new/?place_lat_from=46.65304&place_lon_from=38.80775&place_lat_to=48.07858&place_lon_to=40.5024&geo_radius=300"; // Вставьте URL здесь + const params = new URLSearchParams(url.split('?')[1]); + const latMin = parseFloat(params.get('place_lat_from')); + const latMax = parseFloat(params.get('place_lat_to')); + const lonMin = parseFloat(params.get('place_lon_from')); + const lonMax = parseFloat(params.get('place_lon_to')); + const numLatSplits = 2; + const numLonSplits = 2; + const maxDepth = 10; // Максимальная глубина рекурсии (чтобы не бесконечно разбивать) + let allDealers = []; + const seenCodes = new Set(); + // Функция для задержки (чтобы не спамить API) + function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + // Рекурсивная функция для обработки области + async function processArea(latFrom, latTo, lonFrom, lonTo, depth = 0) { + if (depth > maxDepth) { + console.warn(`🚨 Максимальная глубина (${maxDepth}) достигнута для lat ${latFrom}-${latTo}, lon ${lonFrom}-${lonTo}. Пропускаем.`); + return; + } + const body = { + "section": "new", + "category": "cars", + "place_lat_from": latFrom.toFixed(6), + "place_lat_to": latTo.toFixed(6), + "place_lon_from": lonFrom.toFixed(6), + "place_lon_to": lonTo.toFixed(6), + "__dont_change_map": 1, + "geo_radius": 300, + "geo_id": [35], + "page": 1, + "page_size": 100 + }; + const areaDesc = `lat ${body.place_lat_from}-${body.place_lat_to}, lon ${body.place_lon_from}-${body.place_lon_to}`; + console.log(`\n${depth > 0 ? 'Рекурсия lvl ' + depth + ': ' : ''}Запрос для ${areaDesc}`); + try { + await delay(50); // Пауза 0.5 сек между запросами + const res = await fetch("https://auto.ru/-/ajax/desktop-search/dealersListing/", { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json", + "X-Csrf-Token": csrfToken, + "Accept": "application/json", + "Referer": "https://auto.ru/" + }, + body: JSON.stringify(body) + }); + if (!res.ok) { + console.warn(`Ошибка ${res.status} для ${areaDesc}`); + return; + } + const data = await res.json(); + if (data.totalResultsCount && data.totalResultsCount > 100) { + console.log(`⚠️ Total = ${data.totalResultsCount} > 100. Разбиваем на 4 под-области (глубина ${depth + 1}).`); + // Разбиваем на 2x2 + const latMid = (latFrom + latTo) / 2; + const lonMid = (lonFrom + lonTo) / 2; + await processArea(latFrom, latMid, lonFrom, lonMid, depth + 1); + await processArea(latFrom, latMid, lonMid, lonTo, depth + 1); + await processArea(latMid, latTo, lonFrom, lonMid, depth + 1); + await processArea(latMid, latTo, lonMid, lonTo, depth + 1); + return; // Не обрабатываем текущую область дальше, т.к. разбили + } + if (!data.dealers) return; + let newCount = 0; + for (const d of data.dealers) { + const code = d.dealerCode || d.code || d.id || d.dealerName; + if (code && !seenCodes.has(code)) { + seenCodes.add(code); + allDealers.push(d); + newCount++; + } + } + console.log(` +${data.dealers.length} дилеров (новых: ${newCount}, всего: ${allDealers.length})`); + console.log(` Total в области: ${data.totalResultsCount || 'неизвестно'}`); + } catch (e) { + console.error(`Ошибка для ${areaDesc}:`, e); + } + } + // Генерация начальных областей + const latStep = (latMax - latMin) / numLatSplits; + const lonStep = (lonMax - lonMin) / numLonSplits; + const subAreas = []; + for (let i = 0; i < numLatSplits; i++) { + const latFrom = latMin + i * latStep; + const latTo = (i === numLatSplits - 1 ? latMax : latMin + (i + 1) * latStep); + for (let j = 0; j < numLonSplits; j++) { + const lonFrom = lonMin + j * lonStep; + const lonTo = (j === numLonSplits - 1 ? lonMax : lonMin + (j + 1) * lonStep); + subAreas.push({ latFrom, latTo, lonFrom, lonTo }); + } + } + console.log(`Сгенерировано начальных областей: ${subAreas.length} (${numLatSplits}×${numLonSplits})`); + console.log(`Размер одного квадрата ≈ ${(latStep * 111).toFixed(1)} × ${((lonStep * 111) * Math.cos((latMin + latMax) / 2 * Math.PI / 180)).toFixed(1)} км`); + // Обработка всех начальных областей последовательно + for (let idx = 0; idx < subAreas.length; idx++) { + const { latFrom, latTo, lonFrom, lonTo } = subAreas[idx]; + await processArea(latFrom, latTo, lonFrom, lonTo); + } + console.log(`\n✅ Готово! Собрано уникальных дилеров: ${allDealers.length}`); + // Вывод всех дилеров в консоль в табличном виде + console.table(allDealers); + const codes = allDealers.map(d => d.dealerCode || d.code || d.id || d.dealerName || 'unknown'); + navigator.clipboard.writeText(codes.join('\n')).then(() => { + console.log("Коды успешно скопированы в буфер!"); + }).catch(err => { + console.error("Ошибка копирования:", err); + }); + // НОВАЯ ЧАСТЬ: Запрос телефонов для каждого dealerCode + console.log("\n📞 Запрашиваем телефоны для всех дилеров..."); + let allPhones = {}; // { code: [phones] } + let counter = 0; + for (const d of allDealers) { + counter++; + console.log(counter) + // if (counter > 10) continue; + + const code = d.dealerCode; // Используем dealerCode, если есть + if (!code) { + console.warn(`Пропуск: Нет dealerCode для ${d.dealerName || d.code || d.id}`); + continue; + } + console.log(`Запрос телефонов для ${code}...`); + try { + await delay(100); // Пауза между запросами + const r = await fetch("https://auto.ru/-/ajax/desktop-search/getSalonPhones/", { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json", + "X-Csrf-Token": csrfToken, + "Accept": "application/json", + "Referer": "https://auto.ru/" + }, + body: JSON.stringify({ + code: code, + category: "cars", + section: "all", + geo_radius: 300, + geo_id: [35] + }) + }); + console.log(`Статус для ${code}: ${r.status}`); + if (!r.ok) { + console.warn(`Ошибка ${r.status} для ${code}`); + continue; + } + const data = await r.json(); + console.log(`Полный ответ для ${code}:`, data); + const phones = data || []; + phones.map((v) => { + // phones: [{phone: '', ...}] + if (v.phone) { + v.phone = v.phone.replace(/\D/g, ''); // Оставляем только цифры + } + // add to allPhones + if (!allPhones[code]) { + allPhones[code] = []; + } + if (v.phone && !allPhones[code].includes(v.phone)) { + allPhones[code].push(v.phone); + } + }) + console.log(`Телефоны для ${code}:`, phones.length ? phones : "нет телефонов"); + } catch (e) { + console.error(`Ошибка для ${code}:`, e); + } + } + // Вывод всех телефонов в таблицу + console.log("\n📋 Все телефоны:"); + console.table(Object.entries(allPhones).map(([code, phones]) => ({ + code, + phones: phones.join(', ') || 'нет' + }))); + // Скопировать телефоны в буфер (code: phones) + const phonesText = Object.entries(allPhones).map(([code, phones]) => `${code}: ${phones.join(', ') || 'нет'}`).join('\n'); + navigator.clipboard.writeText(phonesText).then(() => { + console.log("Телефоны (code: phones) скопированы в буфер!"); + }).catch(err => { + console.error("Ошибка копирования телефонов:", err); + }); +})() + + + +Latitude - Longitude +45.430925 - 38.190931 + +Latitude - Longitude +44.372643 - 38.190931 + +Latitude - Longitude +44.372643 - 39.919681 + +Latitude - Longitude +45.430925 - 39.919681 diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..51ad6f1 --- /dev/null +++ b/readme.md @@ -0,0 +1,7 @@ +## Инструменты +... + +### Парсинг +- [collect_dealers_autoru](./parse/collect_dealers_autoru.js) + - Собирает номера автоматически через карту +