first commit

This commit is contained in:
danial
2025-03-21 00:17:37 +08:00
commit 80d934b3c6
22 changed files with 678 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

14
.idea/deployment.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData">
<serverData>
<paths name="root@120.24.83.163:22 password">
<serverdata>
<mappings>
<mapping local="$PROJECT_DIR$" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
</component>
</project>

View File

@@ -0,0 +1,23 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="9">
<item index="0" class="java.lang.String" itemvalue="uwsgi" />
<item index="1" class="java.lang.String" itemvalue="opencv-python" />
<item index="2" class="java.lang.String" itemvalue="opencv-python-headless" />
<item index="3" class="java.lang.String" itemvalue="pyexecjs" />
<item index="4" class="java.lang.String" itemvalue="gevent" />
<item index="5" class="java.lang.String" itemvalue="gunicorn" />
<item index="6" class="java.lang.String" itemvalue="selenium" />
<item index="7" class="java.lang.String" itemvalue="urllib3" />
<item index="8" class="java.lang.String" itemvalue="redis" />
</list>
</value>
</option>
</inspection_tool>
</profile>
</component>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (walmart_bind) (2)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/walmart_bind.iml" filepath="$PROJECT_DIR$/.idea/walmart_bind.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

19
.idea/walmart_bind.iml generated Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="Flask">
<option name="enabled" value="true" />
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.8 (walmart_bind) (2)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/../walmart_bind\templates" />
</list>
</option>
</component>
</module>

26
Dockerfile Normal file
View File

@@ -0,0 +1,26 @@
# 基于 Python 3.8.6 镜像
FROM python:3.8.6
# 修改apt-get源地址为阿里云镜像
RUN echo "" > /etc/apt/sources.list && \
echo "deb http://mirrors.aliyun.com/debian buster main" >> /etc/apt/sources.list && \
echo "deb http://mirrors.aliyun.com/debian-security buster/updates main" >> /etc/apt/sources.list && \
echo "deb http://mirrors.aliyun.com/debian buster-updates main" >> /etc/apt/sources.list
# 复制项目
ADD . /app
# 设置工作目录
WORKDIR /app
# 暴露容器端口
EXPOSE 5009
# python环境包
RUN pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple gunicorn gevent
RUN pip3 install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
ENV FLASK_APP=app.py
# 运行Django应用
CMD ["gunicorn", "-c", "gun.conf", "app:app"]

1
README.md Normal file
View File

@@ -0,0 +1 @@
docker run --name walmart_bind -p 5008:5008 -v /home/www/walmart_bind:/app -d walmart_bind

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

47
app.py Normal file
View File

@@ -0,0 +1,47 @@
import json
import logging
from logging.handlers import TimedRotatingFileHandler
from flask import Flask, request
from flask_cors import CORS
from spiders import WalMartCardSpider
app = Flask(__name__)
# 跨域
CORS(app)
# 设置日志记录级别,可以根据需要调整
app.logger.setLevel(logging.INFO)
# 创建按天滚动的日志处理程序
log_file = 'walmart_bind.log'
handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=7, encoding="utf-8")
handler.suffix = '%Y-%m-%d.log' # 日志文件名的后缀格式,这里按日期命名
handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
app.logger.addHandler(handler)
@app.route('/walmart/bind/card', methods=['GET', 'POST'], strict_slashes=False)
def hello_world():
if request.method == 'GET':
return 'okk'
elif request.method == 'POST':
# 接收参数
data = json.loads(request.get_data())
card_num = data.get("card_num")
cookies = data.get("cookies")
card_pwd = data.get("card_pwd")
order_num = data.get("order_num")
# 日志打印
app.logger.info(f"订单ID{order_num},请求参数:{data}")
res = WalMartCardSpider(
cookies=cookies,
card_num=card_num,
card_pwd=card_pwd,
order_num=order_num,
app=app
).run()
return res
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5009)

70
check_money.py Normal file
View File

