国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

趁著雙11,寫個(gè)京東商品自動(dòng)下單

Labradors / 2543人閱讀

摘要:項(xiàng)目地址求個(gè)在現(xiàn)在,商家一年不賣貨,雙賣出一年的貨是大家都知道的事實(shí)了,總得來(lái)說(shuō)調(diào)一調(diào)蚊子腿的價(jià)格,聊勝于無(wú),但是也會(huì)有些神價(jià)格會(huì)出現(xiàn),這時(shí)候買到就是賺到本來(lái)是想趁著雙組臺(tái)電腦,買個(gè)的板套裝,沒想到京東的一直是無(wú)貨的狀態(tài),這幾天有貨了,價(jià)格

項(xiàng)目地址 求個(gè) star

在現(xiàn)在,商家一年不賣貨,雙11賣出一年的貨是大家都知道的事實(shí)了,總得來(lái)說(shuō)調(diào)一調(diào)蚊子腿的價(jià)格,聊勝于無(wú),但是也會(huì)有些神價(jià)格會(huì)出現(xiàn),這時(shí)候買到就是賺到

本來(lái)是想趁著雙11組臺(tái)電腦,買個(gè) Z370 的板U套裝,沒想到京東的 8700k 一直是無(wú)貨的狀態(tài),這幾天有貨了,價(jià)格漲到了3999,簡(jiǎn)直不能忍,看了下板U套裝比較劃算,但是有些板U套裝是不支持自動(dòng)下單的,所以 gayhub 搜搜看有沒有爬蟲可以監(jiān)聽到貨自動(dòng)下單的,正好有了這哥們的 jd-autobuy Python 腳本,還有 Go 的,看了下接口已經(jīng)很齊全了,來(lái)個(gè) node 版本的助助興

這次用到的 http 庫(kù)是 axios,支持客戶端和服務(wù)端,總得來(lái)說(shuō)語(yǔ)法還是很簡(jiǎn)潔的,在這之前還有個(gè) superagent 庫(kù),看了下也差不多,只不過(guò) superagent 在 response 上多處理了下

因?yàn)樵?vue 中使用了 axios,這次想試試服務(wù)端的能力咋樣,還是一如既往的好,滋次一波

先寫個(gè) request header ,畢竟是服務(wù)端,沒有瀏覽器幫你處理 User-Agent,所以自己去瀏覽器請(qǐng)求下然后把 header 拿到

const defaultInfo = {
    header: {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
        "Content-Type": "text/plain;charset=utf-8",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.6,en;q=0.4,en-US;q=0.2",
        "Connection": "keep-alive",
    },
}

header 拿到我們就可以偽裝成瀏覽器去請(qǐng)求二維碼圖片了,京東的掃碼圖片地址 https://qr.m.jd.com/show,沒有多余的技巧,直接用 axios 來(lái)個(gè)get請(qǐng)求即可

async function requestScan() {
    const result = await request({
        method: "get",
        url: "https://qr.m.jd.com/show",
        headers: defaultInfo.header,
        params: {
            appid: 133,
            size: 147,
            t: new Date().getTime()
        },
        responseType: "arraybuffer"
    })
}

參數(shù) appid sizet 可以通過(guò)抓包拿到的,這里注意我 responseType 用的 arraybuffer,默認(rèn)值是 json ,buffer 主要是方便我們來(lái)像本地寫入圖片,我們來(lái)處理下 res

defaultInfo.cookies = cookieParser(result.headers["set-cookie"])
defaultInfo.cookieData = result.headers["set-cookie"];
const image_file = result.data;
await writeFile("qr.png", image_file)
async function writeFile(fileName, file) {
    return await new Promise((resolve, reject) => {
        fs.writeFile(fileName, file, "binary", err => {
            opn("qr.png")
            resolve()
        })
    })
}

這一步 cookie 已經(jīng)拿到了,這里我做了兩步處理,一步是自己寫的 cookieParser 把參數(shù)進(jìn)行解析,主要是拿到其中的 wlfstk_smdl,接下來(lái)會(huì)用到,然后直接 writeFile 寫入圖片就行了,寫好了之后利用 opn 打開圖片,sindresorhus 大神的 opn 庫(kù)還是蠻好用的,可以指定程序打開圖片,文件等

在掃碼之前我們要監(jiān)聽掃碼的狀態(tài)

