From 07605e737db6a2944e70f4b8b3842ab4ae7b880b Mon Sep 17 00:00:00 2001 From: Hykilpikonna Date: Thu, 11 Aug 2022 12:41:18 -0400 Subject: [PATCH] [+] Taobao crawler script --- taobao-bought-items.js | 178 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 taobao-bought-items.js diff --git a/taobao-bought-items.js b/taobao-bought-items.js new file mode 100644 index 0000000..0d21304 --- /dev/null +++ b/taobao-bought-items.js @@ -0,0 +1,178 @@ +// ==UserScript== +// @name Taobao Superbuy Interface +// @namespace http://tampermonkey.net/ +// @version 1.0 +// @description Crawl taobao bought-items data +// @author Hykilpikonna +// @match https://buyertrade.taobao.com/trade/itemlist/list_bought_items.htm* +// @icon https://www.google.com/s2/favicons?sz=64&domain=taobao.com +// @grant none +// ==/UserScript== + +(async function() { + 'use strict'; + + const GBK = new TextDecoder('GBK') + + /** + * Get taobao bought item links + * + * @returns {{id: string, date: string, store: {name: string, url: string}, items: + * {name: string, url: string, sel?: string[][], promises?: string[], price: string, origPrice?: string, + * qty: string}[]}[]} + */ + async function getTaobaoLinks() + { + let orders = [...document.querySelectorAll('.bought-wrapper-mod__trade-order___2lrzV')] + // orders = [orders[0]] + + return await Promise.all(orders.map(async o => + { + const order = {} + order.id = o.getAttribute('data-id') + + // Header info + const elHeader = o.querySelector('.bought-wrapper-mod__head___2vnqo').querySelectorAll('td') + order.date = elHeader[0].firstChild.textContent + const elStore = elHeader[1].firstElementChild.querySelector('a') + order.store = {name: elStore.innerHTML, url: elStore.getAttribute('href')} + + // Items info + const elItems = [...o.querySelector('tbody:not(.bought-wrapper-mod__head___2vnqo)').children] + order.items = elItems.map(i => + { + const elChildren = i.children + const item = {} + + // Item name block + const elName = [...elChildren[0].firstChild.children[1].children] + elName.forEach(c => + { + const reactid = c.getAttribute('data-reactid') + + // Name & URL block + if (reactid.endsWith('.0')) + { + item.name = c.firstChild.textContent.trim() + + // Filter link, remove tracking parameters + const url = new URL('https:' + c.firstElementChild.getAttribute('href')) + for (let key of url.searchParams.keys()) + if (key !== 'id') url.searchParams.delete(key) + + item.url = url.toString() + } + + // Selection block + if (reactid.endsWith('.1')) + item.sel = [...c.children].map(it => [it.firstChild.innerHTML, it.lastChild.innerHTML]) + + // Promises block + if (reactid.endsWith('.2')) + item.promises = [...c.children].map(it => it.getAttribute('title')) + }) + + // Ignore insurance + if (item.name === '保险服务') return null + + // Price block + const elPrice = elChildren[1].firstChild + item.price = elPrice.lastChild.textContent + if (elPrice.children.length === 2) + item.origPrice = elPrice.firstChild.textContent + + // Quantity block + item.qty = elChildren[2].textContent + + return item + }).filter(i => i) + + // Total price + const elI0 = elItems[0].children + const elTotalPrice = elI0[4].firstChild + order.priceTotal = elTotalPrice.firstChild.textContent + order.priceDelivery = elTotalPrice.children[1].children[1].textContent + + // Status block + const elStatus = elI0[5].firstChild + order.status = elStatus.firstChild.textContent + + // Get delivery status + const req = await fetch(`https://buyertrade.taobao.com/trade/json/transit_step.do?bizOrderId=${order.id}`) + order.delivery = JSON.parse(GBK.decode(await req.arrayBuffer())) + + return order + })); + } + + /** + * Add CSS https://stackoverflow.com/a/33176845/7346633 + */ + function GM_addStyle(css) { + const style = document.getElementById("GM_addStyleBy8626") || (function() { + const style = document.createElement('style'); + style.type = 'text/css'; + style.id = "GM_addStyleBy8626"; + document.head.appendChild(style); + return style; + })(); + const sheet = style.sheet; + sheet.insertRule(css, (sheet.rules || sheet.cssRules || []).length); + } + + /** + * Download text string as file + */ + function download(filename, text) + { + const element = document.createElement('a') + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)) + element.setAttribute('download', filename) + + element.style.display = 'none' + document.body.appendChild(element) + element.click() + document.body.removeChild(element) + } + + /** + * Add interactive buttons + */ + function addBtn() + { + console.log('addBtn called') + let div = document.createElement('div') + div.innerHTML = ` +
+ + + +
+ ` + document.body.appendChild(div) + + GM_addStyle(` + #superbuy-inject + { + position: absolute; + left: 0; + top: 100px; + z-index: 1000; + display: flex; + flex-direction: column + } + `) + + document.getElementById('btn-fill-items').addEventListener('click', async () => { + let data = await getTaobaoLinks() + + }) + + document.getElementById('btn-json-download').addEventListener('click', async () => + { + download('bought_items.json', JSON.stringify(await getTaobaoLinks(), null, 2)) + }) + } + + addBtn() +})();