(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