async function listenScan() {

    let flag = true
    let ticket

    while (flag) {
        const callback = {}
        let name;
        callback[name = ("jQuery" + getRandomInt(100000, 999999))] = data => {
            console.log(`   ${data.msg || "掃碼成功,正在登錄"}`)
            if (data.code === 200) {
                flag = false;
                ticket = data.ticket
            }
        }

        const result = await request({
            method: "get",
            url: "https://qr.m.jd.com/check",
            headers: Object.assign({
                Host: "qr.m.jd.com",
                Referer: "https://passport.jd.com/new/login.aspx",
                Cookie: defaultInfo.cookieData.join(";")
            }, defaultInfo.header),
            params: {
                callback: name,
                appid: 133,
                token: defaultInfo.cookies["wlfstk_smdl"],
                _: new Date().getTime()
            },
        })

        eval("callback." + result.data);
        await sleep(1000)
    }

    return ticket
}

一開始的想法是開個(gè)定時(shí)器來(lái)輪詢下:"好沒好呀",沒有我1秒后再來(lái)問(wèn)下,這里使用 async/await
的強(qiáng)大功能實(shí)現(xiàn)個(gè) sleep,比 setTimeout 的使用更優(yōu)雅而且對(duì)于異步的處理也能夠操控自如

function sleep(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve()
        }, ms)
    })
}

這里我們把 header 組合一下,剛剛拿到的 cookie 帶上,并加上 hostreferer 來(lái)表明我們從哪里來(lái)要到哪里去,參數(shù)里面的 token 就是之前解析 cookie 拿到的 wlfstk_smdl ,這個(gè)接口應(yīng)該約定的 jQuery jsonp(京東看了下 jsonp 還是蠻多的),所以我這里使用一個(gè) callback 來(lái)模擬一個(gè) jsonp 的執(zhí)行,看返回的 code 和 msg,code 為 200 的時(shí)候說(shuō)明掃碼成功了,這時(shí)候 msg 是沒有的,所以自定義下,其他狀態(tài)是有 msg 的,直接輸出就 OK 了,掃碼成功我們要拿到 ticket,這個(gè)從字面上理解就知道了,大兄弟你拿到入場(chǎng)券了,并且 ticket 下單的時(shí)候也是需要的,存起來(lái)

這時(shí)候用你的手機(jī)打開京東掃一掃打開的二維碼圖片,確認(rèn)后掃碼成功,用入場(chǎng)券登錄去

async function login(ticket) {
    const result = await request({
        method: "get",
        url: "https://passport.jd.com/uc/qrCodeTicketValidation",
        headers: Object.assign({
            Host: "passport.jd.com",
            Referer: "https://passport.jd.com/uc/login?ltype=logout",
            Cookie: defaultInfo.cookieData.join("")
        }, defaultInfo.header),
        params: {
            t: ticket
        },
    })

    defaultInfo.header["p3p"] = result.headers["p3p"]
    return defaultInfo.cookieData = result.headers["set-cookie"]
}

這一步?jīng)]什么說(shuō)的,入場(chǎng)券有了,理所應(yīng)當(dāng)?shù)卿洺晒α耍玫?p3p 參數(shù)并且更新下 cookie 這樣一個(gè)合法的身份就誕生了

有了身份后就可以去 get 商品頁(yè)面,這一步需要拿三個(gè)請(qǐng)求的信息拼一下

拿到商品頁(yè)面的 html

function goodInfo(goodId) {

    const stockLink = `http://item.jd.com/${goodId}.html`

    return request({
        method: "get",
        url: stockLink,
        headers: Object.assign(defaultInfo.header, {
            cookie: defaultInfo.cookieData.join("")
        }),
        responseType: "arraybuffer"
    })
}

拿到商品的價(jià)格

async function goodPrice(stockId) {
    const callback = {}
    let name;
    let price;

    callback[name = ("jQuery" + getRandomInt(100000, 999999))] = data => {
        price = data
    }

    const result = await request({
        method: "get",
        url: "http://p.3.cn/prices/mgets",
        headers: Object.assign(defaultInfo.header, {
            cookie: defaultInfo.cookieData.join("")
        }),
        params: {
            type: 1,
            pduid: new Date().getTime(),
            skuIds: "J_" + stockId,
            callback: name,
        },
    })

    eval("callback." + result.data)

    return price
}

拿到商品的狀態(tài)

