淘宝、京东、天猫自动按每斤价格排序 TAOBAO/JD/TMALL / Automatic sort by 500g price.

自用。有疑问联系 [email protected] 已知bug:淘宝的价格和商品标题上写的重量通常对不上,此bug无法修复,天猫、京东暂无此问题, 标题出现2个以上重量单位的按最后一个算

目前为 2019-11-05 提交的版本。查看 最新版本

// ==UserScript==
// @name         淘宝、京东、天猫自动按每斤价格排序 TAOBAO/JD/TMALL / Automatic sort by 500g price.
// @namespace    [email protected]
// @version      0.5
// @description  自用。有疑问联系 [email protected]   已知bug:淘宝的价格和商品标题上写的重量通常对不上,此bug无法修复,天猫、京东暂无此问题, 标题出现2个以上重量单位的按最后一个算
// @author       [email protected]
// @match        http*://cart.jd.com/cart*
// @match        http*://cart.jd.com/addToCart.html*
// @match        http*://order.jd.com/center/alwaysbuy.action*
// @match        http*://www.jd.com/*.html
// @match        http*://item.jd.com/*.html
// @match        http*://search.jd.com/Search*
// @match        http*://list.tmall.com/search_product.htm*
// @match        http*://s.taobao.com/search*
// @match        http*://cart.taobao.com/cart.htm*
// @grant        none
// ==/UserScript==


// update from https://gist.githubusercontent.com/snomiao/946b66ac79c6ef20991018112580c881/raw/bdc1643028a3eda73ad6fae0134346b59a35be6c/pricesof500g.userscript.js
(function() {
    'use strict';

// 获取质量参数
// 前缀乘数 基数量 基数单位 后缀乘数

var 求千克价格 = ({ title, price }) => {
    var units = {
        // 重量、容积单位(按水的重量算)
        kg: 1000, 千克: 1000, l: 1000, 公斤: 1000,
        g: 1, 克: 1, ml: 1,
        磅: 453.59237, lb: 453.59237,
        斤: 500, 两: 50,
        mg: 0.001, ug: 0.000001,
        // 数据单位
        pb: 1000000,
        t: 1000, tb: 1000,
        mb: 0.001,
        kb: 0.000001,
    }
    var reg1 = /(?:(\d+)\*)?(\d+\.\d+|\d+)(kg|g|mg|ug|L|ml|千克|克|斤|两|公斤|升|毫升|pb|tb|mb|kb|t)(?:\*(\d+))?/i
    var reg2 = /(?:(\d+)\*)?(\d+\.\d+|\d+)(kg|g|mg|ug|L|ml|千克|克|斤|两|公斤|升|毫升|pb|tb|mb|kb|t)\b(?:\*(\d+))?/ig
    var matches = title.match(reg2)
    if (matches) {
        var match = matches.pop().match(reg1)
        console.log(title, match)
        var mul = parseFloat(match[4] || match[1]) || 1
        var val = parseFloat(match[2])
        var unit = match[3].toLowerCase()
        var unitMul = units[unit]
        if (unitMul) {
            return price / (mul * val * unitMul / 1000)
        } else {
            console.log(match)
            return Infinity
        }
    }
    return Infinity
}

//
var 解释性价比 = (千克价格) => 千克价格 < Infinity ? parseInt(千克价格 / 2 * 100) / 100 + "¥/500g" : ""
var 映射 = (x, a, b, c, d) => (x - a) / (b - a) * (d - c) + c


var getListItems = ({ selItem, selTitle, selPrice }) => [...document.querySelectorAll(selItem)]
    .map(
        e => {
            var eTitle = e.querySelector(selTitle)
            var ePrice = e.querySelector(selPrice)
            return eTitle && ePrice &&
                {
                    eTitle, eTitle, ePrice,
                    title: eTitle.innerText.trim(),
                    price: parseFloat(ePrice.innerText.trim().replace(/¥|¥/g, "")),
                    e
                }
        }
    ).filter(e => e)
var 按性价比排序 = () => {
    var lsItems = []
    // taobao购物车
    .concat(getListItems({ selItem: ".item-holder,.bundle,#J_OrderList>div", selPrice: ".td.td-price", selTitle: ".item-basic-info a" }))
    // taobao
    .concat(getListItems({ selItem: ".item", selTitle: ".title a", selPrice: ".price" }))
    // TMALL
    .concat(getListItems({ selItem: ".product", selPrice: ".productPrice", selTitle: ".productTitle a" }))
    // JD
    .concat(getListItems({ selItem: ".itemInfo-wrap", selTitle: ".sku-name", selPrice: ".p-price" })) // 当前浏览商品
    .concat(getListItems({ selItem: "ul.more2_list>li.more2_item", selTitle: ".more2_info_name", selPrice: ".more2_info_price" })) // 首页推荐
    .concat(getListItems({ selItem: ".freqt-items>.freqt-item", selTitle: ".p-name a", selPrice: ".p-price" })) // 常购商品
    .concat(getListItems({ selItem: ".gl-item", selTitle: ".p-name em", selPrice: ".p-price" }))
    .concat(getListItems({ selItem: ".track-con>ul>li", selTitle: "a>div", selPrice: "a>p" }))   //看了又看
    .concat(getListItems({ selItem: "ul.plist>li", selTitle: ".p-name", selPrice: ".p-price" })) //店铺新品、店铺热销、店长推荐等    
    .concat(getListItems({ selItem: "ul>li.item", selTitle: ".p-name", selPrice: ".p-price" }))    // 本店好评
    // JD购物车
    .concat(getListItems({ selItem: ".goods-list>ul>li", selTitle: ".p-name a", selPrice: ".p-price" }))
    .concat(getListItems({ selItem: ".item-item,.item-full", selTitle: ".p-name a", selPrice: ".p-price" }))
    .concat(getListItems({ selItem: ".smart-items>ul>li", selTitle: ".item-name a", selPrice: ".item-price" }))
    var lsItems = lsItems.map(e => ({ ...e, 千克价格: 求千克价格(e) }))
        .sort((a, b) => a.千克价格 - b.千克价格)
        .map(e => { e.e.parentNode.appendChild(e.e.parentNode.removeChild(e.e)); return e })

    var 最低价 = Math.min(...lsItems.map(e => e.千克价格).filter(e => e < Infinity))
    var 最高价 = Math.max(...lsItems.map(e => e.千克价格).filter(e => e < Infinity))

    lsItems.forEach(
        e => {
            var percent = 映射(e.千克价格, 最低价, 最高价, 1, 0)
            var span = document.createElement("span")
            span.className = "priceof500g"
            // 红绿渐变,红的最低价
            span.style.backgroundColor = `rgba(${percent * 255},${255 - percent * 255},0,1)`
            span.style.color = "rgba(255,255,255,1)"
            console.log(解释性价比(e.千克价格))
            span.innerText = 解释性价比(e.千克价格);
            // 移除上一次运行结果
            [...e.eTitle.parentNode.querySelectorAll(".priceof500g")].map(child=>e.eTitle.parentNode.removeChild(child))
            // 新结果
            e.eTitle.parentNode.insertBefore(span, e.eTitle)
        })
}

document.addEventListener("onload", 按性价比排序)
setInterval(按性价比排序, 5000)
setTimeout(按性价比排序, 2000)
按性价比排序()






})();