229 lines
10 KiB
JavaScript
229 lines
10 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 = [
|
||
|
||
'купить Belgee в Нижнем Новгороде',
|
||
'купить бу Belgee в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Belgee ',
|
||
'купить в Нижнем Новгороде Belgee ',
|
||
|
||
'купить Haval в Нижнем Новгороде',
|
||
'купить бу Haval в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Haval ',
|
||
'купить в Нижнем Новгороде Haval ',
|
||
|
||
'купить Chery в Нижнем Новгороде',
|
||
'купить бу Chery в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Chery ',
|
||
'купить в Нижнем Новгороде Chery ',
|
||
|
||
'купить Geely в Нижнем Новгороде',
|
||
'купить бу Geely в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Geely ',
|
||
'купить в Нижнем Новгороде Geely ',
|
||
|
||
'купить Changan в Нижнем Новгороде',
|
||
'купить бу Changan в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Changan ',
|
||
'купить в Нижнем Новгороде Changan ',
|
||
|
||
'купить Exeed в Нижнем Новгороде',
|
||
'купить бу Exeed в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Exeed ',
|
||
'купить в Нижнем Новгороде Exeed ',
|
||
|
||
'купить Omoda в Нижнем Новгороде',
|
||
'купить бу Omoda в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Omoda ',
|
||
'купить в Нижнем Новгороде Omoda ',
|
||
|
||
'купить Jaecoo в Нижнем Новгороде',
|
||
'купить бу Jaecoo в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Jaecoo ',
|
||
'купить в Нижнем Новгороде Jaecoo ',
|
||
|
||
'купить Tank в Нижнем Новгороде',
|
||
'купить бу Tank в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Tank ',
|
||
'купить в Нижнем Новгороде Tank ',
|
||
|
||
'купить Jetour в Нижнем Новгороде',
|
||
'купить бу Jetour в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Jetour ',
|
||
'купить в Нижнем Новгороде Jetour ',
|
||
|
||
'купить Forthing в Нижнем Новгороде',
|
||
'купить бу Forthing в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Forthing ',
|
||
'купить в Нижнем Новгороде Forthing ',
|
||
|
||
'купить BAIC в Нижнем Новгороде',
|
||
'купить бу BAIC в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу BAIC ',
|
||
'купить в Нижнем Новгороде BAIC ',
|
||
|
||
'купить Dongfeng в Нижнем Новгороде',
|
||
'купить бу Dongfeng в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Dongfeng ',
|
||
'купить в Нижнем Новгороде Dongfeng ',
|
||
|
||
'купить Hongqi в Нижнем Новгороде',
|
||
'купить бу Hongqi в Нижнем Новгороде',
|
||
'купить в Нижнем Новгороде бу Hongqi ',
|
||
'купить в Нижнем Новгороде Hongqi ',
|
||
];
|
||
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;
|
||
}
|
||
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('⚠️ Промо ссылки не найдены');
|
||
}
|
||
})();
|
||
})(); |