From 567e88a9454d016a1658ffd8b74a2fbeeed03dd1 Mon Sep 17 00:00:00 2001 From: cycz <838143144@qq.com> Date: Mon, 25 Jan 2021 00:27:56 +0800 Subject: [PATCH] goodbye --- AreaTool.py | 11 - README.md | 16 +- config.py | 22 -- configDemo.ini | 40 ---- jdBuyMask.py | 488 ------------------------------------------ jdBuyMask_V2.py | 551 ------------------------------------------------ jdBuyMask_V3.py | 492 ------------------------------------------ jdEmail.py | 41 ---- jdProgram.py | 219 ------------------- jdlogger.py | 26 --- message.py | 37 ---- util.py | 45 ---- wechat_ftqq.py | 31 --- 13 files changed, 5 insertions(+), 2014 deletions(-) delete mode 100644 AreaTool.py delete mode 100644 config.py delete mode 100644 configDemo.ini delete mode 100644 jdBuyMask.py delete mode 100644 jdBuyMask_V2.py delete mode 100644 jdBuyMask_V3.py delete mode 100644 jdEmail.py delete mode 100644 jdProgram.py delete mode 100644 jdlogger.py delete mode 100644 message.py delete mode 100644 util.py delete mode 100644 wechat_ftqq.py diff --git a/AreaTool.py b/AreaTool.py deleted file mode 100644 index 62afe52..0000000 --- a/AreaTool.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding=utf-8 -*- -from jdlogger import logger - -''' -测试 https://c0.3.cn/stock?skuId=100003406321&area=19_1607_4773_0&venderId=1000000946&buyNum=1&choseSuitSkuIds=&cat=9192,9197,12588&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=1580535906442142991701&ch=1&callback=jQuery4291064 -请看教程寻找自己的url -''' -url = '' -skuId = url.split('skuId=')[1].split('&')[0] -area = url.split('area=')[1].split('&')[0] -logger.info('你的area是[ %s ],链接的商品id是[ %s ]', area, skuId) diff --git a/README.md b/README.md index 38ab36e..6409df0 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,12 @@ **** -ãݲˡ +ٷֿ֪ͨʹ88 -exe汾ܹһʱڡ +¼һ¿ֵѷԱʹü໥ -ף**Լ**Ŀ -**** -ʹ÷ https://blog.csdn.net/cyz52/article/details/104239558 -## exe汾[С] 99ֿ -ӣhttps://pan.baidu.com/s/1bgGXsH071GkHWGlLIwgRVw -ȡ룺do3f - -ת֣ĽӿѾ -Ҫ˵ԭ򣬼ȺҪɣ1053467385 +л湤ҲԺ˽ѯ +ټ +**** ף򵽿 diff --git a/config.py b/config.py deleted file mode 100644 index 661a502..0000000 --- a/config.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -import os -import configparser - - -class Config(object): - def __init__(self, config_file='configDemo.ini'): - self._path = os.path.join(os.getcwd(), config_file) - if not os.path.exists(self._path): - raise FileNotFoundError("No such file: config.ini") - self._config = configparser.ConfigParser() - self._config.read(self._path, encoding='utf-8-sig') - self._configRaw = configparser.RawConfigParser() - self._configRaw.read(self._path, encoding='utf-8-sig') - - def get(self, section, name): - return self._config.get(section, name) - - def getRaw(self, section, name): - return self._configRaw.get(section, name) - - diff --git a/configDemo.ini b/configDemo.ini deleted file mode 100644 index 9a8083f..0000000 --- a/configDemo.ini +++ /dev/null @@ -1,40 +0,0 @@ -[config] - - -# 地区id (不知道怎么获取的使用一下AreaTool.py工具) -area = 19_1607_4773_0 -# cookie -cookies_String = shshshfpa=21a5db2 -# 推送方式 1为邮箱,2为微信 -messageType =1 -# mail -mail = xxxxxx@qq.com -# sc_key 方糖微信推送的key 不知道的请看http://sc.ftqq.com/3.version -sc_key = test - -# 支付密码 -# 如果你的账户中有可用的京券(注意不是东券)或 在上次购买订单中使用了京豆, -# 那么京东可能会在下单时自动选择京券支付 或 自动勾选京豆支付。 -# 此时下单会要求输入六位数字的支付密码。请在下方配置你的支付密码,如 123456 。 -# 如果没有上述情况,下方请留空。 -payment_pwd = -#暂时不填写 - - -[V2] -# skuids 英文逗号[,]相隔 (分清楚英文和中文逗号) 末尾不要带逗号 -skuids = 3088512,65437208345,7498169,7498165,7263128,7498167,17449572304,37934196731,100001086804,56657322838,56657322841,100005294853,1938795,15595191653,15595191654,45923412989 -# V2版本下单速度区分 极速模式 【1】 和 正常模式 【2】(极速模式缩短不必要的流程) -model = 1 - -[V3] -# v3版本的skuid,最多写一件 -skuid = 3088512 - - -[Temporary] -#一般不需要修改 -eid = -fp = -# 打码服务器 -captchaUrl = http://122.51.18.81:8111/pic \ No newline at end of file diff --git a/jdBuyMask.py b/jdBuyMask.py deleted file mode 100644 index 67461f8..0000000 --- a/jdBuyMask.py +++ /dev/null @@ -1,488 +0,0 @@ -# -*- coding=utf-8 -*- -''' -京东抢购口罩程序 -''' -import requests -import time -import json -import sys -import random -from bs4 import BeautifulSoup -from jdlogger import logger -from message import message -import traceback - -''' -需要修改 -''' -# cookie 网页获取 -cookies_String = 'xxxxxxx' - -# 推送方式 1(mail)或 2(wechat) -messageType = 1 - -# 有货通知 收件邮箱 -mail = 'xxxxxx@qq.com' - -# 方糖微信推送的key 不知道的请看http://sc.ftqq.com/3.version -sc_key = '' - -# 商品的url -urls = [ - # 'https://c0.3.cn/stock?skuId=1336984&area=19_1607_4773_0&venderId=1000078145&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=1580535906442142991701&ch=1&callback=jQuery6715489', - # 'https://c0.3.cn/stock?skuId=4642656&area=19_1607_4773_0&venderId=1000006724&buyNum=1&choseSuitSkuIds=&cat=9192,12190,1517&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=1580535906442142991701&ch=1&callback=jQuery4552086', - # 'https://c0.3.cn/stock?skuId=65466451629&area=19_1607_4773_0&venderId=127922&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=1580535906442142991701&ch=1&callback=jQuery2790674', - # 'https://c0.3.cn/stock?skuId=65437208345&area=19_1607_4773_0&venderId=127922&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=1580535906442142991701&ch=1&callback=jQuery1749958', - # 'https://c0.3.cn/stock?skuId=7498169&area=19_1607_4773_0&venderId=1000128491&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=15631231857651045904648&ch=1&callback=jQuery4102801', - # 'https://c0.3.cn/stock?skuId=7498165&area=19_1607_4773_0&venderId=1000128491&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=15631231857651045904648&ch=1&callback=jQuery9614479', - 'https://c0.3.cn/stock?skuId=7263128&area=19_1607_4773_0&venderId=1000128491&buyNum=1&choseSuitSkuIds=&cat=9855,9858,9924&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=15631231857651045904648&ch=1&callback=jQuery8872960', - # 'https://c0.3.cn/stock?skuId=1739089&area=19_1607_4773_0&venderId=1000017287&buyNum=1&choseSuitSkuIds=&cat=15248,15250,15278&extraParam={%22originid%22:%221%22}&fqsp=0&pdpin=jd_7c3992aa27d1a&pduid=1580535906442142991701&ch=1&callback=jQuery4479703' -] - -''' -备用 -''' - - -# eid -eid = '' -fp = '' -# 支付密码 -payment_pwd = '' -message = message(messageType=messageType, sc_key=sc_key, mail=mail) -session = requests.session() -session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Connection": "keep-alive" -} -manual_cookies = {} - - -def get_tag_value(tag, key='', index=0): - if key: - value = tag[index].get(key) - else: - value = tag[index].text - return value.strip(' \t\r\n') - - -def response_status(resp): - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -for item in cookies_String.split(';'): - name, value = item.strip().split('=', 1) - # 用=号分割,分割1次 - manual_cookies[name] = value - # 为字典cookies添加内容 - -cookiesJar = requests.utils.cookiejar_from_dict(manual_cookies, cookiejar=None, overwrite=True) -session.cookies = cookiesJar - - -def validate_cookies(): - for flag in range(1, 3): - try: - targetURL = 'https://order.jd.com/center/list.action' - payload = { - 'rid': str(int(time.time() * 1000)), - } - resp = session.get(url=targetURL, params=payload, allow_redirects=False) - if resp.status_code == requests.codes.OK: - logger.info('登录成功') - return True - else: - logger.info('第【%s】次请重新获取cookie', flag) - time.sleep(5) - continue - except Exception as e: - logger.info('第【%s】次请重新获取cookie', flag) - time.sleep(5) - continue - - -def getUsername(): - userName_Url = 'https://passport.jd.com/new/helloService.ashx?callback=jQuery339448&_=' + str( - int(time.time() * 1000)) - session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://order.jd.com/center/list.action", - "Connection": "keep-alive" - } - resp = session.get(url=userName_Url, allow_redirects=True) - resultText = resp.text - resultText = resultText.replace('jQuery339448(', '') - resultText = resultText.replace(')', '') - usernameJson = json.loads(resultText) - logger.info('登录账号名称' + usernameJson['nick']) - - -''' -检查是否有货 -''' - - -def check_item_stock(itemUrl): - response = session.get(itemUrl) - if (response.text.find('无货') > 0): - return True - else: - return False - - -''' -取消勾选购物车中的所有商品 -''' - - -def cancel_select_all_cart_item(): - url = "https://cart.jd.com/cancelAllItem.action" - data = { - 't': 0, - 'outSkus': '', - 'random': random.random() - } - resp = session.post(url, data=data) - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -''' -购物车详情 -''' - - -def cart_detail(): - url = 'https://cart.jd.com/cart.action' - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://order.jd.com/center/list.action", - "Host": "cart.jd.com", - "Connection": "keep-alive" - } - resp = session.get(url, headers=headers) - soup = BeautifulSoup(resp.text, "html.parser") - - cart_detail = dict() - for item in soup.find_all(class_='item-item'): - try: - sku_id = item['skuid'] # 商品id - except Exception as e: - logger.info('购物车中有套装商品,跳过') - continue - try: - # 例如:['increment', '8888', '100001071956', '1', '13', '0', '50067652554'] - # ['increment', '8888', '100002404322', '2', '1', '0'] - item_attr_list = item.find(class_='increment')['id'].split('_') - p_type = item_attr_list[4] - promo_id = target_id = item_attr_list[-1] if len(item_attr_list) == 7 else 0 - - cart_detail[sku_id] = { - 'name': get_tag_value(item.select('div.p-name a')), # 商品名称 - 'verder_id': item['venderid'], # 商家id - 'count': int(item['num']), # 数量 - 'unit_price': get_tag_value(item.select('div.p-price strong'))[1:], # 单价 - 'total_price': get_tag_value(item.select('div.p-sum strong'))[1:], # 总价 - 'is_selected': 'item-selected' in item['class'], # 商品是否被勾选 - 'p_type': p_type, - 'target_id': target_id, - 'promo_id': promo_id - } - except Exception as e: - logger.error("商品%s在购物车中的信息无法解析,报错信息: %s,该商品自动忽略", sku_id, e) - - logger.info('购物车信息:%s', cart_detail) - return cart_detail - - -''' -修改购物车商品的数量 -''' - - -def change_item_num_in_cart(sku_id, vender_id, num, p_type, target_id, promo_id): - url = "https://cart.jd.com/changeNum.action" - data = { - 't': 0, - 'venderId': vender_id, - 'pid': sku_id, - 'pcount': num, - 'ptype': p_type, - 'targetId': target_id, - 'promoID': promo_id, - 'outSkus': '', - 'random': random.random(), - # 'locationId' - } - session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://cart.jd.com/cart", - "Connection": "keep-alive" - } - resp = session.post(url, data=data) - return json.loads(resp.text)['sortedWebCartResult']['achieveSevenState'] == 2 - - -''' -添加商品到购物车 -''' - - -def add_item_to_cart(sku_id): - url = 'https://cart.jd.com/gate.action' - payload = { - 'pid': sku_id, - 'pcount': 1, - 'ptype': 1, - } - resp = session.get(url=url, params=payload) - if 'https://cart.jd.com/cart.action' in resp.url: # 套装商品加入购物车后直接跳转到购物车页面 - result = True - else: # 普通商品成功加入购物车后会跳转到提示 "商品已成功加入购物车!" 页面 - soup = BeautifulSoup(resp.text, "html.parser") - result = bool(soup.select('h3.ftx-02')) # [