async function goodStatus(goodId, areaId) {
    const callback = {}
    let name;
    let status

    callback[name = ("jQuery" + getRandomInt(100000, 999999))] = data => {
        status = data[goodId]
    }

    const result = await request({
        method: "get",
        url: "http://c0.3.cn/stocks",
        headers: Object.assign(defaultInfo.header, {
            cookie: defaultInfo.cookieData.join("")
        }),
        params: {
            type: "getstocks",
            area: areaId,
            skuIds: goodId,
            callback: name,
        },
        responseType: "arraybuffer"
    })

    const data = iconv.decode(result.data, "gb2312")
    eval("callback." + data)

    return status
}

最后 Promise.all 一波帶走

async function runGoodSearch() {

    let flag = true

    while (flag) {
        const all = await Promise.all([goodPrice(defaultInfo.goodId), goodStatus(defaultInfo.goodId, defaultInfo.areaId), goodInfo(defaultInfo.goodId)])

        const body = $.load(iconv.decode(all[2].data, "gb2312"))
        outData.name = body("div.sku-name").text().trim()
        const cartLink = body("a#InitCartUrl").attr("href")
        outData.cartLink = cartLink ? "http:" + cartLink : "無(wú)購(gòu)買鏈接"
        outData.price = all[0][0].p
        outData.stockStatus = all[1]["StockStateName"]
        outData.time = formatDate(new Date(), "yyyy-MM-dd hh:mm:ss")

        console.log()
        console.log(`   商品詳情------------------------------`)
        console.log(`   時(shí)間:${outData.time}`)
        console.log(`   商品名:${outData.name}`)
        console.log(`   價(jià)格:${outData.price}`)
        console.log(`   狀態(tài):${outData.stockStatus}`)
        console.log(`   商品連接:${outData.link}`)
        console.log(`   購(gòu)買連接:${outData.cartLink}`)

        const statusCode = all[1]["StockState"]
        // 如果有貨就下單
        // 33 有貨  34 無(wú)貨
        if (+statusCode === 33) {
            flag = false
        } else {
            await sleep(defaultInfo.time)
        }
    }
}

這里要解析 dom,$ 就是有著 Node 版 jQuery 之稱的 cheerio,但是如果直接解析會(huì)亂碼,先轉(zhuǎn)碼,轉(zhuǎn)碼神器出場(chǎng) iconv-lite,剩下的就是 jQuery 操作了,很久沒寫 jQuery 了,寫起來(lái)還是這么的順溜

defaultInfo 中的 goodId 是商品的 id,下面會(huì)說(shuō)到,解析命令行的參數(shù)獲得的,在哪里能看到呢,來(lái)圖

areaId 是對(duì)應(yīng)著區(qū)域的信息,畢竟每個(gè)城市的庫(kù)存都是不一樣的

京東購(gòu)物的流程購(gòu)物車先走一波,然后開始下單付款,有貨了我們加入購(gòu)物車

async function addCart() {
    console.log()
    console.log("   開始加入購(gòu)物車")

    const result = await request({
        method: "get",
        url: outData.cartLink,
        headers: Object.assign(defaultInfo.header, {
            cookie: defaultInfo.cookieData.join("")
        }),
    })

    const body = $.load(result.data)

    const addCartResult = body("h3.ftx-02")

    if (addCartResult) {
        console.log(`   ${addCartResult.text()}`)
    } else {
        console.log("   添加購(gòu)物車失敗")
    }
}

沒什么可說(shuō)的,加入后開始下單

async function buy() {
    const orderInfo = await request({
        method: "get",
        url: "http://trade.jd.com/shopping/order/getOrderInfo.action",
        headers: Object.assign(defaultInfo.header, {
            cookie: defaultInfo.cookieData.join("")
        }),
        params: {
            rid: new Date().getTime(),
        },
        responseType: "arraybuffer"
    })

    const body = $.load(orderInfo.data)
    const payment = body("span#sumPayPriceId").text().trim()
    const sendAddr = body("span#sendAddr").text().trim()
    const sendMobile = body("span#sendMobile").text().trim()

    console.log()
    console.log(`   訂單詳情------------------------------`)
    console.log(`   訂單總金額:${payment}`)
    console.log(`   ${sendAddr}`)
    console.log(`   ${sendMobile}`)
    console.log()

    console.log("   開始下單")

    const result = await request({
        method: "post",
        url: "http://trade.jd.com/shopping/order/submitOrder.action",
        headers: Object.assign(defaultInfo.header, {
            cookie: defaultInfo.cookieData.join("")
        }),
        params: {
            "overseaPurchaseCookies": "",
            "submitOrderParam.btSupport": "1",
            "submitOrderParam.ignorePriceChange": "0",
            "submitOrderParam.sopNotPutInvoice": "false",
            "submitOrderParam.trackID": defaultInfo.ticket,
            "submitOrderParam.eid": defaultInfo.eid,
            "submitOrderParam.fp": defaultInfo.fp,
        },
    })

    if (result.data.success) {
        console.log(`   下單成功,訂單號(hào)${result.data.orderId}`)
        console.log("請(qǐng)前往京東商城及時(shí)付款,以免訂單超時(shí)取消")
    } else {
        console.log(`   下單失敗,${result.data.message}`)
    }
}

