1. 1. 前言
  2. 2. 开始
  3. 3. 注意
  4. 4.

前言

我会在京东上买些电子产品和文具,那么如何获得商品降价信息,使用更低的价格购买呢?

开始

新建一个 GitHub 仓库,创建 main.py , notify.py.github/workflows/auto.yml 三个文件,内容如下:

main.py (点击展开)
# -*- coding: utf-8 -*-
# 导入模块
import urllib.request, random, json, notify


# 商品列表
check = [
# 闪迪(SanDisk)64GB TF(MicroSD)存储卡
'1887526',
# 晨光(M&G)文具 0.5mm 黑色中性笔
'277393'
# ...
]


# 价格列表,用于临时存储获取到的价格数据
price = {}

# 读取上次的价格文件
try:
file = open('./price.json', mode='r')
lastPrice = json.loads(file.readlines()[0])
except:
print("读取文件时出现错误!")


# 遍历列表,比对价格
for itemId in check:
# 组合请求 URL
# http://p.3.cn/prices/mgets?skuIds=J_
url = 'http://p.3.cn/prices/mgets?skuIds=J_{}'.format(itemId)
# User-Agent 列表
ua = ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60','Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50']
# 随机获得一个 User-Agent,如不带 User-Agent 请求,就会被拒绝。
headers = {
'User-Agent': ua[random.randint(0,4)]
}
# 组合请求参数
request = urllib.request.Request(url = url, headers = headers)
# 向京东发起请求
response = urllib.request.urlopen(request)
# 将获得的数据转为 JSON
page_text = json.loads(response.read().decode('utf-8'))
thisPrice = float(page_text[0]['p'])
# 将价格输入至价格变量
price[itemId] = thisPrice

# 尝试对比价格
try:
if thisPrice > lastPrice[itemId]:
print("{0} 涨价".format(itemId))

print(thisPrice - lastPrice[itemId])
notify.notify(itemId, 0, thisPrice - lastPrice[itemId], thisPrice)

elif thisPrice < lastPrice[itemId]:
print("{0} 降价".format(itemId))
print(lastPrice[itemId] - thisPrice)
notify.notify(itemId, 2, lastPrice[itemId] - thisPrice, thisPrice)

elif lastPrice[itemId] == thisPrice:
print("{0} 价格不变".format(itemId))
else:
print("{0} 未知错误".format(itemId))
except:
print("无法进行比对")


# 将 JSON 转为 字符串
priceStr = json.dumps(price)

# 写入价格文件,便于下次查询
try:
file = open('./price.json', mode = 'w')
file.write(priceStr)
file.close()
except:
print("写入文件时出现错误")


print(price)

notify.py (点击展开)
# -*- coding: utf-8 -*-
import urllib.request, json, urllib.parse, ssl
ssl._create_default_https_context = ssl._create_unverified_context

'''
提醒的服务,支持 `wechat` 与 `qmsg`。
需要在下方进行下一步的配置
'''
server = ['qmsg']

'''
WeChat 采用的是 Server 酱 (https://sc.ftqq.com/3.version) 提供的服务
key:Server 酱提供的 Token,必填。
'''
wechat = {
"key": ""
}

'''
Qmsg 采用的是 Qmsg 酱 (https://qmsg.zendee.cn/) 提供的服务
key:Qmsg 酱提供的 KEY,必填。
qid:接收消息的 QQ 号(不支持 QQ 群),可以添加多个,以半角逗号分割,如:`10001,10002`(必须均在您的 Qmsg 酱 QQ 号列表中)。
'''
qmsg = {
"key": "",
"qid": ""
}

def wechat_send(key, title, text):
url = 'http://sc.ftqq.com/{0}.send?text={1}&desp={2}'.format(key, urllib.parse.quote(title), urllib.parse.quote(text))
headers = {
'User-Agent': "Check Price Bot"
}
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
page_text = json.loads(response.read().decode('utf-8'))
if page_text['errno'] == 0:
return True
else:
return False

def qmsg_send(key, id, text):
url = 'http://qmsg.zendee.cn/send/{0}?msg={1}&qq={2}'.format(key, urllib.parse.quote(text), id)
headers = {
'User-Agent': "Check Price Bot"
}
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
page_text = json.loads(response.read().decode('utf-8'))
if page_text['code'] == 0:
return True
else:
return False

def notify(id,type,price,nowPrice):
'''
type:
0: 涨价
1: 无变化
2: 降价
id: 商品 ID
price: 差价
nowPrice: 现价
'''

for svId in server:
def send(title,content):
if svId == 'wechat':
wechat_send(wechat["key"],title,content)
if svId == 'qmsg':
qmsg_send(qmsg["key"],qmsg["qid"],title + "\n" + content)
else:
return False
if type == 0:
title = "商品 {0} 涨价!".format(id)
content = "您关注的商品 {0} 涨价咯!价格相较于上次监测,高了 {1} 元,现价 {2} 元。商品详情:https://item.jd.com/{0}.html".format(id,price,nowPrice)
send(title,content)
elif type == 1:
print("价格没有变化,不推送通知。")
elif type == 2:
title = "商品 {0} 降价!".format(id)
content = "您关注的商品 {0} 降价咯!价格相较于上次监测,低了 {1} 元,现价 {2} 元。商品详情:https://item.jd.com/{0}.html".format(id, price,nowPrice)
send(title, content)
else:
return False
.github/workflows/auto.yml (点击展开)
name: Check Price

on:
push:
branches:
- master
schedule:
# 每 1 小时运行一次
- cron: "0 * * * *"

jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v2
- name: 'Set up Python'
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Run
run: |
python main.py
- name: Push
run: |
git config --local user.email "icolabot@e.yfun.top"
git config --local user.name "iColaBot"
date +"%Y-%m-%d %H:%M:%S.%N" > date.txt
git add -A
git commit -am "Update price.json"
git push origin master

注意

计划任务语法有 5 个字段,中间用空格分隔,每个字段代表一个时间单位。

┌───────────── 分钟 (0 - 59)
│ ┌───────────── 小时 (0 - 23)
│ │ ┌───────────── 日 (1 - 31)
│ │ │ ┌───────────── 月 (1 - 12 或 JAN-DEC)
│ │ │ │ ┌───────────── 星期 (0 - 6 或 SUN-SAT)
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
* * * * *

每个时间字段的含义:

符号描述举例
*任意值* * * * * 每天每小时每分钟
,值分隔符1,3,4,7 * * * * 每小时的 1 3 4 7 分钟
-范围1-6 * * * * 每小时的 1-6 分钟
/*/15 * * * * 每隔 15 分钟

注:由于 GitHub Actions 的限制,如果设置为 * * * * * 实际的执行频率为每 5 分执行一次。

新建文件 并 配置 notify.py 后,GitHub Action 就会定时执行代码。如果有降价或涨价,就会按照 notify.py 的配置进行通知。

京东也有降价提醒的功能,但我实在是不想给 京东 开通知权限,经常推送商品广告。

本文部分内容参考:justjavac/auto-green#readme