您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Compare product prices on Amazon.fr, Amazon.de, Amazon.es, and Amazon.it to find the best deal.
当前为
// ==UserScript== // @license MIT // @name European Price Checker for Amazon (fr, de, es, it) // @namespace http://tampermonkey.net/ // @version 1.5 // @description Compare product prices on Amazon.fr, Amazon.de, Amazon.es, and Amazon.it to find the best deal. // @author bNj // @match https://www.amazon.fr/* // @match https://www.amazon.de/* // @match https://www.amazon.es/* // @match https://www.amazon.it/* // @grant GM_xmlhttpRequest // @connect amazon.fr // @connect amazon.es // @connect amazon.it // @connect amazon.de // ==/UserScript== (function() { 'use strict'; const ASIN_REGEX = /\/([A-Z0-9]{10})(?:[/?]|$)/; const asinMatch = window.location.href.match(ASIN_REGEX); if (!asinMatch) { return; } const asin = asinMatch[1]; const amazonSites = [ { name: 'Amazon.fr', url: `https://www.amazon.fr/dp/${asin}`, domain: 'amazon.fr', flag: 'https://flagcdn.com/w20/fr.png' }, { name: 'Amazon.es', url: `https://www.amazon.es/dp/${asin}`, domain: 'amazon.es', flag: 'https://flagcdn.com/w20/es.png' }, { name: 'Amazon.it', url: `https://www.amazon.it/dp/${asin}`, domain: 'amazon.it', flag: 'https://flagcdn.com/w20/it.png' }, { name: 'Amazon.de', url: `https://www.amazon.de/dp/${asin}`, domain: 'amazon.de', flag: 'https://flagcdn.com/w20/de.png' } ]; let basePrice = null; const createLoadingContainer = () => { const priceElement = document.querySelector('.priceToPay, #priceblock_ourprice, #priceblock_dealprice'); if (priceElement) { const container = document.createElement('div'); container.id = 'amazonPriceComparisonContainer'; container.style.marginTop = '20px'; container.style.padding = '10px'; container.style.backgroundColor = '#f9f9f9'; container.style.border = '1px solid #ccc'; container.style.borderRadius = '8px'; container.style.position = 'relative'; container.innerHTML = `<div id="loadingMessage" style="text-align: center; font-weight: bold;">Checking other Amazon sites...</div>`; priceElement.parentNode.appendChild(container); basePrice = getPriceFromPage(priceElement.textContent); console.log(`Price found on Amazon.fr:`, basePrice); } }; const removeLoadingIndicator = () => { const loadingMessage = document.getElementById('loadingMessage'); if (loadingMessage) { loadingMessage.style.transition = 'opacity 1s'; loadingMessage.style.opacity = '0'; setTimeout(() => { if (loadingMessage.parentNode) { loadingMessage.parentNode.removeChild(loadingMessage); } displayAllResults(); }, 1000); } }; const getPriceFromPage = (priceText) => { priceText = priceText.replace(/\s+/g, ''); const priceMatch = priceText.match(/\d+[\.,]\d{2}/); if (priceMatch) { return parseFloat(priceMatch[0].replace(',', '.')); } return null; }; const getPriceFromResponse = (responseText) => { // Try to extract price from specific Amazon.de HTML structure const dePriceMatch = responseText.match(/<span class="a-price-whole">(\d+)<span class="a-price-decimal">[.,]<\/span><\/span><span class="a-price-fraction">(\d{2})<\/span>/); if (dePriceMatch) { return parseFloat(`${dePriceMatch[1]}.${dePriceMatch[2]}`); // Convert to numeric value } // Try to extract price from specific Amazon.it HTML structure const itPriceMatch = responseText.match(/<span class="a-price aok-align-center reinventPricePriceToPayMargin priceToPay"[^>]*>.*?<span class="a-price-whole">(\d+)<span class="a-price-decimal">(.)<\/span><\/span><span class="a-price-fraction">(\d{2})<\/span>/); if (itPriceMatch) { return parseFloat(`${itPriceMatch[1]}.${itPriceMatch[3]}`); // Convert to numeric value } return null; }; const getDeliveryPriceFromResponse = (responseText) => { const deliveryMatch = responseText.match(/data-csa-c-delivery-price="[^"]*(\d+[\.,]\d{2})/); if (deliveryMatch) { return parseFloat(deliveryMatch[1].replace(',', '.')); } return null; }; const addPriceToPage = (siteName, price, deliveryPrice, url, flag, percentageDifference, totalPercentageDifference) => { const priceContainer = document.querySelector('#amazonPriceComparisonContainer'); if (!priceContainer) { return; } const row = document.createElement('div'); row.className = 'comparison-row'; row.style.cursor = 'pointer'; row.onmouseover = () => row.style.backgroundColor = '#f1f1f1'; row.onmouseout = () => row.style.backgroundColor = 'inherit'; row.onclick = () => window.open(url, '_blank'); row.style.display = 'flex'; row.style.justifyContent = 'space-between'; row.style.padding = '5px 0'; row.style.borderBottom = '1px solid #ccc'; const flagCell = document.createElement('div'); flagCell.style.flex = '1'; flagCell.innerHTML = `<img src="${flag}" alt="${siteName} flag" style="vertical-align: middle; margin-right: 5px;"> ${siteName}`; const priceCell = document.createElement('div'); priceCell.style.flex = '1'; priceCell.style.textAlign = 'center'; priceCell.innerHTML = `€${price.toFixed(2)}`; const percentagePriceCell = document.createElement('div'); percentagePriceCell.style.flex = '1'; percentagePriceCell.style.textAlign = 'center'; const priceColor = percentageDifference > 0 ? 'red' : 'green'; percentagePriceCell.innerHTML = percentageDifference !== null ? `<span style="color: ${priceColor};">${percentageDifference > 0 ? '+' : ''}${percentageDifference.toFixed(2)}% (Δ€${(price - basePrice).toFixed(2)})</span>` : '-'; const deliveryCell = document.createElement('div'); deliveryCell.style.flex = '1'; deliveryCell.style.textAlign = 'center'; deliveryCell.innerHTML = deliveryPrice !== null ? `<img src="https://img.icons8.com/?size=100&id=12248&format=png&color=000000" width="20"/> €${deliveryPrice.toFixed(2)}` : '-'; const totalPrice = price + (deliveryPrice || 0); const totalCell = document.createElement('div'); totalCell.style.flex = '1'; totalCell.style.textAlign = 'center'; totalCell.innerHTML = `<strong>€${totalPrice.toFixed(2)}</strong>`; const percentageCell = document.createElement('div'); percentageCell.style.flex = '1'; percentageCell.style.textAlign = 'center'; const totalColor = totalPercentageDifference > 0 ? 'red' : 'green'; percentageCell.innerHTML = totalPercentageDifference !== null ? `<span style="color: ${totalColor};">${totalPercentageDifference > 0 ? '+' : ''}${totalPercentageDifference.toFixed(2)}% (Δ€${(totalPrice - basePrice).toFixed(2)})</span>` : '-'; row.appendChild(flagCell); row.appendChild(priceCell); row.appendChild(percentagePriceCell); row.appendChild(deliveryCell); row.appendChild(totalCell); row.appendChild(percentageCell); priceContainer.appendChild(row); }; let priceResults = []; const storePriceResult = (siteName, price, deliveryPrice, url, flag) => { if (price !== null) { priceResults.push({ siteName, price, deliveryPrice, url, flag }); } }; const displayAllResults = () => { const priceContainer = document.querySelector('#amazonPriceComparisonContainer'); if (!priceContainer) { return; } priceContainer.innerHTML = ''; // Clear loading message and icon const headerRow = document.createElement('div'); headerRow.className = 'comparison-row header-row'; headerRow.style.display = 'flex'; headerRow.style.justifyContent = 'space-between'; headerRow.style.padding = '5px 0'; headerRow.style.borderBottom = '2px solid #000'; headerRow.style.fontWeight = 'bold'; ['Site', 'Price', 'Difference (Price %)', 'Delivery', 'Total', 'Difference (Total %)'].forEach(header => { const headerCell = document.createElement('div'); headerCell.style.flex = '1'; headerCell.style.textAlign = 'center'; headerCell.textContent = header; headerRow.appendChild(headerCell); }); priceContainer.appendChild(headerRow); if (priceResults.length > 0 && basePrice !== null) { priceResults.forEach(result => { const percentageDifference = ((result.price - basePrice) / basePrice) * 100; const totalPrice = result.price + (result.deliveryPrice || 0); const totalBasePrice = basePrice; // Assuming no delivery cost for Amazon.fr for simplicity const totalPercentageDifference = ((totalPrice - totalBasePrice) / totalBasePrice) * 100; addPriceToPage(result.siteName, result.price, result.deliveryPrice, result.url, result.flag, percentageDifference, totalPercentageDifference); }); // Add footer with script info after the last row const footer = document.createElement('div'); footer.style.textAlign = 'right'; footer.style.fontSize = '0.8em'; footer.style.color = '#666'; footer.style.marginTop = '10px'; footer.textContent = `European Price Checker for Amazon by bNj v${GM_info.script.version}`; priceContainer.appendChild(footer); } else { priceContainer.innerHTML = '<div style="text-align: center;">No prices available</div>'; } }; createLoadingContainer(); let sitesChecked = 0; amazonSites.forEach(site => { GM_xmlhttpRequest({ method: 'GET', url: site.url, headers: { 'User-Agent': 'Mozilla/5.0', 'Accept-Language': 'en-US,en;q=0.5' }, onload: function(response) { console.log(`Response from ${site.name}:`, response); if (response.status === 200) { const price = getPriceFromResponse(response.responseText); const deliveryPrice = getDeliveryPriceFromResponse(response.responseText); console.log(`Price found on ${site.name}:`, price); console.log(`Delivery price found on ${site.name}:`, deliveryPrice); storePriceResult(site.name, price, deliveryPrice, site.url, site.flag); } else { console.error(`Failed to fetch price from ${site.name}, status:`, response.status); storePriceResult(site.name, null, null, site.url, site.flag); } sitesChecked++; if (sitesChecked === amazonSites.length) { removeLoadingIndicator(); } }, onerror: function(error) { console.error(`Error fetching price from ${site.name}:`, error); storePriceResult(site.name, null, null, site.url, site.flag); sitesChecked++; if (sitesChecked === amazonSites.length) { removeLoadingIndicator(); } } }); }); })();