其實(shí)這里 post http://trade.jd.com/shopping/... 這個(gè)就可以了,前面的一個(gè)請(qǐng)求是下單頁(yè)面拿一下訂單的信息展示下,這里會(huì)有兩個(gè)注意的點(diǎn)

商品的數(shù)量
京東下單是把購(gòu)物車這個(gè)商品全部下單,不管數(shù)量的,比如你購(gòu)物車已經(jīng)有一件這個(gè)商品了,那么前面的流程走完后購(gòu)物車現(xiàn)在有兩件這個(gè)商品,下單后是下單了兩件,當(dāng)然了這里是可以更改數(shù)量的,但是我沒寫

訂單的參數(shù)
上面下單的請(qǐng)求可以注意到三個(gè)陌生的參數(shù) submitOrderParam.trackID submitOrderParam.eid submitOrderParam.fp ,trackID 前面有拿到過(guò),這里直接用就行了,那么 eid 和 fp 是從哪來(lái)的呢?答案是登錄頁(yè)面,但是這里有個(gè)坑是 request 返回的頁(yè)面拿到的 dom 元素是不行的,只能通過(guò)瀏覽器來(lái),這也很好辦,Node 有 phantomjs,但是這里我用了 Chrome 出品的 puppeteer

puppeteer 使用也很簡(jiǎn)單,它是基于 Node 的 headless Chrome 工具

puppeteer.launch().then(async browser => {
    console.log("   初始化完成,開始抓取頁(yè)面")
    const page = await browser.newPage();
    await page.goto("https://passport.jd.com/new/login.aspx");
    await sleep(1000)
    console.log("   頁(yè)面抓取完成,開始分析頁(yè)面")
    const inputs = await page.evaluate(res => {
        const result = document.querySelectorAll("input")
        const data = {}

        for (let v of result) {
            switch (v.getAttribute("id")) {
                case "token":
                    data.token = v.value
                    break
                case "uuid":
                    data.uuid = v.value
                    break
                case "eid":
                    data.eid = v.value
                    break
                case "sessionId":
                    data.fp = v.value
                    break
            }
        }

        return data
    })

    Object.assign(defaultInfo, inputs)
    await browser.close();
    console.log("   頁(yè)面參數(shù)到手,關(guān)閉瀏覽器")

    console.log()
    console.log("   -------------------------------------   ")
    console.log("                請(qǐng)求掃碼")
    console.log("   -------------------------------------   ")
    console.log()

})

puppeteer 首先要 launch 后來(lái)生成一個(gè) browser 的實(shí)例,我們用 browser 來(lái)新建一個(gè)頁(yè)面運(yùn)行我們的網(wǎng)址,并且我們可以在它提供的 evaluate 方法中操作 DOM,上面的代碼也是很簡(jiǎn)單的,一目了然

至此基本上一個(gè)自動(dòng)下單的功能就完成了,再擴(kuò)展下命令行參數(shù)

const args = require("yargs").alias("h", "help")
    .option("a", {
        alias: "area",
        demand: true,
        describe: "地區(qū)編號(hào)",
    })
    .option("g", {
        alias: "good",
        demand: true,
        describe: "商品編號(hào)",
    })
    .option("t", {
        alias: "time",
        describe: "查詢間隔ms",
        default: "10000"
    })
    .option("b", {
        alias: "buy",
        describe: "是否下單",
        default: true
    })
    .usage("Usage: node index.js -a 地區(qū)編號(hào) -g 商品編號(hào)")
    .example("node index.js -a 2_2830_51810_0 -g 5008395")
    .argv;

這里我給了兩個(gè)必需的參數(shù)和兩個(gè)可選的參數(shù),-a 必須要的,地區(qū)編號(hào),-g 必要要的,商品編號(hào),-t 商品查詢的間隔時(shí)間,默認(rèn)是10s,-b是否自動(dòng)購(gòu)買,默認(rèn)是購(gòu)買的,這里是 boolean,yargs 還是蠻好用的,也可以用 TJ 大神的 commander,都是一樣的

