京东商品参数对比工具
// ==UserScript==
// @name 京东商品参数对比工具
// @namespace http://tampermonkey.net/
// @version 0.0.3
// @description 该脚本可用于对比不限数量的同类型商品(如:手机、笔记本)的详细参数
// @author Yihang Wang <wangyihanger@gmail.com>
// @match https://item.jd.com/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant GM_setValue
// @grant GM_getValue
// @license MIT
// ==/UserScript==
(function () {
'use strict';
var itemIDs = GM_getValue("jd-price-compare-item-ids", []);
function pollUntil(conditionFn, interval = 1000, maxAttempts = 10) {
return new Promise((resolve, reject) => {
let attempts = 0;
function checkCondition() {
if (conditionFn()) {
resolve();
} else if (attempts < maxAttempts) {
attempts++;
setTimeout(checkCondition, interval);
} else {
reject(new Error('Polling timed out'));
}
}
checkCondition();
});
}
function getItemID() {
return window.location.pathname.match(/(\d+)\.html/)[1];
}
function getPrice() {
const itemID = getItemID();
const targetSelector = `.price.J-p-${itemID}`;
const targetNode = document.querySelector(targetSelector);
return parseFloat(targetNode.innerText);
}
function getBasicInfo() {
const basicInfoElement = document.querySelector('#detail > div.tab-con > div:nth-child(1) > div.p-parameter');
const basicInfo = {};
basicInfoElement.querySelectorAll('li').forEach(dl => {
let text = dl.textContent.trim();
console.log(text);
if (text.indexOf(":") < 0) {
console.error(`invalid basic info: ${text}, colon is not present`);
return;
}
let items = text.split(":");
if (items.length != 2) {
console.error(`invalid basic info: ${text}, incorrect number of items`);
return;
}
const key = items[0]
const value = items[1]
basicInfo[key] = value;
});
return basicInfo;
}
function getMainInfo() {
const mainInfoElements = document.querySelectorAll('.Ptable-item');
const mainInfo = {};
mainInfoElements.forEach(item => {
const key = item.querySelector('h3').textContent.trim();
const values = {};
item.querySelectorAll('dl').forEach(dl => {
const detailKey = dl.querySelector('dt').textContent.trim();
const detailValue = dl.querySelector('dd').textContent.trim();
values[detailKey] = detailValue;
});
mainInfo[key] = values;
});
return mainInfo;
}
function getPackageList() {
const packageListElement = document.querySelector('.package-list p');
return packageListElement.textContent.trim();
}
function parseItem() {
pollUntil(() => (!isNaN(getPrice())));
let price = getPrice();
let basicInfo = getBasicInfo();
let mainInfo = getMainInfo();
let packageList = getPackageList();
let itemID = getItemID();
let data = JSON.stringify({
"商品编号": itemID,
"基本信息": basicInfo,
"主体信息": mainInfo,
"包装信息": packageList,
"价格": price,
})
return data;
}
function appendList(id) {
let endpoint = "https://jd-compare.authu.online/api/v1/item";
fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(parseItem())
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
console.log(response);
return response.json();
})
.then(data => {
console.log('Response:', data);
})
.catch(error => {
console.error('Error:', error);
});
let itemIdList = GM_getValue("jd-price-compare-item-ids", []);
console.log(itemIdList);
let itemIdSet = new Set(itemIdList)
itemIdSet.add(id);
GM_setValue("jd-price-compare-item-ids", Array.from(itemIdSet.values()));
}
function createList() {
let itemIdList = GM_getValue("jd-price-compare-item-ids", []);
let endpoint = `https://jd-compare.authu.online/api/v1/list`;
let listId = fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(itemIdList)
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.text();
})
.then(data => {
console.log("aaa"+data);
return compareList(data);
})
.catch(error => {
console.error('Error:', error);
});
return listId;
}
function compareList(listId) {
let endpoint = `https://jd-compare.authu.online/api/v1/list/${listId}/compare`;
console.log(endpoint);
let resultUrl = fetch(endpoint)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.text();
})
.then(data => {
window.open(data);
GM_setValue("jd-price-compare-item-ids", []);
})
.catch(error => {
console.error('Error:', error);
});
return resultUrl;
}
function addButton() {
var compareButton = document.createElement('a');
compareButton.href = '#';
compareButton.id = 'jd-price-compare-add-button';
compareButton.textContent = `加入对比清单 (${itemIDs.length})`;
compareButton.className = 'btn-special1 btn-lg';
compareButton.addEventListener("click", function (event) {
event.preventDefault();
appendList(getItemID());
let itemIDs = GM_getValue("jd-price-compare-item-ids", []);
compareButton.textContent = `加入对比清单 (${itemIDs.length})`;
});
var cartButtton = document.querySelector('#preview > div.preview-info > div.left-btns.shieldShopInfo');
cartButtton.appendChild(compareButton);
}
function compareButton() {
var compareButton = document.createElement('a');
compareButton.href = '#';
compareButton.id = 'jd-price-compare-start-button';
compareButton.textContent = '开始对比';
compareButton.className = 'btn-special1 btn-lg';
compareButton.addEventListener("click",function (event) {
event.preventDefault();
createList();
});
var cartButtton = document.querySelector('#preview > div.preview-info > div.left-btns.shieldShopInfo');
cartButtton.appendChild(compareButton);
}
function main() {
addButton();
compareButton();
}
window.addEventListener('load', main);
})();