initial commit
This commit is contained in:
commit
8e7903dc34
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@ -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/
|
||||||
200
parse/collect_dealers_autoru.js
Normal file
200
parse/collect_dealers_autoru.js
Normal file
@ -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
|
||||||
Loading…
Reference in New Issue
Block a user