商品已成功加入购物车!

] - - if result: - logger.info('%s 已成功加入购物车', sku_id) - else: - logger.error('%s 添加到购物车失败', sku_id) - - -def get_checkout_page_detail(): - """获取订单结算页面信息 - - 该方法会返回订单结算页面的详细信息:商品名称、价格、数量、库存状态等。 - - :return: 结算信息 dict - """ - url = 'http://trade.jd.com/shopping/order/getOrderInfo.action' - # url = 'https://cart.jd.com/gotoOrder.action' - payload = { - 'rid': str(int(time.time() * 1000)), - } - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://cart.jd.com/cart.action", - "Connection": "keep-alive", - 'Host': 'trade.jd.com', - } - try: - resp = session.get(url=url, params=payload, headers=headers) - if not response_status(resp): - logger.error('获取订单结算页信息失败') - return '' - - soup = BeautifulSoup(resp.text, "html.parser") - risk_control = get_tag_value(soup.select('input#riskControl'), 'value') - - order_detail = { - 'address': soup.find('span', id='sendAddr').text[5:], # remove '寄送至: ' from the begin - 'receiver': soup.find('span', id='sendMobile').text[4:], # remove '收件人:' from the begin - 'total_price': soup.find('span', id='sumPayPriceId').text[1:], # remove '¥' from the begin - 'items': [] - } - - logger.info("下单信息:%s", order_detail) - return order_detail - except requests.exceptions.RequestException as e: - logger.error('订单结算页面获取异常:%s' % e) - except Exception as e: - logger.error('下单页面数据解析异常:%s', e) - return risk_control - - -def submit_order(risk_control,sku_id): - - - """提交订单 - - 重要: - 1.该方法只适用于普通商品的提交订单(即可以加入购物车,然后结算提交订单的商品) - 2.提交订单时,会对购物车中勾选✓的商品进行结算(如果勾选了多个商品,将会提交成一个订单) - - :return: True/False 订单提交结果 - """ - url = 'https://trade.jd.com/shopping/order/submitOrder.action' - # js function of submit order is included in https://trade.jd.com/shopping/misc/js/order.js?r=2018070403091 - - # overseaPurchaseCookies: - # vendorRemarks: [] - # submitOrderParam.sopNotPutInvoice: false - # submitOrderParam.trackID: TestTrackId - # submitOrderParam.ignorePriceChange: 0 - # submitOrderParam.btSupport: 0 - # riskControl: - # submitOrderParam.isBestCoupon: 1 - # submitOrderParam.jxj: 1 - # submitOrderParam.trackId: - - data = { - 'overseaPurchaseCookies': '', - 'vendorRemarks': '[]', - 'submitOrderParam.sopNotPutInvoice': 'false', - 'submitOrderParam.trackID': 'TestTrackId', - 'submitOrderParam.ignorePriceChange': '0', - 'submitOrderParam.btSupport': '0', - 'riskControl': risk_control, - 'submitOrderParam.isBestCoupon': 1, - 'submitOrderParam.jxj': 1, - 'submitOrderParam.trackId': '9643cbd55bbbe103eef18a213e069eb0', # Todo: need to get trackId - # 'submitOrderParam.eid': eid, - # 'submitOrderParam.fp': fp, - 'submitOrderParam.needCheck': 1, - } - - def encrypt_payment_pwd(payment_pwd): - return ''.join(['u3' + x for x in payment_pwd]) - - if len(payment_pwd) > 0: - data['submitOrderParam.payPassword'] = encrypt_payment_pwd(payment_pwd) - - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", - "Connection": "keep-alive", - 'Host': 'trade.jd.com', - } - for count in range(1, 2): - logger.info('第[%s/%s]次尝试提交订单', count, 3) - try: - resp = session.post(url=url, data=data, headers=headers) - resp_json = json.loads(resp.text) - - # 返回信息示例: - # 下单失败 - # {'overSea': False, 'orderXml': None, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': False, 'resultCode': 60123, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': '请输入支付密码!'} - # {'overSea': False, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'orderXml': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': False, 'resultCode': 60017, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': '您多次提交过快,请稍后再试'} - # {'overSea': False, 'orderXml': None, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': False, 'resultCode': 60077, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': '获取用户订单信息失败'} - # {"cartXml":null,"noStockSkuIds":"xxx","reqInfo":null,"hasJxj":false,"addedServiceList":null,"overSea":false,"orderXml":null,"sign":null,"pin":"xxx","needCheckCode":false,"success":false,"resultCode":600157,"orderId":0,"submitSkuNum":0,"deductMoneyFlag":0,"goJumpOrderCenter":false,"payInfo":null,"scaleSkuInfoListVO":null,"purchaseSkuInfoListVO":null,"noSupportHomeServiceSkuList":null,"msgMobile":null,"addressVO":{"pin":"xxx","areaName":"","provinceId":xx,"cityId":xx,"countyId":xx,"townId":xx,"paymentId":0,"selected":false,"addressDetail":"xx","mobile":"xx","idCard":"","phone":null,"email":null,"selfPickMobile":null,"selfPickPhone":null,"provinceName":null,"cityName":null,"countyName":null,"townName":null,"giftSenderConsigneeName":null,"giftSenderConsigneeMobile":null,"gcLat":0.0,"gcLng":0.0,"coord_type":0,"longitude":0.0,"latitude":0.0,"selfPickOptimize":0,"consigneeId":0,"selectedAddressType":0,"siteType":0,"helpMessage":null,"tipInfo":null,"cabinetAvailable":true,"limitKeyword":0,"specialRemark":null,"siteProvinceId":0,"siteCityId":0,"siteCountyId":0,"siteTownId":0,"skuSupported":false,"addressSupported":0,"isCod":0,"consigneeName":null,"pickVOname":null,"shipmentType":0,"retTag":0,"tagSource":0,"userDefinedTag":null,"newProvinceId":0,"newCityId":0,"newCountyId":0,"newTownId":0,"newProvinceName":null,"newCityName":null,"newCountyName":null,"newTownName":null,"checkLevel":0,"optimizePickID":0,"pickType":0,"dataSign":0,"overseas":0,"areaCode":null,"nameCode":null,"appSelfPickAddress":0,"associatePickId":0,"associateAddressId":0,"appId":null,"encryptText":null,"certNum":null,"used":false,"oldAddress":false,"mapping":false,"addressType":0,"fullAddress":"xxxx","postCode":null,"addressDefault":false,"addressName":null,"selfPickAddressShuntFlag":0,"pickId":0,"pickName":null,"pickVOselected":false,"mapUrl":null,"branchId":0,"canSelected":false,"address":null,"name":"xxx","message":null,"id":0},"msgUuid":null,"message":"xxxxxx商品无货"} - # {'orderXml': None, 'overSea': False, 'noStockSkuIds': 'xxx', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'cartXml': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': False, 'resultCode': 600158, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': {'oldAddress': False, 'mapping': False, 'pin': 'xxx', 'areaName': '', 'provinceId': xx, 'cityId': xx, 'countyId': xx, 'townId': xx, 'paymentId': 0, 'selected': False, 'addressDetail': 'xxxx', 'mobile': 'xxxx', 'idCard': '', 'phone': None, 'email': None, 'selfPickMobile': None, 'selfPickPhone': None, 'provinceName': None, 'cityName': None, 'countyName': None, 'townName': None, 'giftSenderConsigneeName': None, 'giftSenderConsigneeMobile': None, 'gcLat': 0.0, 'gcLng': 0.0, 'coord_type': 0, 'longitude': 0.0, 'latitude': 0.0, 'selfPickOptimize': 0, 'consigneeId': 0, 'selectedAddressType': 0, 'newCityName': None, 'newCountyName': None, 'newTownName': None, 'checkLevel': 0, 'optimizePickID': 0, 'pickType': 0, 'dataSign': 0, 'overseas': 0, 'areaCode': None, 'nameCode': None, 'appSelfPickAddress': 0, 'associatePickId': 0, 'associateAddressId': 0, 'appId': None, 'encryptText': None, 'certNum': None, 'addressType': 0, 'fullAddress': 'xxxx', 'postCode': None, 'addressDefault': False, 'addressName': None, 'selfPickAddressShuntFlag': 0, 'pickId': 0, 'pickName': None, 'pickVOselected': False, 'mapUrl': None, 'branchId': 0, 'canSelected': False, 'siteType': 0, 'helpMessage': None, 'tipInfo': None, 'cabinetAvailable': True, 'limitKeyword': 0, 'specialRemark': None, 'siteProvinceId': 0, 'siteCityId': 0, 'siteCountyId': 0, 'siteTownId': 0, 'skuSupported': False, 'addressSupported': 0, 'isCod': 0, 'consigneeName': None, 'pickVOname': None, 'shipmentType': 0, 'retTag': 0, 'tagSource': 0, 'userDefinedTag': None, 'newProvinceId': 0, 'newCityId': 0, 'newCountyId': 0, 'newTownId': 0, 'newProvinceName': None, 'used': False, 'address': None, 'name': 'xx', 'message': None, 'id': 0}, 'msgUuid': None, 'message': 'xxxxxx商品无货'} - # {"orderXml":null,"cartXml":null,"noStockSkuIds":"","reqInfo":null,"hasJxj":false,"overSea":false,"addedServiceList":null,"sign":null,"pin":null,"needCheckCode":true,"success":false,"resultCode":0,"orderId":0,"submitSkuNum":0,"deductMoneyFlag":0,"goJumpOrderCenter":false,"payInfo":null,"scaleSkuInfoListVO":null,"purchaseSkuInfoListVO":null,"noSupportHomeServiceSkuList":null,"msgMobile":null,"addressVO":null,"msgUuid":null,"message":"验证码不正确,请重新填写"} - # 下单成功 - # {'overSea': False, 'orderXml': None, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': True, 'resultCode': 0, 'orderId': 8740xxxxx, 'submitSkuNum': 1, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': None} - - if resp_json.get('success'): - logger.info('订单提交成功! 订单号:%s', resp_json.get('orderId')) - return True - else: - resultMessage, result_code = resp_json.get('message'), resp_json.get('resultCode') - if result_code == 0: - # self._save_invoice() - if '验证码不正确'in resultMessage: - resultMessage = resultMessage + '(验证码错误)' - else: - resultMessage = resultMessage + '(下单商品可能为第三方商品,将切换为普通发票进行尝试)' - elif result_code == 60077: - resultMessage = resultMessage + '(可能是购物车为空 或 未勾选购物车中商品)' - elif result_code == 60123: - resultMessage = resultMessage + '(需要在payment_pwd参数配置支付密码)' - for i in urls: - if sku_id in i: - urls.remove(i) - logger.info('订单提交失败,避免死循环去除异常id[%s]',sku_id) - logger.info('订单提交失败, 错误码:%s, 返回信息:%s', result_code, resultMessage) - logger.info(resp_json) - return False - except Exception as e: - print(traceback.format_exc()) - continue - - -''' - -''' - - -def item_removed(sku_id): - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", - "Connection": "keep-alive", - 'Host': 'item.jd.com', - } - url = 'https://item.jd.com/{}.html'.format(sku_id) - page = requests.get(url=url, headers=headers) - return '该商品已下柜' not in page.text - - -''' -购买环节 -测试三次 -''' - - -def buyMask(sku_id): - cancel_select_all_cart_item() - cart = cart_detail() - if sku_id in cart: - logger.info('%s 已在购物车中,调整数量为 %s', sku_id, 1) - cart_item = cart.get(sku_id) - change_item_num_in_cart( - sku_id=sku_id, - vender_id=cart_item.get('vender_id'), - num=1, - p_type=cart_item.get('p_type'), - target_id=cart_item.get('target_id'), - promo_id=cart_item.get('promo_id') - ) - else: - add_item_to_cart(sku_id) - risk_control = get_checkout_page_detail() - if len(risk_control) > 0: - if submit_order(risk_control,sku_id): - return True - return False - - -flag = 1 -while (1): - try: - if flag == 1: - validate_cookies() - getUsername() - checkSession = requests.Session() - checkSession.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Connection": "keep-alive" - } - logger.info('第' + str(flag) + '次 ') - flag += 1 - for i in urls: - # 商品url - skuId = i.split('skuId=')[1].split('&')[0] - skuidUrl = 'https://item.jd.com/' + skuId + '.html' - response = checkSession.get(i) - if (response.text.find('无货') > 0): - logger.info('[%s]类型口罩无货', skuId) - else: - if item_removed(skuId): - logger.info('[%s]类型口罩有货啦!马上下单', skuId) - if buyMask(skuId): - message.send(skuidUrl, False) - sys.exit(1) - else: - message.send(skuidUrl, False) - else: - logger.info('[%s]类型口罩有货,但已下柜商品', skuId) - timesleep = random.randint(3, 8) - time.sleep(timesleep) - if flag % 20 == 0: - logger.info('校验是否还在登录') - validate_cookies() - except Exception as e: - - print(traceback.format_exc()) - time.sleep(10) diff --git a/jdBuyMask_V2.py b/jdBuyMask_V2.py deleted file mode 100644 index 2d67f53..0000000 --- a/jdBuyMask_V2.py +++ /dev/null @@ -1,551 +0,0 @@ -# -*- coding=utf-8 -*- -''' -2020/2/13 -(避免滥用,代码已经废弃,现已不更新,有需要请适量使用exe版本) -京东抢购口罩程序 -通过商品的skuid、地区id抢购 -''' -import sys - -import requests -from bs4 import BeautifulSoup - -from config import Config -from jdProgram import * -from message import message -from util import getconfigMd5, _setDNSCache - -global cookies_String, mail, sc_key, messageType, modelType, area, skuidsString, skuids, captchaUrl, eid, fp, payment_pwd - - -def getconfig(): - global cookies_String, mail, sc_key, messageType, modelType, area, skuidsString, skuids, captchaUrl, eid, fp, payment_pwd - global_config = Config() - # cookie 网页获取 - cookies_String = global_config.getRaw('config', 'cookies_String') - # 有货通知 收件邮箱 - mail = global_config.getRaw('config', 'mail') - # 方糖微信推送的key 不知道的请看http://sc.ftqq.com/3.version - sc_key = global_config.getRaw('config', 'sc_key') - # 推送方式 1(mail)或 2(wechat) - messageType = global_config.getRaw('config', 'messageType') - # 下单模式 - modelType = global_config.getRaw('V2', 'model') - # 地区id - area = global_config.getRaw('config', 'area') - # 商品id - skuidsString = global_config.getRaw('V2', 'skuids') - skuids = str(skuidsString).split(',') - # 验证码服务地址 - captchaUrl = global_config.getRaw('Temporary', 'captchaUrl') - if not modelType: - logger.error('请在configDemo.ini文件填写下单model') - - if len(skuids[0]) == 0: - logger.error('请在configDemo.ini文件中输入你的商品id') - sys.exit(1) - ''' - 备用 - ''' - # eid - eid = global_config.getRaw('Temporary', 'eid') - fp = global_config.getRaw('Temporary', 'fp') - # 支付密码 - payment_pwd = global_config.getRaw('config', 'payment_pwd') - - -# 初次 -configTime = int(time.time()) -getconfig() -configMd5 = getconfigMd5() -message = message(messageType=messageType, sc_key=sc_key, mail=mail) - -is_Submit_captcha = False -submit_captcha_rid = '' -submit_captcha_text = '' -encryptClientInfo = '' -submit_Time = 0 -session = requests.session() -session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Connection": "keep-alive" -} -checksession = requests.session() -checksession.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Connection": "keep-alive" -} -manual_cookies = {} - - -def get_tag_value(tag, key='', index=0): - if key: - value = tag[index].get(key) - else: - value = tag[index].text - return value.strip(' \t\r\n') - - -for item in cookies_String.split(';'): - name, value = item.strip().split('=', 1) - # 用=号分割,分割1次 - manual_cookies[name] = value - # 为字典cookies添加内容 - -cookiesJar = requests.utils.cookiejar_from_dict(manual_cookies, cookiejar=None, overwrite=True) -session.cookies = cookiesJar - - -def validate_cookies(): - for flag in range(1, 3): - try: - targetURL = 'https://order.jd.com/center/list.action' - payload = { - 'rid': str(int(time.time() * 1000)), - } - resp = session.get(url=targetURL, params=payload, allow_redirects=False) - if resp.status_code == requests.codes.OK: - logger.info('校验是否登录[成功]') - return True - else: - logger.info('校验是否登录[失败]') - logger.info('请在configDemo.ini文件下更新cookie') - time.sleep(5) - continue - except Exception as e: - logger.info('第【%s】次请重新获取cookie', flag) - time.sleep(5) - continue - message.sendAny('脚本登录cookie失效了,请重新登录') - sys.exit(1) - - -def getUsername(): - userName_Url = 'https://passport.jd.com/new/helloService.ashx?callback=jQuery339448&_=' + str( - int(time.time() * 1000)) - session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://order.jd.com/center/list.action", - "Connection": "keep-alive" - } - resp = session.get(url=userName_Url, allow_redirects=True) - resultText = resp.text - resultText = resultText.replace('jQuery339448(', '') - resultText = resultText.replace(')', '') - usernameJson = json.loads(resultText) - logger.info('登录账号名称[%s]', usernameJson['nick']) - - -''' -检查是否有货 -''' - - -def check_item_stock(itemUrl): - response = session.get(itemUrl) - if (response.text.find('无货') > 0): - return True - else: - return False - - -''' -取消勾选购物车中的所有商品 -''' - - -def cancel_select_all_cart_item(): - url = "https://cart.jd.com/cancelAllItem.action" - data = { - 't': 0, - 'outSkus': '', - 'random': random.random() - } - resp = session.post(url, data=data) - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -''' -购物车详情 -''' - - -def cart_detail(): - url = 'https://cart.jd.com/cart.action' - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://order.jd.com/center/list.action", - "Host": "cart.jd.com", - "Connection": "keep-alive" - } - resp = session.get(url, headers=headers) - soup = BeautifulSoup(resp.text, "html.parser") - - cart_detail = dict() - for item in soup.find_all(class_='item-item'): - try: - sku_id = item['skuid'] # 商品id - except Exception as e: - logger.info('购物车中有套装商品,跳过') - continue - try: - # 例如:['increment', '8888', '100001071956', '1', '13', '0', '50067652554'] - # ['increment', '8888', '100002404322', '2', '1', '0'] - item_attr_list = item.find(class_='increment')['id'].split('_') - p_type = item_attr_list[4] - promo_id = target_id = item_attr_list[-1] if len(item_attr_list) == 7 else 0 - - cart_detail[sku_id] = { - 'name': get_tag_value(item.select('div.p-name a')), # 商品名称 - 'verder_id': item['venderid'], # 商家id - 'count': int(item['num']), # 数量 - 'unit_price': get_tag_value(item.select('div.p-price strong'))[1:], # 单价 - 'total_price': get_tag_value(item.select('div.p-sum strong'))[1:], # 总价 - 'is_selected': 'item-selected' in item['class'], # 商品是否被勾选 - 'p_type': p_type, - 'target_id': target_id, - 'promo_id': promo_id - } - except Exception as e: - logger.error("商品%s在购物车中的信息无法解析,报错信息: %s,该商品自动忽略", sku_id, e) - - logger.info('购物车信息:%s', cart_detail) - return cart_detail - - -''' -修改购物车商品的数量 -''' - - -def change_item_num_in_cart(sku_id, vender_id, num, p_type, target_id, promo_id): - url = "https://cart.jd.com/changeNum.action" - data = { - 't': 0, - 'venderId': vender_id, - 'pid': sku_id, - 'pcount': num, - 'ptype': p_type, - 'targetId': target_id, - 'promoID': promo_id, - 'outSkus': '', - 'random': random.random(), - # 'locationId' - } - session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://cart.jd.com/cart", - "Connection": "keep-alive" - } - resp = session.post(url, data=data) - return json.loads(resp.text)['sortedWebCartResult']['achieveSevenState'] == 2 - - -''' -添加商品到购物车 -''' - - -def add_item_to_cart(sku_id): - url = 'https://cart.jd.com/gate.action' - payload = { - 'pid': sku_id, - 'pcount': 1, - 'ptype': 1, - } - resp = session.get(url=url, params=payload) - if 'https://cart.jd.com/cart.action' in resp.url: # 套装商品加入购物车后直接跳转到购物车页面 - result = True - else: # 普通商品成功加入购物车后会跳转到提示 "商品已成功加入购物车!" 页面 - soup = BeautifulSoup(resp.text, "html.parser") - result = bool(soup.select('h3.ftx-02')) # [

