利用Python檢索某東口罩的庫存和價格等信息

最近口罩很多地方都得搖號購買了……買不到口罩呆在家裏總不是辦法,很快就要上班了啊……於是用Python寫了個京東庫存檢索的工具,一旦發現有庫存,就會彈窗提示,並且直接打開瀏覽器開啓對應頁面。

需要用到的包

import configparser
import json
import time
#用於啓動系統默認瀏覽器
import webbrowser
#用於代理Python自帶的re,以解決檢索帶有“/”符號的正則會出問題的bug
import regex as re
import requests
#pip install pywin32
#用於實現彈窗提示,可能不支持非windows系統
import win32api
import win32con
#用於檢索當前是什麼系統,以屏蔽win32的功能
import platform

sysno=platform.system()
print('當前正在使用',sysno,'系統')
print('若非Windows系統,將無法支持彈窗提示。')
print('如果你是高級用戶,可以閱讀目錄下的readme.txt文件,瞭解有關配置信息。')

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
}

請在程序當前目錄下新建一個province.txt的文件,內容如下:

1 北京
2 上海
3 天津
4 重慶
5 河北
6 山西
7 河南
8 遼寧
9 吉林
10 黑龍江
11 內蒙古
12 江蘇
13 山東
14 安徽
15 浙江
16 福建
17 湖北
18 湖南
19 廣東
20 廣西
21 江西
22 四川
23 海南
24 貴州
25 雲南
26 西藏
27 陝西
28 甘肅
29 青海
30 寧夏
31 新疆

處理需要檢索的sku的鏈接,我已經整理了一些口罩的鏈接,如有需要可以自己補充或者分享。

#文件名爲linklist.txt,保存在當前的程序目錄下
#請每行輸入一個京東自營的鏈接,非京東自營暫未測試,儘量使用京東電腦端或京東手機APP複製出來的鏈接
https://item.jd.com/100011293950.html?dist=jd
https://item.jd.com/100006248247.html?dist=jd
https://item.jd.com/100006248177.html?dist=jd
https://item.jd.com/100011293928.html?dist=jd
https://item.jd.com/1336984.html?dist=jd
https://item.jd.com/100001086804.html?dist=jd
https://item.jd.com/100009130434.html?dist=jd
https://item.jd.com/1835967.html?dist=jd
https://item.jd.com/100000890793.html?dist=jd
https://item.jd.com/3083413.html?dist=jd
https://item.jd.com/3083409.html?dist=jd
https://item.jd.com/100006245723.html?dist=jd
https://item.jd.com/100009732594.html?dist=jd
https://item.jd.com/100005463173.html?dist=jd
https://item.jd.com/100005507297.html?dist=jd
https://item.jd.com/100009442472.html?dist=jd
https://item.jd.com/100010638508.html?dist=jd
https://item.jd.com/100010638508.html?dist=jd
https://item.jd.com/100009394518.html?dist=jd
https://item.jd.com/7257333.html?dist=jd
https://item.jd.com/100005818743.html?dist=jd
https://item.jd.com/100002690384.html?dist=jd
https://item.jd.com/100009445348.html?dist=jd
https://item.jd.com/100009441994.html?dist=jd
https://item.jd.com/1938795.html?dist=jd
https://item.jd.com/100010439846.html?dist=jd
https://item.jd.com/4080705.html?dist=jd
https://item.jd.com/851157.html?dist=jd
https://item.jd.com/100011290368.html

另外還需要新建一個config.conf文件在當前目錄下。我用的configparser的包好像對GBK的配置文件讀取有些問題,所以註釋用英文寫了,時間有限暫不理睬這個問題。

[config]
#File name is ‘config.conf’
#Set the cycle time in seconds. It is recommended to cycle every 60 seconds
waittime = 60

這個文件的用途是用來控制循環的時間的,單位是秒,默認是60秒循環一次linklist.txt文件中的鏈接。 

需要用到的自己寫的方法,本工具藉助命令行/終端執行。

def getUnicodeStr(s: str, encode='utf-8') -> str:
    """
    用於將str轉爲Unicode,然後再將Unicode變成str但是不編碼的
    :param s:
    :return:
    """
    u = s.encode('unicode_escape')
    ns = str(u.decode(encode)).replace('\\', '%')
    return ns


def getLoaction(p: str) -> dict:
    """
    獲取地址列表
    :param p:
    :return:
    """
    url = 'https://fts.jd.com/area/get?fid=%s&sceneval=2' % p
    resp = requests.get(url=url, headers=headers)
    j = resp.json()
    areaDict = {}
    for k in j:
        areaDict[str(k['id'])] = k['name']
    return areaDict


def getContentFromInput() -> str:
    """
    獲取輸入內容
    :return:
    """
    content = input('請輸入你的地址代碼,按鍵盤上的回車(ENTER)按鍵確認:')
    return str(content)


def printDict(d: dict):
    """
    用於打印字典
    :param d:
    :return:
    """
    print('代碼 | 地址')
    for i in d.keys():
        print(str(i) + '\t' + str(d[i]))

代碼段1:

因爲京東的庫存是有地域分佈的,所以先要拼出所需檢索庫存的地區,然後才能去檢索具體某個SKU是否有貨。