@@ -0,0 +1,70 @@
import hashlib
import json
import time
import requests
class CheckMoney:
def __init__(self, cookies):
self.cookies = cookies
self.url = "https://apicard.swiftpass.cn/app/card/mem/more/consume.json"
def md5_encrypt(self, data):
# 创建 MD5 哈希对象
md5_hash = hashlib.md5()
# 更新哈希对象以包含数据
md5_hash.update(data.encode('utf-8')) # 确保数据为字节类型
# 返回十六进制表示的大写 MD5 值
return md5_hash.hexdigest().upper()
def query_balance(self):
timestamp = f"{int(time.time() * 1000)}"
data = '{"bizType":2,"currentPage":0,"pageSize":0,"sign":"%s"}%saab23c732038417795a0f5caf70899b7' % (
self.cookies, timestamp
)
signature = self.md5_encrypt(data)
headers = {
"Host": "apicard.swiftpass.cn",
"version": "16",
"timestamp": f"{timestamp}",
"signature": signature,
"xweb_xhr": "1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090c2d)XWEB/11581",
"content-type": "application/json",
"accept": "*/*",
"sec-fetch-site": "cross-site",
"sec-fetch-mode": "cors",
"sec-fetch-dest": "empty",
"referer": "https://servicewechat.com/wx81d3e1fe4c2e11b4/158/page-frame.html",
"accept-language": "zh-CN,zh;q=0.9"
}
data = {
"bizType": 2,
"currentPage": 0,
"pageSize": 0,
"sign": self.cookies
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(self.url, headers=headers, data=data)
return response.json()
def run(self):
res = self.query_balance()
print(res)
balance = res["data"]["balanceCnt"]
return {
"code": 100,
"data": {
"balance": balance
}
}
if __name__ == '__main__':
cookies = "5761d1dfeea1422990c7f0dace26dcd8@853540263801a118ff85ec686f23bbd7"
res = CheckMoney(
cookies=cookies
).run()
print(res)

19
gun.conf Normal file
View File

@@ -0,0 +1,19 @@
# 并行工作进程数
workers = 2
# 指定每个工作者的线程数
threads = 4
# 监听内网端口80
bind = '0.0.0.0:5009'
# 工作模式协程
worker_class = 'gevent'
# 设置最大并发量
worker_connections = 2000
# 设置进程文件目录
pidfile = 'gunicorn.pid'
# 设置访问日志和错误信息日志路径
accesslog = '-'
errorlog = '-'
# 设置日志记录水平
loglevel = 'info'
# 代码发生变化是否自动重启
reload = True

1
gunicorn.pid Normal file
View File

@@ -0,0 +1 @@
1

29
logger.py Normal file
View File

@@ -0,0 +1,29 @@
from loguru import logger
import sys
import pytz
from datetime import datetime
# 移除默认的日志处理器
logger.remove()
# 设置中国时区
china_tz = pytz.timezone("Asia/Shanghai")
# 自定义时间格式函数
def custom_time():
return datetime.now(china_tz).strftime("%Y-%m-%d %H:%M:%S")
# 添加新的处理器,输出到控制台
logger.add(sys.stdout, format="{time:YYYY-MM-DD HH:mm:ss} {level} {message}", level="INFO", serialize=False)
# 添加文件日志处理器
logger.add("walmart.log", rotation="20 MB", retention="30 days", format="{time:YYYY-MM-DD HH:mm:ss} {level} {message}")
# 创建一个带有时间信息的 Logger
logger = logger.bind(time=custom_time())
def get_logger():
return logger

5
requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
flask==3.0.3
flask_cors==4.0.1
requests==2.32.3
urllib3==1.26.2
redis==5.0.7

387
spiders.py Normal file
View File

@@ -0,0 +1,387 @@
import datetime
import hashlib
import json
import random
import time
from json import JSONDecodeError
import requests
import urllib3
import traceback
from logger import get_logger
logger = get_logger()
ANDROID_USER_AGENT = [
"Mozilla/5.0 (Linux; U; Android 1.5; en-us; sdk Build/CUPCAKE) AppleWebkit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 1.5; en-us; htc_bahamas Build/CRB17) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 2.1-update1; de-de; HTC Desire 1.19.161.5 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 1.5; de-ch; HTC Hero Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; ADR6300 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 2.1; en-us; HTC Legend Build/cupcake) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 1.5; de-de; HTC Magic Build/PLAT-RC33) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 FirePHP/0.3",
"Mozilla/5.0 (Linux; U; Android 1.6; en-us; HTC_TATTOO_A3288 Build/DRC79) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
"Mozilla/5.0 (Linux; U; Android 1.5; en-us; T-Mobile G1 Build/CRB43) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari 525.20.1",
"Mozilla/5.0 (Linux; U; Android 1.5; en-gb; T-Mobile_G2_Touch Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 2.0; en-us; Droid Build/ESD20) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; Droid Build/FRG22D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 2.0; en-us; Milestone Build/ SHOLS_U2_01.03.1) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.0.1; de-de; Milestone Build/SHOLS_U2_01.14.0) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
"Mozilla/5.0 (Linux; U; Android 0.5; en-us) AppleWebKit/522 (KHTML, like Gecko) Safari/419.3",
"Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
"Mozilla/5.0 (Linux; U; Android 2.0; en-us; Droid Build/ESD20) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 2.2; en-us; ADR6300 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 2.2; en-ca; GT-P1000M Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"Mozilla/5.0 (Linux; U; Android 3.0.1; fr-fr; A500 Build/HRI66) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
"Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
"Mozilla/5.0 (Linux; U; Android 1.6; es-es; SonyEricssonX10i Build/R1FA016) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
"Mozilla/5.0 (Linux; U; Android 1.6; en-us; SonyEricssonX10i Build/R1AA056) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
]
# 忽略InsecureRequestWarning警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class WalMartCardSpider:
def __init__(self, cookies, card_num, card_pwd, order_num, app):
self.app = app
# 接收参数
self.cookies = cookies
self.card_num = card_num
self.card_pwd = card_pwd
self.order_num = order_num
# 请求超时
self.timeout = 3
self.bind_timeout = 60
self.user_agent = random.choice(ANDROID_USER_AGENT)
# 初始化开始滑块验证时间
self.start_timestamp = int(time.time() * 1000)
current_time = datetime.datetime.utcnow()
self.start_formatted_time = current_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
# 日志存储
self.log_list = []
# 执行记录存储
self.record_list = []
# 备注
self.remarks = ""
self.session = requests.Session()
# 请求超时时间设置
self.timeout = 3.5
def format_number(self, number):
if not number:
number = 0
number = float(number)
formatted_number = "{:.2f}".format(number)
return formatted_number
def md5_encrypt(self, data):
# 创建 MD5 哈希对象
md5_hash = hashlib.md5()
# 更新哈希对象以包含数据
md5_hash.update(data.encode('utf-8')) # 确保数据为字节类型
# 返回十六进制表示的大写 MD5 值
return md5_hash.hexdigest().upper()
def walmart_bind_card(self):
"""
/* 绑定成功 {"logId":"qZXePbHl","status":true,"error":{"errorcode":1,"message":null,"redirect":null,"validators":null},"data":"59519706"}
* 错误密码 {"logId":"IQwPkfLT","status":false,"error":{"errorcode":19000,"message":"校验密码失败密码错误次数1","redirect":null,"validators":null},"data":null}
* 重复绑定 {"logId":"Dj6nJ4OM","status":false,"error":{"errorcode":10131,"message":"该电子卡已被其他用户绑定","redirect":null,"validators":null},"data":null}
* 错误卡号/卡密 {"logId":"hX6Ju6lD","status":false,"error":{"errorcode":19000,"message":"无权操作该卡","redirect":null,"validators":null},"data":null}
* 登录失效 {"logId":"V0Sw4Q2f","status":false,"error":{"errorcode":203,"message":"请先去登录","redirect":null,"validators":null},"data":null}
* 错误密码 {"logId":"Aavc0ch1","status":false,"error":{"errorcode":201,"message":"密码输入有误","redirect":null,"validators":null},"data":null}
* 密码输入错误次数过多 {"logId":"bchMZcyv","status":false,"error":{"errorcode":110136,"message":"密码输入错误次数过多","redirect":null,"validators":null},"data":null}
* 校验密码失败密码错误次数2 {"logId":"MDN05jVd","status":false,"error":{"errorcode":19000,"message":"校验密码失败密码错误次数2","redirect":null,"validators":null},"data":null}
* {"logId":"tP0TWGY8","status":false,"error":{"errorcode":110224,"message":"您绑卡已超过单日20张限制请明天再试","redirect":null,"validators":null},"data":null}
* {'logId': 'Ff4eK7Bu', 'status': False, 'error': {'errorcode': 110134, 'message': '错误次数过多,请稍后再试', 'redirect': None, 'validators': None}, 'data': None}
*/
:return:
"""
try:
user_info = self.cookies.split("#")
if len(user_info) != 3:
self.set_record(f"ck失效格式不正确")
return 113
sign = user_info[0]
user_key = user_info[1]
version = user_info[2]
timestamp = f"{int(time.time() * 1000)}"
data = '{"cardNo":"%s","cardPwd":"%s","currentPage":0,"pageSize":0,"sign":"%s","storeId":"","userPhone":""}%s%s' % (
self.card_num, self.card_pwd, sign, timestamp, user_key
)
signature = self.md5_encrypt(data)
headers = {
"authority": "apicard.swiftpass.cn",
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"content-type": "application/json",
"referer": "https://servicewechat.com/wx81d3e1fe4c2e11b4/159/page-frame.html",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
"signature": signature,
"timestamp": timestamp,
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) XWEB/8555",
"xweb_xhr": "1",
"version": version
}
url = "https://apicard.swiftpass.cn/app/card/mem/bind.json"
data = {
"cardNo": self.card_num,
"cardPwd": self.card_pwd,
"currentPage": 0,
"pageSize": 0,
"sign": sign,
"storeId": "",
"userPhone": ""
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(url, headers=headers, data=data)
res = response.json()
self.app.logger.info(f"订单ID: {self.order_num},请求绑卡返回:{res}")
logger.info(f"订单ID: {self.order_num},请求绑卡返回:{res}")
self.remarks = res.get("error", {}).get("message", "")
if res.get("error").get("errorcode") == 1:
self.set_record(f"绑定成功")
return 100
elif res.get("error").get("errorcode") == 203:
self.set_record(f"ck失效")
return 113
elif res.get("error").get("errorcode") == 5041:
self.set_record(f"请重新获取ck开放平台迁移小程序跳转公众号同步unionid")
return 113
elif res.get("error").get("errorcode") == 10131:
self.set_record(f"该电子卡已被其他用户绑定")
return 104
elif res.get("error").get("errorcode") == 110400:
self.set_record("操作频繁,请稍后重试")
return 115
elif res.get("error").get("errorcode") == 19000 and "校验密码失败" in res.get("error").get("message"):
self.set_record(f"校验密码失败")
return 105
elif res.get("error").get("errorcode") == 19000 and "无权操作该卡" in res.get("error").get("message"):
self.set_record(f"无权操作该卡")
return 105
elif res.get("error").get("errorcode") == 19000 and "该卡已被绑定" in res.get("error").get("message"):
self.set_record(f"同一张实体卡只允许绑定到一个微信账户或山姆APP礼品卡账户该卡已被绑定")
return 104
elif res.get("error").get("errorcode") == 19000 and "重复提交" in res.get("error").get("message"):
self.set_record(f"重复提交")
return 110
elif res.get("error").get("errorcode") == 201:
self.set_record(f"密码输入有误")
return 105
elif res.get("error").get("errorcode") == 110136:
self.set_record(f"密码输入错误次数过多")
return 105
elif res.get("error").get("errorcode") == 110224:
self.set_record(f"您绑卡已超过单日20张限制请明天再试")
return 116
elif res.get("error").get("errorcode") == 110134:
self.set_record(f"错误次数过多,请稍后再试")
return 115
else:
self.set_record(f"存在未知状态")
return 111
except Exception as e:
self.log_list.append(f"订单ID: {self.order_num},绑卡异常报错:{str(e)}")
return 111
def get_params(self):
headers = {
"language": "CN",
"system-language": "CN",
"Content-Type": "application/json",
"device-type": "android",
"tpg": "1",
"app-version": "5.0.98",
"device-id": "",
"device-os-version": "9",
"device-name": "samsung_SM-N9760",
"treq-id": "35cbc67b3bdb42238e97214e4bb371ad.515.17270811912489411",
"auth-token": self.cookies,
"longitude": "113.412697",
"latitude": "23.10594",
"p": "1656120205",
"t": "1727080982681",
"n": "b233a136c3484043a022dc935684491a",
"sy": "0",
"st": "a2f3a3427f7391aa470bca22cfe52177",
"sny": "c",
# "rcs": "2",
"spv": "1.1",
"Local-Longitude": "0.0",
"Local-Latitude": "0.0",
"zoneType": "1",
"Host": "api-sams.walmartmobile.cn",
"User-Agent": "okhttp/4.8.1"
}
url = "https://api-sams.walmartmobile.cn/api/v1/sams/sams-user/tool/yinshang/request_param"
response = self.session.get(url, headers=headers, verify=False, timeout=self.timeout)
self.app.logger.info(f"订单ID: {self.order_num}获取app打开沃尔玛绑卡页面参数{response.text}")
logger.info(f"订单ID: {self.order_num}获取app打开沃尔玛绑卡页面参数{response.text}")
print(f"订单ID: {self.order_num}获取app打开沃尔玛绑卡页面参数{response.text}")
res = response.json()
if res.get("code") != "Success":
return "01"
params = res["data"]["params"]
params = dict(item.split("=") for item in params.split("&"))
return params
def get_session_id(self, params):
url = "https://vpay.upcard.com.cn/vcweixin/mwalm/loginmwalmmenu"
headers = {
"Host": "vpay.upcard.com.cn",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Linux; Android 9; SM-N9760 Build/PQ3B.190801.06281543; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Mobile Safari/537.36SR-SAMS/5.0.98",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"X-Requested-With": "cn.samsclub.app",
"Sec-Fetch-Site": "none",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
}
res = self.session.get(url, headers=headers, params=params, verify=False, timeout=self.timeout)
cookies = res.cookies.get_dict()
print(f"订单ID: {self.order_num}获取JSESSIONID{cookies}")
self.app.logger.info(f"订单ID: {self.order_num}获取JSESSIONID{cookies}")
logger.info(f"订单ID: {self.order_num}获取JSESSIONID{cookies}")
return cookies
def sanmu_bind_card(self):
for i in range(5):
try:
if len(self.cookies) > 50:
try:
params = self.get_params()
except JSONDecodeError as e:
self.remarks = "请求频繁,跳转至错误页面,请稍后重试"
self.set_record(f"请求频繁")
return 115
if params == "01":
self.set_record(f"ck失效")
return 113
cookies = self.get_session_id(params)
else:
cookies = {
"JSESSIONID": self.cookies,
"route": ""
}
headers = {
"Host": "vpay.upcard.com.cn",
"Accept": "application/json, text/javascript, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest",
"User-Agent": "Mozilla/5.0 (Linux; Android 9; SM-N9760 Build/PQ3B.190801.06281543; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Mobile Safari/537.36SR-SAMS/5.0.98",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://vpay.upcard.com.cn",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Dest": "empty",
"Referer": "https://vpay.upcard.com.cn/vcweixin/mwalm/bind/card?company=mwalm&channel=App",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
}
url = "https://vpay.upcard.com.cn/vcweixin/mwalm/bindCard"
data = {
"company": "mwalm",
"channel": "App",
"cardNo": self.card_num,
"cardPwd": self.card_pwd
}
response = self.session.post(
url=url,
headers=headers,
data=data,
cookies=cookies,
verify=False,
timeout=self.bind_timeout,
)
res = response.json()
print(f"订单ID: {self.order_num}app请求绑卡返回{res}")
self.app.logger.info(f"订单ID: {self.order_num}app请求绑卡返回{res}")
logger.info(f"订单ID: {self.order_num}app请求绑卡返回{res}")
self.remarks = res.get("msg", "")
if res.get("code") == "00":
self.set_record(f"绑定成功")
return 100
elif res.get("code") == "11" and "该卡已被绑定" in self.remarks:
self.set_record(self.remarks)
return 104
elif res.get("code") == "11" and self.remarks == "线上密码无效":
self.set_record(self.remarks)
return 105
elif res.get("code") == "11" and "校验密码失败" in self.remarks:
self.set_record(self.remarks)
return 105
elif res.get("code") == "11" and self.remarks == "无法识别的卡号!":
self.set_record(self.remarks)
return 104
elif res.get("code") == "11" and self.remarks == "卡号不存在":
self.set_record(self.remarks)
return 104
elif res.get("code") == "01":
self.set_record(f"ck失效")
return 113
elif res.get("code") == "11" and "超过当天绑定上限" in self.remarks:
self.set_record(self.remarks)
return 116
else:
self.set_record(f"订单ID: {self.order_num},返回:{res}")
self.set_record(f"新的状态返回")
return 111
except Exception as e:
self.app.logger.info(f"订单ID: {self.order_num},报错:{traceback.format_exc()}")
logger.info(f"订单ID: {self.order_num},报错:{traceback.format_exc()}")
continue
return 110
def get_time(self):
from datetime import datetime
# 获取当前时间
current_time = datetime.now()
# 将当前时间格式化为指定格式的字符串
formatted_date = current_time.strftime("%Y-%m-%d %H:%M:%S")
return formatted_date
def set_record(self, text, log_only=False):
# 如果传入的是订单ID则不打印日志只做记录存储
if text == self.order_num:
record = f"{self.get_time()}#订单ID: {self.order_num}"
else:
log_text = f"{self.get_time()}#订单ID:{self.order_num}, {text}"
self.log_list.append(log_text)
record = f"{self.get_time()}#{text}"
if not log_only:
self.record_list.append(record)
def get_record(self):
return "@".join(self.record_list) + "@"
def run(self):
if "@" in self.cookies:
# 沃尔玛ck绑卡
code = self.walmart_bind_card()
else:
# 山姆app ck绑卡
code = self.sanmu_bind_card()
record = self.get_record()
return {
"code": code,
"record": record,
"log_list": self.log_list,
"remarks": self.remarks,
}

2
test.py Normal file
View File

@@ -0,0 +1,2 @@
secret = "+0Qrd0RdUvNrk/i8ThCeiA=="
version = "22"