商品已成功加入购物车!

] - - if result: - logger.info('%s 已成功加入购物车', sku_id) - else: - logger.error('%s 添加到购物车失败', sku_id) - - -def get_checkout_page_detail(): - """获取订单结算页面信息 - - 该方法会返回订单结算页面的详细信息:商品名称、价格、数量、库存状态等。 - - :return: 结算信息 dict - """ - url = 'http://trade.jd.com/shopping/order/getOrderInfo.action' - # url = 'https://cart.jd.com/gotoOrder.action' - payload = { - 'rid': str(int(time.time() * 1000)), - } - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://cart.jd.com/cart.action", - "Connection": "keep-alive", - 'Host': 'trade.jd.com', - } - try: - resp = session.get(url=url, params=payload, headers=headers) - if not response_status(resp): - logger.error('获取订单结算页信息失败') - return '' - if '刷新太频繁了' in resp.text: - return '刷新太频繁了' - soup = BeautifulSoup(resp.text, "html.parser") - risk_control = get_tag_value(soup.select('input#riskControl'), 'value') - showCheckCode = get_tag_value(soup.select('input#showCheckCode'), 'value') - if not showCheckCode: - pass - else: - if showCheckCode == 'true': - logger.info('提交订单需要验证码') - global is_Submit_captcha, encryptClientInfo - encryptClientInfo = get_tag_value(soup.select('input#encryptClientInfo'), 'value') - is_Submit_captcha = True - - order_detail = { - 'address': soup.find('span', id='sendAddr').text[5:], # remove '寄送至: ' from the begin - 'receiver': soup.find('span', id='sendMobile').text[4:], # remove '收件人:' from the begin - 'total_price': soup.find('span', id='sumPayPriceId').text[1:], # remove '¥' from the begin - 'items': [] - } - - logger.info("下单信息:%s", order_detail) - return risk_control - except requests.exceptions.RequestException as e: - logger.error('订单结算页面获取异常:%s' % e) - except Exception as e: - logger.error('下单页面数据解析异常:%s', e) - return '' - - -''' -下柜商品检测 -''' - - -def item_removed(sku_id): - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", - "Connection": "keep-alive", - 'Host': 'item.jd.com', - } - url = 'https://item.jd.com/{}.html'.format(sku_id) - page = requests.get(url=url, headers=headers) - return '该商品已下柜' not in page.text - - -''' -购买环节 -测试三次 -''' - - -def normalModeBuyMask(sku_id): - cancel_select_all_cart_item() - cart = cart_detail() - if sku_id in cart: - logger.info('%s 已在购物车中,调整数量为 %s', sku_id, 1) - cart_item = cart.get(sku_id) - change_item_num_in_cart( - sku_id=sku_id, - vender_id=cart_item.get('vender_id'), - num=1, - p_type=cart_item.get('p_type'), - target_id=cart_item.get('target_id'), - promo_id=cart_item.get('promo_id') - ) - else: - add_item_to_cart(sku_id) - risk_control = get_checkout_page_detail() - if risk_control == '刷新太频繁了': - return False - if len(risk_control) > 0: - if submit_order(session, risk_control, sku_id, skuids, submit_Time, encryptClientInfo, is_Submit_captcha, - payment_pwd, submit_captcha_text, submit_captcha_rid): - return True - return False - - -def fastModeBuyMask(sku_id): - add_item_to_cart(sku_id) - risk_control = get_checkout_page_detail() - if risk_control == '刷新太频繁了': - return False - if len(risk_control) > 0: - if submit_order(session, risk_control, sku_id, skuids, submit_Time, encryptClientInfo, is_Submit_captcha, - payment_pwd, submit_captcha_text, submit_captcha_rid): - return True - return False - - -''' -删除购物车选中商品 -''' - - -def remove_item(): - url = "https://cart.jd.com/batchRemoveSkusFromCart.action" - data = { - 't': 0, - 'null': '', - 'outSkus': '', - 'random': random.random(), - 'locationId': '19-1607-4773-0' - } - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.37", - "Accept": "application/json, text/javascript, */*; q=0.01", - "Referer": "https://cart.jd.com/cart.action", - "Host": "cart.jd.com", - "Content-Type": "application/x-www-form-urlencoded", - "Accept-Encoding": "gzip, deflate, br", - "Accept-Encoding": "zh-CN,zh;q=0.9,ja;q=0.8", - "Origin": "https://cart.jd.com", - "Connection": "keep-alive" - } - resp = session.post(url, data=data, headers=headers) - logger.info('清空购物车') - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -def select_all_cart_item(): - url = "https://cart.jd.com/selectAllItem.action" - data = { - 't': 0, - 'outSkus': '', - 'random': random.random() - } - resp = session.post(url, data=data) - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -def normalModeAutoBuy(inStockSkuid): - for skuId in inStockSkuid: - if item_removed(skuId): - global submit_Time - submit_Time = int(time.time() * 1000) - logger.info('[%s]类型口罩有货啦!马上下单', skuId) - skuidUrl = 'https://item.jd.com/' + skuId + '.html' - if normalModeBuyMask(skuId): - message.send(skuidUrl, True) - sys.exit(1) - else: - message.send(skuidUrl, False) - else: - logger.info('[%s]类型口罩有货,但已下柜商品', skuId) - - -def fastModeAutoBuy(inStockSkuid): - for skuId in inStockSkuid: - global submit_Time - submit_Time = int(time.time() * 1000) - logger.info('[%s]类型口罩有货啦!马上下单', skuId) - skuidUrl = 'https://item.jd.com/' + skuId + '.html' - if fastModeBuyMask(skuId): - message.send(skuidUrl, True) - sys.exit(1) - else: - if item_removed(skuId): - message.send(skuidUrl, False) - else: - logger.info('[%s]商品已下柜,商品列表中踢出', skuId) - skuids.remove(skuId) - select_all_cart_item() - remove_item() - - -def check_Config(): - global configMd5, configTime - nowMd5 = getconfigMd5() - configTime = time.time() - if not nowMd5 == configMd5: - logger.info('配置文件修改,重新读取文件') - getconfig() - configMd5 = nowMd5 - - -def normalMode(): - flag = 1 - while (1): - try: - if flag == 1: - validate_cookies() - getUsername() - # 检测配置文件是否修改 - if int(time.time()) - configTime >= 60: - check_Config() - # modelType - logger.info('第' + str(flag) + '次 ') - flag += 1 - # 检测库存 - inStockSkuid = check_stock(checksession, skuids, area) - # 下单任务 - normalModeAutoBuy(inStockSkuid) - # 休眠模块 - timesleep = random.randint(1, 3) / 10 - time.sleep(timesleep) - # 校验是否还在登录模块 - if flag % 100 == 0: - logger.info('校验是否还在登录') - validate_cookies() - except Exception as e: - print(traceback.format_exc()) - time.sleep(10) - - -def fastMode(): - flag = 1 - while (1): - try: - if flag == 1: - validate_cookies() - getUsername() - select_all_cart_item() - remove_item() - # 检测配置文件修改 - if int(time.time()) - configTime >= 600: - check_Config() - # modelType - logger.info('第' + str(flag) + '次 ') - flag += 1 - # 检测库存 - inStockSkuid = check_stock(checksession, skuids, area) - # 下单任务 - fastModeAutoBuy(inStockSkuid) - # 休眠模块 - timesleep = random.randint(1, 3) / 10 - time.sleep(timesleep) - # 校验是否还在登录模块 - if flag % 100 == 0: - logger.info('校验是否还在登录') - validate_cookies() - except Exception as e: - print(traceback.format_exc()) - time.sleep(10) - - -# _setDNSCache() -if modelType == '2': - logger.info('V2版本当前模式[普通模式]') - normalMode() -elif modelType == '1': - logger.info('V2版本当前模式[极速模式]') - fastMode() diff --git a/jdBuyMask_V3.py b/jdBuyMask_V3.py deleted file mode 100644 index 8774464..0000000 --- a/jdBuyMask_V3.py +++ /dev/null @@ -1,492 +0,0 @@ -# -*- coding=utf-8 -*- -''' -2020/2/13 -(避免滥用,代码已经废弃,现已不更新,有需要请适量使用exe版本) -京东抢购口罩程序V3版本 -''' -import sys -import traceback - -from bs4 import BeautifulSoup - -from config import Config -from jdProgram import * -from jdlogger import logger -from message import message -from util import * -from util import _setDNSCache - -''' -需要修改 -''' -global cookies_String, mail, sc_key, messageType, area, skuidsString, skuids, captchaUrl, eid, fp, payment_pwd - - -def getconfig(): - global_config = Config() - global cookies_String, mail, sc_key, messageType, area, skuidsString, skuids, captchaUrl, eid, fp, payment_pwd - # cookie 网页获取 - cookies_String = global_config.getRaw('config', 'cookies_String') - # 有货通知 收件邮箱 - mail = global_config.getRaw('config', 'mail') - # 方糖微信推送的key 不知道的请看http://sc.ftqq.com/3.version - sc_key = global_config.getRaw('config', 'sc_key') - # 推送方式 1(mail)或 2(wechat) - messageType = global_config.getRaw('config', 'messageType') - # 地区id - area = global_config.getRaw('config', 'area') - # 商品id - skuidsString = global_config.getRaw('V3', 'skuid') - skuids = str(skuidsString).split(',') - # 验证码服务地址 - captchaUrl = global_config.getRaw('Temporary', 'captchaUrl') - if len(skuids[0]) == 0: - logger.error('请在configDemo.ini文件中输入你的商品id') - sys.exit(1) - ''' - 备用 - ''' - # eid - eid = global_config.getRaw('Temporary', 'eid') - fp = global_config.getRaw('Temporary', 'fp') - # 支付密码 - payment_pwd = global_config.getRaw('config', 'payment_pwd') - - -# 初次 -configTime = int(time.time()) -getconfig() -configMd5 = getconfigMd5() -message = message(messageType=messageType, sc_key=sc_key, mail=mail) - -is_Submit_captcha = False -submit_captcha_rid = '' -submit_captcha_text = '' -encryptClientInfo = '' -submit_Time = 0 -session = requests.session() -checksession = requests.session() -session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Connection": "keep-alive" -} -checksession.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Connection": "keep-alive" -} -manual_cookies = {} - - -def get_tag_value(tag, key='', index=0): - if key: - value = tag[index].get(key) - else: - value = tag[index].text - return value.strip(' \t\r\n') - - -def response_status(resp): - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -for item in cookies_String.split(';'): - name, value = item.strip().split('=', 1) - # 用=号分割,分割1次 - manual_cookies[name] = value - # 为字典cookies添加内容 - -cookiesJar = requests.utils.cookiejar_from_dict(manual_cookies, cookiejar=None, overwrite=True) -session.cookies = cookiesJar - - -def validate_cookies(): - for flag in range(1, 3): - try: - targetURL = 'https://order.jd.com/center/list.action' - payload = { - 'rid': str(int(time.time() * 1000)), - } - resp = session.get(url=targetURL, params=payload, allow_redirects=False) - if resp.status_code == requests.codes.OK: - logger.info('登录成功') - return True - else: - logger.info('第【%s】次请重新获取cookie', flag) - time.sleep(5) - continue - except Exception as e: - logger.info('第【%s】次请重新获取cookie', flag) - time.sleep(5) - continue - message.sendAny('脚本登录cookie失效了,请重新登录') - sys.exit(1) - - -def getUsername(): - userName_Url = 'https://passport.jd.com/new/helloService.ashx?callback=jQuery339448&_=' + str( - int(time.time() * 1000)) - session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://order.jd.com/center/list.action", - "Connection": "keep-alive" - } - resp = session.get(url=userName_Url, allow_redirects=True) - resultText = resp.text - resultText = resultText.replace('jQuery339448(', '') - resultText = resultText.replace(')', '') - usernameJson = json.loads(resultText) - logger.info('登录账号名称' + usernameJson['nick']) - - -''' -检查是否有货 -''' - - -def check_item_stock(itemUrl): - response = session.get(itemUrl) - if (response.text.find('无货') > 0): - return True - else: - return False - - -''' -取消勾选购物车中的所有商品 -''' - - -def cancel_select_all_cart_item(): - url = "https://cart.jd.com/cancelAllItem.action" - data = { - 't': 0, - 'outSkus': '', - 'random': random.random() - } - resp = session.post(url, data=data) - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -''' -勾选购物车中的所有商品 -''' - - -def select_all_cart_item(): - url = "https://cart.jd.com/selectAllItem.action" - data = { - 't': 0, - 'outSkus': '', - 'random': random.random() - } - resp = session.post(url, data=data) - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -''' -删除购物车选中商品 -''' - - -def remove_item(): - url = "https://cart.jd.com/batchRemoveSkusFromCart.action" - data = { - 't': 0, - 'null': '', - 'outSkus': '', - 'random': random.random(), - 'locationId': '19-1607-4773-0' - } - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.37", - "Accept": "application/json, text/javascript, */*; q=0.01", - "Referer": "https://cart.jd.com/cart.action", - "Host": "cart.jd.com", - "Content-Type": "application/x-www-form-urlencoded", - "Accept-Encoding": "gzip, deflate, br", - "Accept-Encoding": "zh-CN,zh;q=0.9,ja;q=0.8", - "Origin": "https://cart.jd.com", - "Connection": "keep-alive" - } - resp = session.post(url, data=data, headers=headers) - logger.info('清空购物车') - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -''' -购物车详情 -''' - - -def cart_detail(): - url = 'https://cart.jd.com/cart.action' - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://order.jd.com/center/list.action", - "Host": "cart.jd.com", - "Connection": "keep-alive" - } - resp = session.get(url, headers=headers) - soup = BeautifulSoup(resp.text, "html.parser") - - cart_detail = dict() - for item in soup.find_all(class_='item-item'): - try: - sku_id = item['skuid'] # 商品id - except Exception as e: - logger.info('购物车中有套装商品,跳过') - continue - try: - # 例如:['increment', '8888', '100001071956', '1', '13', '0', '50067652554'] - # ['increment', '8888', '100002404322', '2', '1', '0'] - item_attr_list = item.find(class_='increment')['id'].split('_') - p_type = item_attr_list[4] - promo_id = target_id = item_attr_list[-1] if len(item_attr_list) == 7 else 0 - - cart_detail[sku_id] = { - 'name': get_tag_value(item.select('div.p-name a')), # 商品名称 - 'verder_id': item['venderid'], # 商家id - 'count': int(item['num']), # 数量 - 'unit_price': get_tag_value(item.select('div.p-price strong'))[1:], # 单价 - 'total_price': get_tag_value(item.select('div.p-sum strong'))[1:], # 总价 - 'is_selected': 'item-selected' in item['class'], # 商品是否被勾选 - 'p_type': p_type, - 'target_id': target_id, - 'promo_id': promo_id - } - except Exception as e: - logger.error("商品%s在购物车中的信息无法解析,报错信息: %s,该商品自动忽略", sku_id, e) - - logger.info('购物车信息:%s', cart_detail) - return cart_detail - - -''' -修改购物车商品的数量 -''' - - -def change_item_num_in_cart(sku_id, vender_id, num, p_type, target_id, promo_id): - url = "https://cart.jd.com/changeNum.action" - data = { - 't': 0, - 'venderId': vender_id, - 'pid': sku_id, - 'pcount': num, - 'ptype': p_type, - 'targetId': target_id, - 'promoID': promo_id, - 'outSkus': '', - 'random': random.random(), - # 'locationId' - } - session.headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://cart.jd.com/cart", - "Connection": "keep-alive" - } - resp = session.post(url, data=data) - return json.loads(resp.text)['sortedWebCartResult']['achieveSevenState'] == 2 - - -''' -添加商品到购物车 -''' - - -def add_item_to_cart(sku_id): - url = 'https://cart.jd.com/gate.action' - payload = { - 'pid': sku_id, - 'pcount': 1, - 'ptype': 1, - } - resp = session.get(url=url, params=payload) - if 'https://cart.jd.com/cart.action' in resp.url: # 套装商品加入购物车后直接跳转到购物车页面 - result = True - else: # 普通商品成功加入购物车后会跳转到提示 "商品已成功加入购物车!" 页面 - soup = BeautifulSoup(resp.text, "html.parser") - result = bool(soup.select('h3.ftx-02')) # [