完整的代碼可以去下面的項(xiàng)目地址中查看

項(xiàng)目地址 求個(gè) star

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/89420.html

相關(guān)文章

  • #11.11#騰訊云11智惠云集:爆款云服務(wù)器首年48元,海量代金券,續(xù)費(fèi)2.5折起

    摘要:騰訊云雙活動(dòng)地址點(diǎn)擊進(jìn)入騰訊云年雙十一活動(dòng)優(yōu)惠活動(dòng)參與騰訊云活動(dòng),多重優(yōu)惠享不停一爆品秒殺爆款核云服務(wù)器首年元,每日?qǐng)雒霘ⅲ瓯c(diǎn)價(jià)。 騰訊云正式開啟2021年雙11智惠云集促銷活動(dòng),多重優(yōu)惠享不停,包括首購(gòu)服務(wù)器低至0.4折直擊底價(jià),爆款1核2G云服務(wù)器首年48元;新老用戶同享,領(lǐng)今年最大額度代金券;折上再享優(yōu)惠iPad Pr,額外10%返券等你拿,具體活動(dòng)內(nèi)容如下。 ...

    clasnake 評(píng)論0 收藏0
  • 架構(gòu) - 收藏集 - 掘金

    摘要:淺談秒殺系統(tǒng)架構(gòu)設(shè)計(jì)后端掘金秒殺是電子商務(wù)網(wǎng)站常見的一種營(yíng)銷手段。這兩個(gè)項(xiàng)目白話網(wǎng)站架構(gòu)演進(jìn)后端掘金這是白話系列的文章。 淺談秒殺系統(tǒng)架構(gòu)設(shè)計(jì) - 后端 - 掘金秒殺是電子商務(wù)網(wǎng)站常見的一種營(yíng)銷手段。 不要整個(gè)系統(tǒng)宕機(jī)。 即使系統(tǒng)故障,也不要將錯(cuò)誤數(shù)據(jù)展示出來(lái)。 盡量保持公平公正。 實(shí)現(xiàn)效果 秒殺開始前,搶購(gòu)按鈕為活動(dòng)未開始。 秒殺開始時(shí),搶購(gòu)按鈕可以點(diǎn)擊下單。 秒殺結(jié)束后,按鈕按鈕變...

    Riddler 評(píng)論0 收藏0
  • 京東CTO張晨:用技術(shù)迎接第四次零售革命

    摘要:張晨表示,第四次零售革命必然是顛覆性的,因?yàn)樗淖兞肆闶鄣幕A(chǔ)設(shè)施。張晨表示,零售基礎(chǔ)設(shè)施是第四次零售革命的核心,其社會(huì)化更是推動(dòng)整個(gè)零售行業(yè)變革的動(dòng)力。 從用戶畫像個(gè)性化的描摹,到與供應(yīng)商結(jié)合需求進(jìn)行動(dòng)態(tài)定價(jià),再到無(wú)人運(yùn)輸與云服務(wù)在基礎(chǔ)設(shè)施上的升級(jí),圍繞零售的整條產(chǎn)業(yè)鏈,京東已經(jīng)在底層進(jìn)行了長(zhǎng)期的建設(shè)和夯實(shí)。 showImg(https://segmentfault.com/img/...

    evin2016 評(píng)論0 收藏0
  • #11.11#騰訊云:企業(yè)高配大帶寬云服務(wù)器,4核8G內(nèi)存/10M,三年僅需768元

    摘要:年騰訊云雙十一活動(dòng)力針對(duì)企業(yè)用戶推出專享的高配置大帶寬云服務(wù)器優(yōu)惠核年元,核年元,核年元,適合各種企業(yè)建站使用。輕量云服務(wù)器騰訊云輕量應(yīng)用服務(wù)器優(yōu)惠,可選上海廣州北京成都機(jī)房,我們可以自定義配置,其中核年元核年元核年元。 騰訊云2021年雙十一活動(dòng)力度非常不錯(cuò),雙11智惠云集不管是個(gè)人還是企業(yè)都比較優(yōu)惠,這里小編來(lái)推薦下企業(yè)專區(qū)下面的輕量應(yīng)用服務(wù)器,Lighthouse具有配置高、帶寬...

    mozillazg 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<