cart2excel

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

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==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.$)