商品已成功加入购物车!

] - - if result: - logger.info('%s 已成功加入购物车', sku_id) - else: - logger.error('%s 添加到购物车失败', sku_id) - - -def get_checkout_page_detail(): - """获取订单结算页面信息 - - 该方法会返回订单结算页面的详细信息:商品名称、价格、数量、库存状态等。 - - :return: 结算信息 dict - """ - url = 'http://trade.jd.com/shopping/order/getOrderInfo.action' - # url = 'https://cart.jd.com/gotoOrder.action' - payload = { - 'rid': str(int(time.time() * 1000)), - } - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://cart.jd.com/cart.action", - "Connection": "keep-alive", - 'Host': 'trade.jd.com', - } - try: - resp = session.get(url=url, params=payload, headers=headers) - if not response_status(resp): - logger.error('获取订单结算页信息失败') - return '' - if '刷新太频繁了' in resp.text: - return '刷新太频繁了' - soup = BeautifulSoup(resp.text, "html.parser") - showCheckCode = get_tag_value(soup.select('input#showCheckCode'), 'value') - if not showCheckCode: - pass - else: - if showCheckCode == 'true': - logger.info('提交订单需要验证码') - global is_Submit_captcha, encryptClientInfo - encryptClientInfo = get_tag_value(soup.select('input#encryptClientInfo'), 'value') - is_Submit_captcha = True - risk_control = get_tag_value(soup.select('input#riskControl'), 'value') - - order_detail = { - 'address': soup.find('span', id='sendAddr').text[5:], # remove '寄送至: ' from the begin - 'receiver': soup.find('span', id='sendMobile').text[4:], # remove '收件人:' from the begin - 'total_price': soup.find('span', id='sumPayPriceId').text[1:], # remove '¥' from the begin - 'items': [] - } - - logger.info("下单信息:%s", order_detail) - return risk_control - except requests.exceptions.RequestException as e: - logger.error('订单结算页面获取异常:%s' % e) - except Exception as e: - logger.error('下单页面数据解析异常:%s', e) - return '' - - -''' -商品下柜检测 -''' - - -def item_removed(sku_id): - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", - "Connection": "keep-alive", - 'Host': 'item.jd.com', - } - url = 'https://item.jd.com/{}.html'.format(sku_id) - page = requests.get(url=url, headers=headers) - return '该商品已下柜' not in page.text - - -''' -购买环节 -测试三次 -''' - - -def buyMask(sku_id): - risk_control = get_checkout_page_detail() - if risk_control == '刷新太频繁了': - return False - if len(risk_control) > 0: - if submit_order(session, risk_control, sku_id, skuids, submit_Time, encryptClientInfo, is_Submit_captcha, - payment_pwd, submit_captcha_text, submit_captcha_rid): - return True - - -def V3check(skuId): - select_all_cart_item() - remove_item() - validate_cookies() - logger.info('校验是否还在登录') - add_item_to_cart(skuId) - if not item_removed(skuId): - logger.info('[%s]已下柜商品', skuId) - sys.exit(1) - - -def V3AutoBuy(inStockSkuid): - if skuId in inStockSkuid: - global submit_Time - submit_Time = int(time.time() * 1000) - logger.info('[%s]类型口罩有货啦!马上下单', skuId) - skuidUrl = 'https://item.jd.com/' + skuId + '.html' - if buyMask(skuId): - message.send(skuidUrl, True) - sys.exit(1) - else: - if item_removed(skuId): - message.send(skuidUrl, False) - else: - logger.info('[%s]已下柜商品', skuId) - sys.exit(1) - - -def check_Config(): - global configMd5, configTime - nowMd5 = getconfigMd5() - configTime = time.time() - if not nowMd5 == configMd5: - logger.info('配置文件修改,重新读取文件') - getconfig() - configMd5 = nowMd5 - - -# _setDNSCache() -if len(skuids) != 1: - logger.info('请准备一件商品') -skuId = skuids[0] -flag = 1 -while (1): - try: - # 初始化校验 - if flag == 1: - logger.info('当前是V3版本') - validate_cookies() - getUsername() - select_all_cart_item() - remove_item() - add_item_to_cart(skuId) - # 检测配置文件修改 - if int(time.time()) - configTime >= 60: - check_Config() - logger.info('第' + str(flag) + '次 ') - flag += 1 - # 检查库存模块 - inStockSkuid = check_stock(checksession, skuids, area) - # 自动下单模块 - V3AutoBuy(inStockSkuid) - # 休眠模块 - timesleep = random.randint(1, 3) / 10 - time.sleep(timesleep) - # 校验是否还在登录模块 - if flag % 100 == 0: - V3check(skuId) - except Exception as e: - print(traceback.format_exc()) - time.sleep(10) diff --git a/jdEmail.py b/jdEmail.py deleted file mode 100644 index 292c80f..0000000 --- a/jdEmail.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding=utf-8 -*- -''' -发送邮件模块 -''' -import traceback - - -def sendMail(mail, msgtext): - try: - import smtplib - from email.mime.text import MIMEText - # email 用于构建邮件内容 - from email.header import Header - - # 用于构建邮件头 - # 发信方的信息:发信邮箱,QQ 邮箱授权码 - from_addr = 'jdbuymask@163.com' - password = 'alpsneahcyz123' - - # 收信方邮箱 - to_addr = mail - # 发信服务器 - smtp_server = 'smtp.163.com' - # 邮箱正文内容,第一个参数为内容,第二个参数为格式(plain 为纯文本),第三个参数为编码 - msg = MIMEText(msgtext, 'plain', 'utf-8') - # 邮件头信息 - # msg['From'] = Header(from_addr) - msg['From'] = Header(u'from Mark<{}>'.format(from_addr), 'utf-8') - msg['To'] = Header(to_addr) - msg['Subject'] = Header('京东口罩监控','utf-8') - # 开启发信服务,这里使用的是加密传输 - server = smtplib.SMTP_SSL(host=smtp_server) - server.connect(smtp_server, 465) - # 登录发信邮箱 - server.login(from_addr, password) - # 发送邮件 - server.sendmail(from_addr, to_addr, msg.as_string()) - # 关闭服务器 - server.quit() - except Exception as e: - print(traceback.format_exc()) diff --git a/jdProgram.py b/jdProgram.py deleted file mode 100644 index 780e714..0000000 --- a/jdProgram.py +++ /dev/null @@ -1,219 +0,0 @@ -# -*- coding=utf-8 -*- - -import json -import random -import time -from io import BytesIO - -from PIL import Image - -from jdlogger import logger -from util import parse_json, response_status -import traceback - -''' -2020/2/13 -(避免滥用,代码已经废弃,现已不更新,有需要请适量使用exe版本) -''' -''' -查询库存(旧) -''' - - -def check_stock(checksession, skuids, area): - start = int(time.time() * 1000) - skuidString = ','.join(skuids) - callback = 'jQuery' + str(random.randint(1000000, 9999999)) - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://cart.jd.com/cart.action", - "Connection": "keep-alive", - "Host": "c0.3.cn" - } - # - url = 'https://c0.3.cn/stocks' - payload = { - 'type': 'getstocks', - 'skuIds': skuidString, - 'area': area, - 'callback': callback, - '_': int(time.time() * 1000), - } - resp = checksession.get(url=url, params=payload, headers=headers) - inStockSkuid = [] - nohasSkuid = [] - unUseSkuid = [] - for sku_id, info in parse_json(resp.text).items(): - sku_state = info.get('skuState') # 商品是否上架 - stock_state = info.get('StockState') # 商品库存状态 - if sku_state == 1 and stock_state in (33, 40): - inStockSkuid.append(sku_id) - if sku_state == 0: - unUseSkuid.append(sku_id) - if stock_state == 34: - nohasSkuid.append(sku_id) - logger.info('检测[%s]个口罩有货,[%s]个口罩无货,[%s]个口罩下柜,耗时[%s]ms', len(inStockSkuid), len(nohasSkuid), len(unUseSkuid), - int(time.time() * 1000) - start) - - if len(unUseSkuid) > 0: - logger.info('[%s]口罩已经下柜', ','.join(unUseSkuid)) - return inStockSkuid - - -''' -提交订单 -''' - - -def submit_order(session, risk_control, sku_id, skuids, submit_Time, encryptClientInfo, is_Submit_captcha, payment_pwd, - submit_captcha_text, submit_captcha_rid): - """ - - 重要: - 1.该方法只适用于普通商品的提交订单(即可以加入购物车,然后结算提交订单的商品) - 2.提交订单时,会对购物车中勾选✓的商品进行结算(如果勾选了多个商品,将会提交成一个订单) - - :return: True/False 订单提交结果 - """ - url = 'https://trade.jd.com/shopping/order/submitOrder.action' - # js function of submit order is included in https://trade.jd.com/shopping/misc/js/order.js?r=2018070403091 - - data = { - 'overseaPurchaseCookies': '', - 'vendorRemarks': '[]', - 'submitOrderParam.sopNotPutInvoice': 'false', - 'submitOrderParam.trackID': 'TestTrackId', - 'submitOrderParam.ignorePriceChange': '0', - 'submitOrderParam.btSupport': '0', - 'riskControl': risk_control, - 'submitOrderParam.isBestCoupon': 1, - 'submitOrderParam.jxj': 1, - 'submitOrderParam.trackId': '9643cbd55bbbe103eef18a213e069eb0', # Todo: need to get trackId - # 'submitOrderParam.eid': eid, - # 'submitOrderParam.fp': fp, - 'submitOrderParam.needCheck': 1, - } - - def encrypt_payment_pwd(payment_pwd): - return ''.join(['u3' + x for x in payment_pwd]) - - if len(payment_pwd) > 0: - data['submitOrderParam.payPassword'] = encrypt_payment_pwd(payment_pwd) - - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "http://trade.jd.com/shopping/order/getOrderInfo.action", - "Connection": "keep-alive", - 'Host': 'trade.jd.com', - } - for count in range(1, 3): - logger.info('第[%s/%s]次尝试提交订单', count, 3) - try: - if is_Submit_captcha: - captcha_result = page_detail_captcha(session, encryptClientInfo) - # 验证码服务错误 - if not captcha_result: - logger.error('验证码服务异常') - continue - data['submitOrderParam.checkcodeTxt'] = submit_captcha_text - data['submitOrderParam.checkCodeRid'] = submit_captcha_rid - resp = session.post(url=url, data=data, headers=headers) - resp_json = json.loads(resp.text) - logger.info('本次提交订单耗时[%s]毫秒', str(int(time.time() * 1000) - submit_Time)) - # 返回信息示例: - # 下单失败 - # {'overSea': False, 'orderXml': None, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': False, 'resultCode': 60123, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': '请输入支付密码!'} - # {'overSea': False, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'orderXml': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': False, 'resultCode': 60017, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': '您多次提交过快,请稍后再试'} - # {'overSea': False, 'orderXml': None, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': False, 'resultCode': 60077, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': '获取用户订单信息失败'} - # {"cartXml":null,"noStockSkuIds":"xxx","reqInfo":null,"hasJxj":false,"addedServiceList":null,"overSea":false,"orderXml":null,"sign":null,"pin":"xxx","needCheckCode":false,"success":false,"resultCode":600157,"orderId":0,"submitSkuNum":0,"deductMoneyFlag":0,"goJumpOrderCenter":false,"payInfo":null,"scaleSkuInfoListVO":null,"purchaseSkuInfoListVO":null,"noSupportHomeServiceSkuList":null,"msgMobile":null,"addressVO":{"pin":"xxx","areaName":"","provinceId":xx,"cityId":xx,"countyId":xx,"townId":xx,"paymentId":0,"selected":false,"addressDetail":"xx","mobile":"xx","idCard":"","phone":null,"email":null,"selfPickMobile":null,"selfPickPhone":null,"provinceName":null,"cityName":null,"countyName":null,"townName":null,"giftSenderConsigneeName":null,"giftSenderConsigneeMobile":null,"gcLat":0.0,"gcLng":0.0,"coord_type":0,"longitude":0.0,"latitude":0.0,"selfPickOptimize":0,"consigneeId":0,"selectedAddressType":0,"siteType":0,"helpMessage":null,"tipInfo":null,"cabinetAvailable":true,"limitKeyword":0,"specialRemark":null,"siteProvinceId":0,"siteCityId":0,"siteCountyId":0,"siteTownId":0,"skuSupported":false,"addressSupported":0,"isCod":0,"consigneeName":null,"pickVOname":null,"shipmentType":0,"retTag":0,"tagSource":0,"userDefinedTag":null,"newProvinceId":0,"newCityId":0,"newCountyId":0,"newTownId":0,"newProvinceName":null,"newCityName":null,"newCountyName":null,"newTownName":null,"checkLevel":0,"optimizePickID":0,"pickType":0,"dataSign":0,"overseas":0,"areaCode":null,"nameCode":null,"appSelfPickAddress":0,"associatePickId":0,"associateAddressId":0,"appId":null,"encryptText":null,"certNum":null,"used":false,"oldAddress":false,"mapping":false,"addressType":0,"fullAddress":"xxxx","postCode":null,"addressDefault":false,"addressName":null,"selfPickAddressShuntFlag":0,"pickId":0,"pickName":null,"pickVOselected":false,"mapUrl":null,"branchId":0,"canSelected":false,"address":null,"name":"xxx","message":null,"id":0},"msgUuid":null,"message":"xxxxxx商品无货"} - # {'orderXml': None, 'overSea': False, 'noStockSkuIds': 'xxx', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'cartXml': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': False, 'resultCode': 600158, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': {'oldAddress': False, 'mapping': False, 'pin': 'xxx', 'areaName': '', 'provinceId': xx, 'cityId': xx, 'countyId': xx, 'townId': xx, 'paymentId': 0, 'selected': False, 'addressDetail': 'xxxx', 'mobile': 'xxxx', 'idCard': '', 'phone': None, 'email': None, 'selfPickMobile': None, 'selfPickPhone': None, 'provinceName': None, 'cityName': None, 'countyName': None, 'townName': None, 'giftSenderConsigneeName': None, 'giftSenderConsigneeMobile': None, 'gcLat': 0.0, 'gcLng': 0.0, 'coord_type': 0, 'longitude': 0.0, 'latitude': 0.0, 'selfPickOptimize': 0, 'consigneeId': 0, 'selectedAddressType': 0, 'newCityName': None, 'newCountyName': None, 'newTownName': None, 'checkLevel': 0, 'optimizePickID': 0, 'pickType': 0, 'dataSign': 0, 'overseas': 0, 'areaCode': None, 'nameCode': None, 'appSelfPickAddress': 0, 'associatePickId': 0, 'associateAddressId': 0, 'appId': None, 'encryptText': None, 'certNum': None, 'addressType': 0, 'fullAddress': 'xxxx', 'postCode': None, 'addressDefault': False, 'addressName': None, 'selfPickAddressShuntFlag': 0, 'pickId': 0, 'pickName': None, 'pickVOselected': False, 'mapUrl': None, 'branchId': 0, 'canSelected': False, 'siteType': 0, 'helpMessage': None, 'tipInfo': None, 'cabinetAvailable': True, 'limitKeyword': 0, 'specialRemark': None, 'siteProvinceId': 0, 'siteCityId': 0, 'siteCountyId': 0, 'siteTownId': 0, 'skuSupported': False, 'addressSupported': 0, 'isCod': 0, 'consigneeName': None, 'pickVOname': None, 'shipmentType': 0, 'retTag': 0, 'tagSource': 0, 'userDefinedTag': None, 'newProvinceId': 0, 'newCityId': 0, 'newCountyId': 0, 'newTownId': 0, 'newProvinceName': None, 'used': False, 'address': None, 'name': 'xx', 'message': None, 'id': 0}, 'msgUuid': None, 'message': 'xxxxxx商品无货'} - # {"orderXml":null,"cartXml":null,"noStockSkuIds":"","reqInfo":null,"hasJxj":false,"overSea":false,"addedServiceList":null,"sign":null,"pin":null,"needCheckCode":true,"success":false,"resultCode":0,"orderId":0,"submitSkuNum":0,"deductMoneyFlag":0,"goJumpOrderCenter":false,"payInfo":null,"scaleSkuInfoListVO":null,"purchaseSkuInfoListVO":null,"noSupportHomeServiceSkuList":null,"msgMobile":null,"addressVO":null,"msgUuid":null,"message":"验证码不正确,请重新填写"} - # {'overSea': False, 'orderXml': None, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'sign': None, 'pin': 'jd_7c3992aa27d1a', 'needCheckCode': False, 'success': False, 'resultCode': 60070, 'orderId': 0, 'submitSkuNum': 0, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': '抱歉,您当前选择的省份无法购买商品星工 KN95口罩防雾霾防尘防花粉PM2.5 硅胶鼻垫带阀耳戴透气 工业粉尘防护口罩 白色25只独立包装'} - # 下单成功 - # {'overSea': False, 'orderXml': None, 'cartXml': None, 'noStockSkuIds': '', 'reqInfo': None, 'hasJxj': False, 'addedServiceList': None, 'sign': None, 'pin': 'xxx', 'needCheckCode': False, 'success': True, 'resultCode': 0, 'orderId': 8740xxxxx, 'submitSkuNum': 1, 'deductMoneyFlag': 0, 'goJumpOrderCenter': False, 'payInfo': None, 'scaleSkuInfoListVO': None, 'purchaseSkuInfoListVO': None, 'noSupportHomeServiceSkuList': None, 'msgMobile': None, 'addressVO': None, 'msgUuid': None, 'message': None} - if resp_json.get('success'): - logger.info('订单提交成功! 订单号:%s', resp_json.get('orderId')) - return True - else: - resultMessage, result_code = resp_json.get('message'), resp_json.get('resultCode') - if result_code == 0: - # self._save_invoice() - if '验证码不正确' in resultMessage: - resultMessage = resultMessage + '(验证码错误)' - logger.info('提交订单验证码[错误]') - continue - else: - resultMessage = resultMessage + '(下单商品可能为第三方商品,将切换为普通发票进行尝试)' - elif result_code == 60077: - resultMessage = resultMessage + '(可能是购物车为空 或 未勾选购物车中商品)' - elif result_code == 60123: - resultMessage = resultMessage + '(需要在payment_pwd参数配置支付密码)' - elif result_code == 60070: - resultMessage = resultMessage + '(省份不支持销售)' - skuids.remove(sku_id) - logger.info('[%s]类型口罩不支持销售踢出', sku_id) - logger.info('订单提交失败, 错误码:%s, 返回信息:%s', result_code, resultMessage) - logger.info(resp_json) - return False - except Exception as e: - print(traceback.format_exc()) - continue - - -''' -订单页面验证码 -''' - - -def page_detail_captcha(session, isId): - url = 'https://captcha.jd.com/verify/image' - acid = '{}_{}'.format(random.random(), random.random()) - payload = { - 'acid': acid, - 'srcid': 'trackWeb', - 'is': isId, - } - headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/531.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "Referer": "https://trade.jd.com/shopping/order/getOrderInfo.action", - "Connection": "keep-alive", - 'Host': 'captcha.jd.com', - } - try: - resp = session.get(url=url, params=payload, headers=headers) - if not response_status(resp): - logger.error('获取订单验证码失败') - return '' - logger.info('解析验证码开始') - image = Image.open(BytesIO(resp.content)) - image.save('captcha.jpg') - result = analysis_captcha(resp.content) - if not result: - logger.error('解析订单验证码失败') - return '' - global submit_captcha_text, submit_captcha_rid - submit_captcha_text = result - submit_captcha_rid = acid - return result - except Exception as e: - logger.error('订单验证码获取异常:%s', e) - return '' - - -def analysis_captcha(session, captchaUrl, pic): - for i in range(1, 10): - try: - url = captchaUrl - resp = session.post(url, pic) - if not response_status(resp): - logger.error('解析验证码失败') - continue - logger.info('解析验证码[%s]', resp.text) - return resp.text - except Exception as e: - print(traceback.format_exc()) - continue - return '' diff --git a/jdlogger.py b/jdlogger.py deleted file mode 100644 index d8c5f17..0000000 --- a/jdlogger.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding=utf-8 -*- -import logging -import logging.handlers -''' -日志模块 -''' -LOG_FILENAME = 'jdBuyMask.log' - -logger = logging.getLogger() - - -def set_logger(): - logger.setLevel(logging.INFO) - formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s') - - console_handler = logging.StreamHandler() - console_handler.setFormatter(formatter) - logger.addHandler(console_handler) - - file_handler = logging.handlers.RotatingFileHandler( - LOG_FILENAME, maxBytes=10485760, backupCount=5, encoding="utf-8") - file_handler.setFormatter(formatter) - logger.addHandler(file_handler) - - -set_logger() diff --git a/message.py b/message.py deleted file mode 100644 index bc4faac..0000000 --- a/message.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- encoding=utf8 -*- -from jdEmail import sendMail -from wechat_ftqq import sendWechat - - -class message(object): - """消息推送类""" - - def __init__(self, messageType, sc_key, mail): - if messageType == '2': - if not sc_key: - raise Exception('sc_key can not be empty') - self.sc_key = sc_key - elif messageType == '1': - if not mail: - raise Exception('mail can not be empty') - self.mail = mail - self.messageType = messageType - - def send(self, desp='', isOrder=False): - desp = str(desp) - if isOrder: - msg = desp + ' 类型口罩,已经下单了。24小时内付款' - else: - msg = desp + ' 类型口罩,下单失败了' - if self.messageType == '1': - sendMail(self.mail, msg) - if self.messageType == '2': - sendWechat(sc_key=self.sc_key, desp=msg) - - def sendAny(self, desp=''): - desp = str(desp) - msg = desp - if self.messageType == '1': - sendMail(self.mail, msg) - if self.messageType == '2': - sendWechat(sc_key=self.sc_key, desp=msg) diff --git a/util.py b/util.py deleted file mode 100644 index 2761aab..0000000 --- a/util.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding=utf-8 -*- -import hashlib -import json -import socket -import requests - -_dnscache = {} - -def parse_json(s): - begin = s.find('{') - end = s.rfind('}') + 1 - return json.loads(s[begin:end]) - - -def getconfigMd5(): - with open('configDemo.ini', 'r', encoding='utf-8') as f: - configText = f.read() - return hashlib.md5(configText.encode('utf-8')).hexdigest() - -def response_status(resp): - if resp.status_code != requests.codes.OK: - print('Status: %u, Url: %s' % (resp.status_code, resp.url)) - return False - return True - - -def _setDNSCache(): - """ - Makes a cached version of socket._getaddrinfo to avoid subsequent DNS requests. - """ - - def _getaddrinfo(*args, **kwargs): - global _dnscache - if args in _dnscache: - # print(str(args) + " in cache") - return _dnscache[args] - - else: - # print(str(args) + " not in cache") - _dnscache[args] = socket._getaddrinfo(*args, **kwargs) - return _dnscache[args] - - if not hasattr(socket, '_getaddrinfo'): - socket._getaddrinfo = socket.getaddrinfo - socket.getaddrinfo = _getaddrinfo diff --git a/wechat_ftqq.py b/wechat_ftqq.py deleted file mode 100644 index 55cb00f..0000000 --- a/wechat_ftqq.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- encoding=utf8 -*- -import datetime -import json - -import requests - -from jdlogger import logger - - -def sendWechat(sc_key, text='京东商品监控', desp=''): - if not text.strip(): - logger.error('Text of message is empty!') - return - - now_time = str(datetime.datetime.now()) - desp = '[{0}]'.format(now_time) if not desp else '{0} [{1}]'.format(desp, now_time) - - try: - resp = requests.get( - 'https://sc.ftqq.com/{}.send?text={}&desp={}'.format(sc_key, text, desp) - ) - resp_json = json.loads(resp.text) - if resp_json.get('errno') == 0: - logger.info('Message sent successfully [text: %s, desp: %s]', text, desp) - else: - logger.error('Fail to send message, reason: %s', resp.text) - except requests.exceptions.RequestException as req_error: - logger.error('Request error: %s', req_error) - except Exception as e: - logger.error('Fail to send message [text: %s, desp: %s]: %s', text, desp, e) -- GitLab