cart2excel

导出淘宝/天猫购物车到excel

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         cart2excel
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  导出淘宝/天猫购物车到excel
// @author       yxf
// @grant        none
// @license      MIT
// @include      *://cart.taobao.com/*
// @require      https://code.jquery.com/jquery-3.5.1.min.js
// @require      https://unpkg.com/[email protected]/FileSaver.js
// @require      https://unpkg.com/[email protected]/Blob.js
// @require      https://unpkg.com/xlsx/dist/shim.min.js
// @require      https://unpkg.com/xlsx/dist/xlsx.full.min.js
// @run-at document-body
// ==/UserScript==

(function ($) {
  'use strict'

  // Your code here...

  // const scripts = [
  //   '//unpkg.com/[email protected]/FileSaver.js',
  //   '//unpkg.com/[email protected]/Blob.js',
  //   '//unpkg.com/xlsx/dist/shim.min.js',
  //   '//unpkg.com/xlsx/dist/xlsx.full.min.js'
  // ]

  // const promises = scripts.map(item => loadScript(item))
  // Promise.all(promises).then(res => {
  //   createBtn()
  // })
  createBtn()
  function createBtn (src) {
    if (!document.querySelector('#downloadBtn')) {
      const btn = document.createElement('button')
      btn.id = 'downloadBtn'
      btn.onclick = handleDownload
      btn.style.cssText = `
      position:fixed;
      top:40px;
      right:0;
      z-index:999;     
      display: inline-block;
    padding: 10px 16px;
    color:white;
    cursor: pointer;
    border: none;
    text-decoration: none;
    background: #ea4c89;
    -webkit-transition: all 200ms ease;
    transition: all 200ms ease;
    border-radius: 8px;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    outline: none;
    font-family: 'Haas Grot Text R Web', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    height: 40px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    text-align: center;
      `

      btn.innerText = 'export Excel'

      document.body.appendChild(btn)
    }
  }

  function handleDownload () {
    crawl().then(list => {
      const tHeader = ['图片', '标题', '规格', '原价', '现价', '数量', '总价', '失效状态']
      const filterVal = ['img', 'title', 'info', 'priceOriginal', 'priceNow', 'amount', 'sum', 'valid']
      const data = formatJson(filterVal, list)
      export_json_to_excel({
        header: tHeader, // 表头 必填
        data, // 具体数据 必填
        filename: 'cart', // 非必填
        autoWidth: true, // 非必填
        bookType: 'xlsx' // 非必填
      })
    })
  }

  function crawl () {
    return new Promise((resolve, reject) => {
      const $productList = $('.J_ItemBody')

      const list = []
      $productList.each((index, item) => {
        const obj = {}
        obj.img = $(item).find('.itempic.J_ItemImg').attr('src')
        obj.title = $(item).find('.item-basic-info').text() // 标题
        obj.info = $(item).find('.item-props').text() // 规格信息
        obj.priceOriginal = $(item).find('.price-original').text() // 原价
        obj.priceNow = $(item).find('.J_Price.price-now').text() // 现价
        obj.amount = $(item).find('input.J_ItemAmount').length ? $(item).find('input.J_ItemAmount').val() : $(item).find('.item-amount ').text() // 数量
        obj.sum = $(item).find('.J_ItemSum.number').text()
        obj.valid = $(item).find('.td-inner .label-invalid').length ? '失效' : ''
        list.push(obj)
      })
      resolve(list)
    })
  }
  function sheet_from_array_of_arrays (data, opts) {
    var ws = {}
    var range = {
      s: {
        c: 10000000,
        r: 10000000
      },
      e: {
        c: 0,
        r: 0
      }
    }
    for (var R = 0; R != data.length; ++R) {
      for (var C = 0; C != data[R].length; ++C) {
        if (range.s.r > R) range.s.r = R
        if (range.s.c > C) range.s.c = C
        if (range.e.r < R) range.e.r = R
        if (range.e.c < C) range.e.c = C
        var cell = {
          v: data[R][C]
        }
        if (cell.v == null) continue
        var cell_ref = XLSX.utils.encode_cell({
          c: C,
          r: R
        })

        if (typeof cell.v === 'number') cell.t = 'n'
        else if (typeof cell.v === 'boolean') cell.t = 'b'
        else if (cell.v instanceof Date) {
          cell.t = 'n'
          cell.z = XLSX.SSF._table[14]
          cell.v = datenum(cell.v)
        } else cell.t = 's'

        ws[cell_ref] = cell
      }
    }
    if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range)
    return ws
  }

  function Workbook () {
    if (!(this instanceof Workbook)) return new Workbook()
    this.SheetNames = []
    this.Sheets = {}
  }
  function s2ab (s) {
    var buf = new ArrayBuffer(s.length)
    var view = new Uint8Array(buf)
    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
    return buf
  }

  function datenum (v, date1904) {
    if (date1904) v += 1462
    var epoch = Date.parse(v)
    return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
  }

  function export_json_to_excel ({
    multiHeader = [],
    header,
    data,
    filename,
    merges = [],
    autoWidth = true,
    bookType = 'xlsx'
  } = {}) {
  /* original data */
    filename = filename || 'excel-list'
    data = [...data]
    data.unshift(header)

    for (let i = multiHeader.length - 1; i > -1; i--) {
      data.unshift(multiHeader[i])
    }

    var ws_name = 'SheetJS'
    var wb = new Workbook()
    var ws = sheet_from_array_of_arrays(data)

    if (merges.length > 0) {
      if (!ws['!merges']) ws['!merges'] = []
      merges.forEach(item => {
        ws['!merges'].push(XLSX.utils.decode_range(item))
      })
    }

    if (autoWidth) {
    /* 设置worksheet每列的最大宽度 */
      const colWidth = data.map(row => row.map(val => {
      /* 先判断是否为null/undefined */
        if (val == null) {
          return {
            wch: 10
          }
        }
        /* 再判断是否为中文 */
        else if (val.toString().charCodeAt(0) > 255) {
          return {
            wch: val.toString().length * 2
          }
        } else {
          return {
            wch: val.toString().length
          }
        }
      }))
      /* 以第一行为初始值 */
      const result = colWidth[0]
      for (let i = 1; i < colWidth.length; i++) {
        for (let j = 0; j < colWidth[i].length; j++) {
          if (result[j].wch < colWidth[i][j].wch) {
            result[j].wch = colWidth[i][j].wch
          }
        }
      }
      ws['!cols'] = result
    }

    /* add worksheet to workbook */
    wb.SheetNames.push(ws_name)
    wb.Sheets[ws_name] = ws

    var wbout = XLSX.write(wb, {
      bookType: bookType,
      bookSST: false,
      type: 'binary'
    })
    saveAs(new Blob([s2ab(wbout)], {
      type: 'application/octet-stream'
    }), `${filename}.${bookType}`)
  }

  function formatJson (filterVal, jsonData) {
    return jsonData.map(v => filterVal.map(j => {
      if (j === 'timestamp') {
        return parseTime(v[j])
      } else {
        return v[j]
      }
    }))
  }

  function loadScript (src) {
    return new Promise((resolve, reject) => {
      const existingScript = document.getElementById(src)
      if (!existingScript) {
        const script = document.createElement('script')
        script.id = src
        script.src = src

        document.body.appendChild(script)
        script.onload = function () {
          this.onerror = this.onload = null
          resolve()
        }
      }
    })
  }
})(window.$)