feat: Add collect_promo_links
This commit is contained in:
parent
ff7421fad2
commit
fa033c8833
207
parse/collect_promo_links.js
Normal file
207
parse/collect_promo_links.js
Normal 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('⚠️ Промо ссылки не найдены');
|
||||
}
|
||||
})();
|
||||
})();
|
||||
Loading…
Reference in New Issue
Block a user