utils/parse/collect_promo_links.js

229 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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