207 lines
9.3 KiB
JavaScript
207 lines
9.3 KiB
JavaScript
|
|
// ==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('⚠️ Промо ссылки не найдены');
|
|||
|
|
}
|
|||
|
|
})();
|
|||
|
|
})();
|