利用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

接着按照页面上的内容输入你的省/直辖市、市、区/县、镇/街道的代码,然后检索程序将开始运行。 

你可能感兴趣的:(利用Python检索某东口罩的库存和价格等信息)