mirror of
https://git.oceanpay.cc/danial/kami_walmart_card.git
synced 2025-12-18 11:02:03 +00:00
first commit
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal 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
14
.idea/deployment.xml
generated
Normal 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>
|
||||
23
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
23
.idea/inspectionProfiles/Project_Default.xml
generated
Normal 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>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal 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
7
.idea/misc.xml
generated
Normal 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
8
.idea/modules.xml
generated
Normal 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
6
.idea/vcs.xml
generated
Normal 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
19
.idea/walmart_bind.iml
generated
Normal 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
26
Dockerfile
Normal 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
1
README.md
Normal file
@@ -0,0 +1 @@
|
||||
docker run --name walmart_bind -p 5008:5008 -v /home/www/walmart_bind:/app -d walmart_bind
|
||||
BIN
__pycache__/app.cpython-38.pyc
Normal file
BIN
__pycache__/app.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/gun.cpython-38.pyc
Normal file
BIN
__pycache__/gun.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/logger.cpython-38.pyc
Normal file
BIN
__pycache__/logger.cpython-38.pyc
Normal file
Binary file not shown.
BIN
__pycache__/spiders.cpython-38.pyc
Normal file
BIN
__pycache__/spiders.cpython-38.pyc
Normal file
Binary file not shown.
47
app.py
Normal file
47
app.py
Normal 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
70
check_money.py
Normal 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
19
gun.conf
Normal 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
1
gunicorn.pid
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
29
logger.py
Normal file
29
logger.py
Normal 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
5
requirements.txt
Normal 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
387
spiders.py
Normal 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,
|
||||
}
|
||||
Reference in New Issue
Block a user