一、背景
大家是否在京东购买过东西 我相信大部分的京东铁粉都知道 如果二个月内购买的商品出现了降价 我们可以申请报价 然后得到差价补偿,这个时候 如果我购买的东西比较多 一个个手点岂不是很麻烦?其次时间上你也不一定会记得
这里小编告诉大家 申请报价的地方在 京东app->我的->客户服务->价格保护 也就是下图界面了 在这里 小编的是个空的 当然也就直白的告诉了大家 小编已经二个多月没有在京东购买过商品了
二、解决办法
问题来了 如何解决这个事情呢?首先批量的话 可以通过python写个脚本来执行,其次定时可以利用我们上次讲的crontab
a.分析整体接口请求
小编通过抓包分析 发现一共有二个接口 看下图大概知道意思 第一个接口是获取所有的订单数据 ,第二个接口是根据第一个接口返回的orderid skuid参数 进行价格申请提交,所以现在这个问题的关键 就是需要从第一个响应里面提取出这些数据。
b.对第一个接口的响应数据进行提取(也就是提取第二个接口的orderId skuId等)
分析完大致的请求之后,我们首先要做的 是模拟发送第一个请求,然后在对第一个请求的响应 进行数据提取,在这里查看第一个接口返回的数据 可以知道这个返回了一个html的源代码
相对于之前小编遇到的 大部分app都会使用json格式进行数据传递的 这里京东app不一样 他非得返回一个html ,这么看小编觉得很不好看,于是 copy了他的响应部分的body 直接在自己电脑新建了一个记事本 粘贴进去,然后修改后缀名为html 打开这个html开始进行了审查元素,根据响应和第一个接口的提交参数来看 第一次提交的pagesizede条数是按照订单数来的 也不是sku数 ,然后查看第二个接口的请求参数 发现订单id可以相同 只是skuid可以不同,所以我们这里需要定位到每个sku以及sku所属orderid,而下图中 小编突然发现 蓝色区域标记处(skuApply()函数里面的值) ,不正好是我需要的数据?于是确定了
第一个值 :orderId
第二个值:skuId
第三个值:不清楚
第四个值:应该是第二个请求里面的type 或者orderCategory (这里小编暂时定义成是type 而orderCategory直接当做是3 )
第五个值:不清楚
知道了值在哪里 现在我们需要确定怎么在这个html取值 ,我们查看到这个数据是一个a标签的onclick属性 而这个a标签的clstag属性值为“pageclick|keycount|M_proprice_201801099|1” 于是小编搜索了这个值,发现这个数量跟sku的数量一致 于是可以基本确定等会以这个标签进行xpath定位。
这里小编用的是python中lxml的tree定位方法 直接定位a标签属性clstag值为pageclick|keycount|M_proprice_201801099|1的标签,然后在取这个标签中onclick的值,所以得出的xpat为 : //a[@clstag="pageclick|keycount|M_proprice_201801099|1"]/@onclick
c.利用上一步提取的orderId skuId值 作为参数 模拟第三个接口 ,这个参数都来了 模拟一下请求而已 这个就不明细讲了 。
d.之后在linux中设置定时任务 这个可以参考上篇博客 https://blog.csdn.net/Tester_xjp/article/details/86749954
最后奉上运行截图和源代码一份
# author: xiejiangpeng
# time:2019/2/1/21:25
# python:3.6
# message:京东申请报价
import requests
import time
import random
import logging
from lxml import etree
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
class JdApplyPrice(object):
def __init__(self):
self.host = "https://msitepp-fm.jd.com"
self.header = {'User-Agent': 'Dalvik/1.6.0 (Linux; U; Android 4.1.1; M040 Build/JRO03H)'}
self.cookie = {'隐私': '换成自己的京东cookie'}
self.n = 0
self.logger = logging.getLogger("运行日志:")
self.logger.setLevel(logging.DEBUG)
self.handler = logging.FileHandler("log.txt")
self.handler.setLevel(logging.DEBUG)
self.conhandler = logging.StreamHandler()
self.conhandler.setLevel(logging.INFO)
self.formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
self.logger.addHandler(self.handler)
self.logger.addHandler(self.conhandler)
self.handler.setFormatter(self.formater)
self.conhandler.setFormatter(self.formater)
def applyprice(self):
# 1.获取对应的sku和order数据
infourl = self.host + "/rest/priceprophone/priceskusPull"
infodata = {'page': '1', 'pageSize': '50', 'keyWords': '', 'sid': '', 'type': '3'}
infohtml = requests.post(url=infourl, data=infodata, cookies=self.cookie, verify=False,
headers=self.header).content
self.logger.info(str(infohtml))
infolist = etree.HTML(infohtml).xpath('//a[@clstag="pageclick|keycount|M_proprice_201801099|1"]/@onclick')
skudict = {}
for i in range(len(infolist)):
skuapplys = str(infolist[i]).split(",")
skudict["orderId"] = skuapplys[0][9:]
skudict["orderCategory"] = "3"
skudict["skuId"] = skuapplys[1]
skudict["sid"] = ""
skudict["type"] = skuapplys[3]
skudict["refundtype"] = "1"
# 2.申请报价
time.sleep(int(random.randint(2, 10)))
self.skuprotectapply(**skudict)
self.n = self.n + 1
self.logger.info("合计申请保价数:%s" % str(self.n))
def skuprotectapply(self, **data):
self.header.update({"Accept": "application/json"})
applyurl = self.host + "//rest/priceprophone/skuProtectApply"
resp = requests.post(url=applyurl, data=data, cookies=self.cookie, verify=False, headers=self.header)
self.logger.info(str(resp.json()))
if __name__ == '__main__':
xiejiangpeng = JdApplyPrice()
xiejiangpeng.applyprice()