Compare commits

...

2 Commits

Author SHA1 Message Date
93a512c980 chore: Update readme 2026-03-16 12:59:28 +03:00
fa033c8833 feat: Add collect_promo_links 2026-03-16 12:58:57 +03:00
2 changed files with 213 additions and 0 deletions

View File

@ -0,0 +1,207 @@
// ==UserScript==
// @name Yandex Promo Links Collector (Multi-Query Console Version)
// @namespace yandex.console.collector.promo.multi
// @version 1.2
// @description Собирает промо ссылки из выдачи Яндекса для нескольких запросов — версия для Tampermonkey (единый вывод)
// @match https://yandex.ru/search/*
// @match https://www.yandex.ru/search/*
// @match https://yandex.com/search/*
// @grant GM_xmlhttpRequest
// @connect yandex.ru
// @connect yandex.com
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
// === НАСТРОЙКИ ===
const QUERIES = [
'купить Great Wall в Краснодаре',
'купить BYD в Краснодаре',
'купить SAIC в Краснодаре',
'купить BAIC в Краснодаре',
'купить Lifan в Краснодаре',
'купить Zotye в Краснодаре',
'купить Brilliance в Краснодаре',
'купить Hongqi в Краснодаре',
'купить Tank в Краснодаре',
'купить Lynk & Co в Краснодаре',
'купить Zeekr в Краснодаре',
'купить Nio в Краснодаре',
'купить Xpeng в Краснодаре',
'купить Li Auto в Краснодаре',
'купить Seres в Краснодаре',
'купить Aion в Краснодаре',
'купить Forthing в Краснодаре',
'купить Dayun в Краснодаре',
'купить авто с пробегом в Краснодаре',
'купить б/у автомобиль в Краснодаре',
'подержанные машины в Краснодаре',
'автосалоны с пробегом в Краснодаре',
'купить подержанный авто в Краснодаре',
'б/у Haval в Краснодаре',
'б/у Chery в Краснодаре',
'б/у Geely в Краснодаре',
'б/у Changan в Краснодаре',
'б/у Exeed в Краснодаре',
'б/у Jetour в Краснодаре',
'б/у GAC в Краснодаре',
'б/у Jaecoo в Краснодаре',
'б/у FAW в Краснодаре',
'б/у DongFeng в Краснодаре',
'б/у JAC в Краснодаре',
'б/у Kaiyi в Краснодаре',
'б/у BAIC в Краснодаре',
'б/у Lifan в Краснодаре',
'б/у Hongqi в Краснодаре',
'б/у Tank в Краснодаре',
'б/у Nio в Краснодаре',
'б/у Xpeng в Краснодаре',
'автосалоны подержанных авто в Краснодаре',
'купить машину с пробегом от дилера в Краснодаре',
'trade-in авто в Краснодаре',
'обмен авто с пробегом в Краснодаре',
'сертифицированные б/у автомобили в Краснодаре'
];
const MAX_PAGES_PER_QUERY = 3;// Макс. страниц на запрос
const PAGE_DELAY_MS = 500;// Задержка между страницами
const QUERY_DELAY_MS = 1000;// Задержка между запросами (чтобы не блочить)
// =================
var allLinks = [];
var uniqueLinks = new Set();
var baseUrl = window.location.origin;
// === ФУНКЦИИ ===
function cleanUrl(url) {
try {
var urlObj = new URL(url);
urlObj.searchParams.delete('primary_reqid');
urlObj.searchParams.delete('rnd');
urlObj.searchParams.delete('reqid');
return urlObj.toString();
} catch (e) {
return url;
}
}
function processPage(doc, queryLinks) {
var nodes = doc.querySelectorAll('li.serp-item a[href]');
var pageLinks = [];
for (var i = 0; i < nodes.length; i++) {
var href = nodes[i].getAttribute('href');
if (href && href.startsWith('https://yabs.yandex.ru')) {
var fullUrl = href.startsWith('http') ? href : baseUrl + href;
var cleanedUrl = cleanUrl(fullUrl);
if (!uniqueLinks.has(cleanedUrl)) {
uniqueLinks.add(cleanedUrl);
pageLinks.push(cleanedUrl);
queryLinks.push(cleanedUrl);
}
}
}
return pageLinks.length;
}
function getNextPageUrl(doc) {
var nextBtn = doc.querySelector('a.Pager-Item_type_next');
if (!nextBtn) {
nextBtn = doc.querySelector('a[aria-label="Следующая страница"]');
}
if (nextBtn) {
var href = nextBtn.getAttribute('href');
if (href) {
return href.startsWith('http') ? href : baseUrl + href;
}
}
return null;
}
async function processQuery(query) {
var queryLinks = [];
var pagesProcessed = 0;
var searchUrl = `${baseUrl}/search/?text=${encodeURIComponent(query)}`;
try {
var html = await gmFetch(searchUrl);
var parser = new DOMParser();
var doc = parser.parseFromString(html, 'text/html');
processPage(doc, queryLinks);
pagesProcessed++;
var nextUrl = getNextPageUrl(doc);
while (nextUrl && pagesProcessed < MAX_PAGES_PER_QUERY) {
await new Promise(r => setTimeout(r, PAGE_DELAY_MS));
html = await gmFetch(nextUrl);
doc = parser.parseFromString(html, 'text/html');
processPage(doc, queryLinks);
pagesProcessed++;
nextUrl = getNextPageUrl(doc);
}
console.log(`[Запрос: "${query}"] Обработано страниц: ${pagesProcessed}, промо ссылок: ${queryLinks.length}`);
allLinks.push(queryLinks.join('\n'));
} catch (error) {
console.error(`❌ Ошибка для запроса "${query}":`, error);
}
return queryLinks.length;
}
// === TAMPERMONKEY-ОБЁРТКИ ===
function gmFetch(url) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'GET',
url: url,
headers: {
'User-Agent': navigator.userAgent,
'Referer': baseUrl
},
onload: (response) => {
if (response.status >= 200 && response.status < 300) {
resolve(response.responseText);
} else {
reject(new Error(`HTTP ${response.status}`));
}
},
onerror: (err) => reject(err),
ontimeout: (err) => reject(new Error('Timeout'))
});
});
}
function copyToClipboard(text) {
if (navigator.clipboard && window.isSecureContext) {
return navigator.clipboard.writeText(text);
}
return new Promise((resolve, reject) => {
try {
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
var success = document.execCommand('copy');
document.body.removeChild(textarea);
success ? resolve() : reject();
} catch (e) {
reject(e);
}
});
}
// === ЗАПУСК ===
console.log(`🚀 Запуск сбора промо ссылок для ${QUERIES.length} запросов (макс. страниц на запрос: ${MAX_PAGES_PER_QUERY})...`);
(async function run() {
var totalLinks = 0;
for (let i = 0; i < QUERIES.length; i++) {
if (i > 0) await new Promise(r => setTimeout(r, QUERY_DELAY_MS));
totalLinks += await processQuery(QUERIES[i]);
}
// === ФИНАЛЬНЫЙ ВЫВОД ===
console.log('\n' + '='.repeat(50));
console.log(`✅ СБОР ЗАВЕРШЁН`);
console.log(`📄 Запросов обработано: ${QUERIES.length}`);
console.log(`🔗 Промо ссылок собрано всего: ${totalLinks}`);
console.log('='.repeat(50) + '\n');
if (totalLinks > 0) {
var outputText = allLinks.join('\n');
console.log(outputText);
await copyToClipboard(outputText);
console.log('\n✅ Все промо ссылки (с разделителями по запросам) скопированы в буфер обмена!');
console.log('💡 Нажмите Ctrl+V в любом месте для вставки');
} else {
console.log('⚠️ Промо ссылки не найдены');
}
})();
})();

View File

@ -7,3 +7,9 @@
- Для работы укажите свой csrfToken и url - Для работы укажите свой csrfToken и url
- Так же, дополнительно, можно указать начальное деление на чанки (numLatSplits, numLonSplits) и максимальную глубину рекурсии (maxDepth) - Так же, дополнительно, можно указать начальное деление на чанки (numLatSplits, numLonSplits) и максимальную глубину рекурсии (maxDepth)
- [collect_promo_links](./parse/collect_promo_links.js)
- Собирает промо ссылки с поисковой выдачи яндекс
- Автоматически собирает с нескольких страниц автоматически переходя по ним. Для изменения количества обрабатываемых страниц изменить переменную (MAX_PAGES_PER_QUERY)
- Поддерживает переход по нескольким поисковым запросам указанным в (QUERIES)
- Эта версия для расширения Tampermonkey для удобной кнопки "Скопировать" после сбора
- Для запуска скрипта через Tampermonkey нужно разрешить выполнение пользовательских скриптов, путем включения режима разработчика <a href="browser://extensions/">browser://extensions/</a>