2026-03-16 11:28:40 +03:00
( 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 ) ;
} ) ;
2026-03-16 11:30:50 +03:00
} ) ( )