天巡历史价格记录

比较现在和上次记录的价格

// ==UserScript==
// @name         天巡历史价格记录
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  比较现在和上次记录的价格
// @author       你的名字
// @match        https://www.tianxun.com/transport/flights/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 等待页面加载完成
    function waitForElement(selector, callback) {
        console.log('等待页面中出现' + selector + '元素');
        const el = document.querySelector(selector);
        if (el) {
            callback(el);
        } else {
            setTimeout(() => waitForElement(selector, callback), 500);
        }
    }

    // 等待页面中出现"条结果"文本
    function waitForText(text, callback) {
        console.log('等待页面中出现"条结果"文本');
        const el = Array.from(document.querySelectorAll('body *')).find(e => e.textContent.includes(text));
        if (el) {
            callback(el);
        } else {
            setTimeout(() => waitForText(text, callback), 1000);
        }
    }

    waitForText('条结果', () => {
        waitForElement('[class^="FlightsResults_dayViewItems__"]', (container) => {

            // 获取当前搜索结果的日期
            const dateInput = document.getElementById('outbound_date');
            const searchDate = dateInput ? dateInput.value : '';

            // 添加一个key,从<div class="SearchDetails_location__NDZmN">下的文本获取
            const searchLocation = document.querySelector('.SearchDetails_location__NDZmN')?.textContent.trim();

            // 获取所有子div
            const divs = Array.from(container.children);
            if (divs.length <= 1) return;

            // 排除第一个div .slice(1) 有时候不能排除第一个
            divs.forEach(div => {
                debugger
                // 获取航司名
                const airlineSpan = div.querySelector('[class^="LogoImage_label__"]'); // 如果选择不到就得到null
                const airline = airlineSpan ? airlineSpan.textContent.trim() : '';

                // 获取出发和到达时间
                const departDiv = div.querySelector('[class^="LegInfo_routePartialDepart__"]');
                const departTime = departDiv ? departDiv.textContent.trim() : '';

                // 获取到达时间
                const arriveDiv = div.querySelector('[class^="LegInfo_routePartialArrive__"]');
                const arriveTime = arriveDiv ? arriveDiv.textContent.trim() : '';

                // 获取价格
                const priceDiv = div.querySelector('[class^="Price_mainPriceContainer__"]');
                const price = priceDiv ? priceDiv.textContent.trim() : '';

                if (airline && departTime && price && searchDate) {
                    const key = `${airline}_${departTime}__${arriveTime}_${searchLocation}_${searchDate}`;

                    // 这里添加代码
                    let record = GM_getValue(key, null);
                    let lastPrice = null;
                    let minPrices = [];
                    if (record) {
                        try {
                            record = JSON.parse(record);
                            lastPrice = record.lastPrice;
                            minPrices = Array.isArray(record.minPrices) ? record.minPrices : (record.minPrice ? [record.minPrice] : []);
                        } catch (e) {
                            lastPrice = record;
                            minPrices = [record];
                        }
                    }
                    const infoSpan = document.createElement('span');
                    infoSpan.style.marginLeft = '10px';
                    infoSpan.style.color = '#f60';
                    if (lastPrice !== null) {
                        if (lastPrice === price) {
                            infoSpan.textContent = '没有变化';
                        } else {
                            infoSpan.textContent = `上次价格:${lastPrice}`;
                        }
                        if (minPrices.length > 0) {
                            infoSpan.textContent += ` / 历史价格:${minPrices.join('、')}`;
                        }
                        div.appendChild(infoSpan);
                        // 更新lastPrice和minPrices
                        // 只保留最多7个最低价,升序 修改,不只保留最低价了,只有最低价不好看这个价格变化的趋势
                        debugger
                        let allPrices = minPrices.concat([price]);

                        // allPrices = Array.from(new Set(allPrices.map(p => p.replace(/[^\d.]/g, '')))); // 去重,仅保留数字部分
                        // allPrices = allPrices.map(Number).filter(n => !isNaN(n)).sort((a, b) => a - b).slice(0, 7);
                            
                        // 还原为带货币符号的字符串(用当前price的格式)
                        // const formatPrice = n => price.replace(/([\d.]+)/, n);

                        // 去重,仅保留数字部分
                        allPrices = Array.from(new Set(allPrices.map(p => p.replace(/[^\d.]/g, ''))));
                        allPrices = allPrices.map(Number).filter(n => !isNaN(n));
                        // 还原为字符串
                        const formatPrice = n => n.toString();
                        const minPricesStr = allPrices.slice(-15).map(formatPrice);
                        GM_setValue(key, JSON.stringify({ lastPrice: price, minPrices: minPricesStr }));
                    } else {
                        // 首次保存
                        GM_setValue(key, JSON.stringify({ lastPrice: price, minPrices: [price] }));
                        console.log(`已保存: ${key} => ${price}`);
                    }
                }
            });
        });
    });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址