# 獲取地址
provicelist = {}
print('省份列表:')
with open('provincelist.txt', 'r', encoding='utf-8') as f:
    for line in f.readlines():
        ll = line.split(' ')
        provicelist[str(ll[0])] = ll[1].replace('\n', '')
    f.close()
print('代碼 | 地址')
for i in provicelist.keys():
    print(str(i) + '\t' + str(provicelist[i]))
p = getContentFromInput()
areaCodeList = {}
while True:
    if p not in provicelist.keys():
        p = input('地區代碼輸入錯誤,請重新輸入:')
    else:
        areaCodeList[p] = provicelist[p]
        provicelist = getLoaction(p)
        if len(provicelist) > 0:
            printDict(provicelist)
            p = getContentFromInput()
        else:
            break

代碼段2:

對地址進行處理,拼出京東請求sku信息所需的字段。這裏用的是京東H5裏面的接口,京東所需的地址是四段式的,如果地址不足4段,需要用0或空值補齊。

# 地址不足4位會補全地址
areano = []
areaCN = []
for i in areaCodeList.keys():
    areano.append(i)
    areaCN.append(areaCodeList[i])
while len(areano) < 4:
    areano.append('0')
    areaCN.append('')

# 轉爲京東cookie專用格式
mitemAddrId = jdAddrId = '_'.join(areano)
jdAddrName = '_'.join(areaCN)
regionAddress = '.'.join(areano)
wq_addr = '0|' + jdAddrId + '|' + jdAddrName + '||'
print('已選擇地址:')
printDict(areaCodeList)

代碼段3:

讀取前文中提到的linklist.txt文件中的鏈接,通過正則獲取sku的id,然後去重。然後讀取前文提到的config.conf文件中的循環時間。

# 獲取SKU鏈接
linklist = []
with open('linklist.txt', 'r', encoding='utf-8') as f:
    for i in f.readlines():
        if i.find('#', 0, 1) > -1:
            pass
        else:
            url = i.replace('\n', '')
            # 嘗試匹配1
            skup = re.search(r'jd.com/\d+', url)
            if skup != None:
                skun = str(skup.group()).replace('jd.com/', '')
                linklist.append(skun)
            else:
                skup = re.search(r'jd.com/product/\d+', url)
                if skup != None:
                    skun = str(skup.group()).replace('jd.com/product/', '')
                    linklist.append(skun)
# 去重
sll = set(linklist)

# 讀取配置文件
cf = configparser.ConfigParser()
cf.read('config.conf')
waittime = cf.getint('config', 'waittime')
if waittime < 0:
    waittime = 60
    print('等待時間不能小於0!按照默認60秒開始中')

代碼片段4:

開始循環檢索鏈接列表中所有的商品是否有貨,如果有貨就彈窗提示、使用系統默認瀏覽器打開對應商品的列表。這時候就趕緊去買吧!

這裏值得注意的是,京東的參數是寫在cookies裏面的……

# 開始循環任務
cookie = 'wq_addr=%s; jdAddrId=%s; jdAddrName=%s; commonAddress=0; regionAddress=%s; mitemAddrId=%s; mitemAddrName=' % (
    getUnicodeStr(wq_addr), jdAddrId, getUnicodeStr(jdAddrName), regionAddress.replace('.', '%2C'),
    mitemAddrId)
cookietoUnicode = cookie.replace('|', '%7C')
headers2 = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
    'cookie': cookietoUnicode
}
while True:
    for i in set(sll):
        try:
            r = requests.get('https://item.m.jd.com/item/mview2?datatype=1&cgi_source=mitem&sku=%s' % i,
                             headers=headers2)
            htmlRespRaw = r.text
            hr = htmlRespRaw[7:len(htmlRespRaw) - 2]
            hrr = re.sub(r'\\x\d\w', '', hr)
            hrrj = json.loads(hrr)
            skuName = hrrj['skuName']
            skuId = hrrj['skuId']
            pricep = hrrj['price']['p']
            pricetpp = hrrj['price']['tpp']
            StockState = hrrj['stock']['StockState']
            StockStateName = hrrj['stock']['StockStateName']
            skuUrl = 'https://item.jd.com/%s.html' % skuId
            print('商品名稱:', skuName, '商品價格:', pricep, '商品鏈接:', skuUrl, '庫存狀態:', StockStateName)
            if StockState == 33 or StockState == 39 or StockStateName != '無貨':
                # 使用默認瀏覽器打開網頁
                webbrowser.open(skuUrl, new=2)
                # 使用Windows的彈窗提醒
                if sysno=='Windows':
                    win32api.MessageBox(0, '發現有貨的商品,已爲您在瀏覽器中打開。', '提醒', win32con.MB_OK)
            # if StockState == 33:
            #     print('現貨')
            # elif StockState == 39:
            #     print('有貨')
            # elif StockState == 36:
            #     print('預定')
            # else:
            #     print('無貨')
            r.close()
            time.sleep(1)
        except BaseException:
            print(BaseException)
            print(hr)
    time.sleep(waittime)

我把文件最後保存爲run.py。此時目錄下應該有以下文件

  • linklist.txt
  • province.txt
  • config.conf
  • run.py

然後打開命令行,轉到文件所在目錄,執行

python run.py

接着按照頁面上的內容輸入你的省/直轄市、市、區/縣、鎮/街道的代碼,然後檢索程序將開始運行。 

發佈了17 篇原創文章 · 獲贊 20 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章