mirror of https://github.com/FanbeiFan/JD-SHOPPER
louisyoungx
3 years ago
73 changed files with 13070 additions and 336 deletions
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
[Spider] |
||||
# eid, fp参数必须填写,具体请参考Wiki-常见问题 https://github.com/tychxn/jd-assistant/wiki/1.-%E4%BA%AC%E4%B8%9C%E6%8A%A2%E8%B4%AD%E5%8A%A9%E6%89%8B%E7%94%A8%E6%B3%95 |
||||
eid = "2PBCMB2WINZUQI6XRDCSKOZXTCHEOHLDABNAVSAEYTS6DBH2DWOACQPUEKXGHV7ZYTKCRDXZX34SPL2XI3KQYVNVSM" |
||||
fp = "63a2c6fceb97a082753cdf00710f4f46" |
||||
# area到area_id目录下人工查找,例如:江西省南昌市昌北区蛟桥镇的area是21_1827_4101_40925 |
||||
area = 21_1827_4101_40925 |
||||
# 商品id |
||||
sku_id = 10027576824361 |
||||
# 购买数量 |
||||
amount = 1 |
||||
# 设定时间 # 2020-12-09 10:00:00.100000(修改成每天的几点几分几秒几毫秒) |
||||
buy_time = 2021-11-13 04:30:00.000 |
||||
# 提交订单失败重试次数 |
||||
retry = 100 |
||||
# 查询库存请求超时(秒),可选配置,默认10秒 |
||||
timeout = 10 |
||||
# 默认UA |
||||
DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" |
||||
# 是否使用随机 useragent,默认为 false |
||||
random_useragent = false |
||||
# 多进程数量 |
||||
work_count = 1 |
||||
|
||||
[Account] |
||||
# 支付密码 |
||||
# 如果你的账户中有可用的京券(注意不是东券)或 在上次购买订单中使用了京豆, |
||||
# 那么京东可能会在下单时自动选择京券支付 或 自动勾选京豆支付。 |
||||
# 此时下单会要求输入六位数字的支付密码。请在下方配置你的支付密码,如 123456 。 |
||||
# 如果没有上述情况,下方请留空。 |
||||
payment_pwd = "" |
||||
|
||||
[Message] |
||||
# 使用了Server酱的推送服务 |
||||
# 如果想开启下单成功后消息推送,则将 enable 设置为 true,默认为 false 不开启推送 |
||||
# 开启消息推送必须填入 sckey,如何获取请参考 http://sc.ftqq.com/3.version。感谢Server酱~ |
||||
enable = false |
||||
sckey = ??????? |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ============================= |
||||
# ============================= |
||||
# ====== 以下框架配置请勿动 ====== |
||||
# ============================= |
||||
# ============================= |
||||
|
||||
|
||||
[Information] |
||||
# 本项目的信息 |
||||
# PROJECT-项目名,VERSION-版本,AUTHOR-作者,TIME-创作时间 |
||||
PROJECT = "jd-shopper" |
||||
VERSION = "1.0.0-Alpha" |
||||
AUTHOR = "Louis·Young" |
||||
TIME = "2021-11-13" |
||||
|
||||
[Debug] |
||||
# DEBUG 设置 |
||||
# DEBUG-开启DEBUG后无视Scheduler只会执行Core.core.main函数中代码 |
||||
DEBUG = False |
||||
|
||||
[Server] |
||||
# 服务器信息 |
||||
# SERVER_NAME-服务器名,SERVER_VERSION-服务器版本 |
||||
# START_USING-是否开启服务器 |
||||
# SERVER_HOST-填写服务器域名,LOCAL_HOST-用于启动项目的局域网IP,PORT-端口 |
||||
# PROCESS_MODEL-是否开启多进程,PROCESS_COUNT-进程数量 |
||||
SERVER_NAME = "TinyServer" |
||||
SERVER_VERSION = "0.4.8" |
||||
START_USING = True |
||||
SERVER_HOST = "www.server.com" |
||||
LOCAL_HOST = "0.0.0.0" |
||||
PORT = 12020 |
||||
PROCESS_MODEL = False |
||||
PROCESS_COUNT = 4 |
||||
|
||||
[Logger] |
||||
# 记录设置 |
||||
# FILE_NAME-记录文件名,AMOUNT-记录文件个数,MAX_BYTES-单个记录文件的大小 |
||||
# CLEAR_UP每次启动程序是否清理log文件中内容,SERVER_LOGGER-开启HTTP Server的log记录 |
||||
FILE_NAME = "TinyServerManager.log" |
||||
FILE_PATH = "/Logger/Log_Files/" |
||||
AMOUNT = 1 |
||||
MAX_BYTES = 10485760 |
||||
CLEAR_UP = True |
||||
SERVER_LOGGER = False |
||||
|
||||
[Scheduler] |
||||
# 调度器设置(用于定时执行) |
||||
# START_USING-是否开启定时执行,调度器开启后main函数将被scheduler调度器代理,开启定时执行main |
||||
# START_TIME-任务开启时间,SKIP_WEEKEND-周末不执行任务 |
||||
START_USING = False |
||||
START_TIME = "18:00:00" |
||||
SKIP_WEEKEND = True |
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
def main(): |
||||
# 此处填写业务 |
||||
print("===== 此处业务处理 =====") |
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
import os |
||||
import logging |
||||
import logging.handlers |
||||
from Config.settings import config |
||||
|
||||
# 从config中查询所需数据 |
||||
path = config.path() + config.settings("Logger", "FILE_PATH") |
||||
filename = config.path() + config.settings("Logger", "FILE_PATH") + config.settings("Logger", "FILE_NAME") |
||||
maxBytes = config.settings("Logger", "MAX_BYTES") |
||||
backupCount = config.settings("Logger", "AMOUNT") |
||||
clearUp = config.settings("Logger", "CLEAR_UP") |
||||
|
||||
# 创建一个logger,创建一个列表存放logger数据 |
||||
logger = logging.getLogger() |
||||
logger_records = [] |
||||
|
||||
class CustomFilter(logging.Filter): |
||||
def filter(self, record): |
||||
# logger_records.append(record.msg) |
||||
return record.msg |
||||
|
||||
def clearUpLogFile(): |
||||
if not os.path.exists(path): |
||||
os.mkdir(path) |
||||
with open(filename, "w") as file: |
||||
file.seek(0) |
||||
file.truncate() # 清空文件 |
||||
|
||||
def logger_init(): |
||||
# 清理log文件 |
||||
if clearUp: |
||||
clearUpLogFile() |
||||
|
||||
# 设置logger输出级别 |
||||
logger.setLevel(logging.INFO) |
||||
filter = CustomFilter() |
||||
logger.addFilter(filter) |
||||
|
||||
# 设置logger输出格式 |
||||
# fmt = logging.Formatter('%(asctime)s - %(process)d-%(threadName)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s') |
||||
fmt = '[%(asctime)s] (%(module)s.%(funcName)s): <%(levelname)s> %(message)s' |
||||
datefmt = "%Y-%m-%d %H:%M:%S" |
||||
formatter = logging.Formatter(fmt=fmt, datefmt=datefmt) |
||||
|
||||
# 定义一个console_handler,用于输出到控制台 |
||||
console_handler = logging.StreamHandler() |
||||
|
||||
# 定义一个console_handler,用于输出到控制台 |
||||
file_handler = logging.handlers.RotatingFileHandler( |
||||
filename, maxBytes=maxBytes, backupCount=backupCount, encoding="utf-8") |
||||
|
||||
# 给handler添加formatter |
||||
console_handler.setFormatter(formatter) |
||||
file_handler.setFormatter(formatter) |
||||
|
||||
# 把初始化完毕的handler对象添加到logger对象中 |
||||
logger.addHandler(console_handler) |
||||
logger.addHandler(file_handler) |
||||
|
||||
|
||||
logger_init() |
||||
|
||||
|
||||
|
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python |
||||
# -*- encoding=utf8 -*- |
||||
import datetime |
||||
import json |
||||
|
||||
import requests |
||||
|
||||
from logger import logger |
||||
from config import global_config |
||||
|
||||
|
||||
class Messenger(object): |
||||
"""消息推送类""" |
||||
|
||||
def __init__(self, sc_key): |
||||
if not sc_key: |
||||
raise Exception('sc_key can not be empty') |
||||
|
||||
self.sc_key = sc_key |
||||
|
||||
def send(self, 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(self.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) |
||||
|
||||
|
||||
sckey = global_config.getRaw("messenger", "sckey") |
||||
message = Messenger(sckey) |
||||
|
||||
|
||||
def sendMessage(mes): |
||||
message.send(mes) |
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
import datetime |
||||
import time |
||||
from Logger.logger import logger |
||||
|
||||
|
||||
class Timer(object): |
||||
|
||||
def __init__(self, task, startTime, skipWeekend): |
||||
'''初始化''' |
||||
self.task = task |
||||
self.start_time = startTime |
||||
self.skip_weekend = skipWeekend |
||||
|
||||
def schedule(self): |
||||
'''调度执行上下文''' |
||||
while True: # 一个循环为一天时间 |
||||
self._schedule() # 进入今天的循环 |
||||
self.sleepToTomorrow() # 今天的任务结束,休眠到下一天 |
||||
|
||||
def _schedule(self): |
||||
'''调度执行''' |
||||
|
||||
logger.info("Daily Task Initialized Successfully") |
||||
|
||||
if self.skip_weekend and not self.isTodayWorkday(): |
||||
# 今天不是工作日,结束今天的任务 |
||||
return False |
||||
|
||||
elif self.isTimePass(): |
||||
# 今天的任务时间已经过了,结束今天的任务 |
||||
return False |
||||
|
||||
else: |
||||
self.execute() |
||||
return True |
||||
|
||||
def execute(self): |
||||
real_datetime = self.realDate() # 当前的时间(日期) |
||||
real_mstime = self.dateMSTime(real_datetime) # 当前的时间(毫秒) |
||||
today_task_datetime = self.todayTaskTime() # 今天任务时间(日期) |
||||
today_task_mstime = self.dateMSTime(today_task_datetime) # 今天任务时间(毫秒) |
||||
wait_time = today_task_mstime - real_mstime # 获取当前时间与任务的时间差 |
||||
logger.info("Waiting to Start Mission -> {}".format(today_task_datetime)) |
||||
time.sleep(wait_time) # 线程休眠阻塞任务 |
||||
self.task() # 阻塞结束执行 |
||||
logger.info("Today's Mission Completed") |
||||
|
||||
|
||||
def realDate(self): |
||||
''' |
||||
获取当前的日期与时间 |
||||
return: date "%Y-%m-%d %H:%M:%S" |
||||
''' |
||||
localtime = time.localtime(time.time()) |
||||
date = \ |
||||
localtime.tm_year.__str__() + '-' + \ |
||||
localtime.tm_mon.__str__() + '-' + \ |
||||
localtime.tm_mday.__str__() + ' ' + \ |
||||
localtime.tm_hour.__str__() + ':' + \ |
||||
localtime.tm_min.__str__() + ':' + \ |
||||
localtime.tm_sec.__str__() |
||||
return date |
||||
|
||||
def realMSTime(self): |
||||
''' |
||||
获取当前的毫秒时间 |
||||
return: 毫秒时间 |
||||
''' |
||||
return time.time() |
||||
|
||||
def tomorrowMSTime(self): |
||||
''' |
||||
获取明天的00:00:00毫秒时间 |
||||
return: 毫秒时间 |
||||
''' |
||||
localtime = time.localtime(time.time()) |
||||
# 今天00:00:00的日期时间 |
||||
today_start_date = \ |
||||
localtime.tm_year.__str__() + '-' + \ |
||||
localtime.tm_mon.__str__() + '-' + \ |
||||
localtime.tm_mday.__str__() + ' ' + \ |
||||
'00:00:00' |
||||
today_start_time = self.dateMSTime(today_start_date) |
||||
tomorrow_start_time = today_start_time + 60 * 60 * 24 |
||||
return tomorrow_start_time |
||||
|
||||
def isTodayWorkday(self): |
||||
''' |
||||
该日期是否为工作日 |
||||
params: |
||||
date "%Y-%m-%d %H:%M:%S" |
||||
return: |
||||
工作日: True |
||||
休息日: False |
||||
''' |
||||
localtime = time.localtime(time.time()) |
||||
week = localtime.tm_wday.__str__() |
||||
if week in (5, 6): |
||||
# 如果是休息日 |
||||
logger.info("Over The Weekend") |
||||
return False |
||||
else: |
||||
# 如果是工作日 |
||||
logger.info("Working Day") |
||||
return True |
||||
|
||||
def sleepToTomorrow(self): |
||||
'''休眠到下一天''' |
||||
real_datetime = self.realDate() # 当前的时间(日期) |
||||
real_mstime = self.dateMSTime(real_datetime) # 当前的时间(毫秒) |
||||
tomorrow_mstime = self.tomorrowMSTime() # 明天0点的时间(毫秒) |
||||
diff_time = tomorrow_mstime - real_mstime # 现在到明天0点的毫秒时间 |
||||
logger.info("Sleeping to tomorrow -> {} Seconds".format(diff_time)) |
||||
time.sleep(diff_time) |
||||
|
||||
def isTimePass(self): |
||||
''' |
||||
确认当前时间是否超过今天执行时间 |
||||
return: |
||||
True:超时 |
||||
False:没超时 |
||||
''' |
||||
real_datetime = self.realDate() # 当前的时间(日期) |
||||
real_mstime = self.dateMSTime(real_datetime) # 当前的时间(毫秒) |
||||
today_task_datetime = self.todayTaskTime() # 今天任务时间(日期) |
||||
today_task_mstime = self.dateMSTime(today_task_datetime) # 今天任务时间(毫秒) |
||||
if real_mstime > today_task_mstime: |
||||
logger.info("Time Pass - Now Time: {} TaskTime: {}".format(real_datetime, today_task_datetime)) |
||||
return True |
||||
else: |
||||
logger.info("Time Waiting - RealTime: {}".format(real_datetime)) |
||||
return False |
||||
|
||||
def dateMSTime(self, date): |
||||
''' |
||||
获取该日期对应的毫秒时间 |
||||
params: |
||||
date 格式为"%Y-%m-%d %H:%M:%S" |
||||
return: |
||||
ms_time 毫秒时间 |
||||
''' |
||||
date_time = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S") |
||||
ms_time = int(time.mktime(date_time.timetuple()) + date_time.microsecond) |
||||
return ms_time |
||||
|
||||
def todayTaskTime(self): |
||||
''' |
||||
获取今天的任务日期 |
||||
return: today_date "%Y-%m-%d %H:%M:%S" |
||||
''' |
||||
localtime = time.localtime(time.time()) |
||||
today_date = \ |
||||
localtime.tm_year.__str__() + '-' + \ |
||||
localtime.tm_mon.__str__() + '-' + \ |
||||
localtime.tm_mday.__str__() + ' ' + \ |
||||
self.start_time |
||||
return today_date |
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
import copy |
||||
import psutil |
||||
|
||||
from Config.settings import config |
||||
|
||||
def log(request): |
||||
file_path = config.path() + config.settings("Logger", "FILE_PATH") + config.settings("Logger", "FILE_NAME") |
||||
file_page_file = open(file_path, 'r') |
||||
return str(file_page_file.read()) |
||||
|
||||
def systemInfo(request): |
||||
info = {} |
||||
info['cpu_count'] = psutil.cpu_count() # CPU逻辑数量 |
||||
info['cpu_percent'] = psutil.cpu_percent(interval=1) # CPU使用率 |
||||
info['cpu_times'] = psutil.cpu_times() # CPU的用户/系统/空闲时间 |
||||
info['virtual_memory'] = psutil.virtual_memory() # 物理内存 |
||||
info['swap_memory'] = psutil.swap_memory() # 交换内存 |
||||
info['disk_partitions'] = psutil.disk_partitions() # 磁盘分区信息 |
||||
info['disk_partitions'] = psutil.disk_usage('/') # 磁盘使用情况 |
||||
info['disk_partitions'] = psutil.disk_io_counters() # 磁盘IO |
||||
info['disk_partitions'] = psutil.net_io_counters() # 获取网络读写字节/包的个数 |
||||
info['disk_partitions'] = psutil.net_if_addrs() # 获取网络接口信息 |
||||
info['disk_partitions'] = psutil.net_if_stats() # 获取网络接口状态 |
||||
# need sudo: info['disk_partitions'] = psutil.net_connections() # 获取当前网络连接信息 |
||||
return info |
||||
|
||||
def serverConfig(request): |
||||
appConfig = copy.deepcopy(config._config._sections) |
||||
for model in appConfig: |
||||
for item in appConfig[model]: |
||||
appConfig[model][item] = eval(appConfig[model][item]) |
||||
value = appConfig[model][item] |
||||
# DEBUG print(model, item, value, type(value)) |
||||
return appConfig |
@ -0,0 +1,127 @@
@@ -0,0 +1,127 @@
|
||||
import os, json |
||||
import time |
||||
|
||||
from Logger.logger import logger |
||||
from http.server import BaseHTTPRequestHandler |
||||
from Config.settings import config |
||||
|
||||
# Document https://docs.python.org/3.9/library/http.server.html |
||||
from Server.url import urls |
||||
|
||||
|
||||
class RequestHandler(BaseHTTPRequestHandler): |
||||
'''处理请求并返回页面''' |
||||
|
||||
# 处理一个GET请求 |
||||
def do_GET(self): |
||||
self.rootPath = config.path() + "/Static" |
||||
url = self.requestline[4:-9] |
||||
request_data = {} # 存放GET请求数据 |
||||
try: |
||||
if url.find('?') != -1: |
||||
req = url.split('?', 1)[1] |
||||
url = url.split('?', 1)[0] |
||||
parameters = req.split('&') |
||||
for i in parameters: |
||||
key, val = i.split('=', 1) |
||||
request_data[key] = val |
||||
except: |
||||
logger.error("URL Format Error") |
||||
if (url == "/"): |
||||
self.home() |
||||
elif ("/api" in url): |
||||
self.api(url[4:], request_data) |
||||
else: |
||||
self.file(url) |
||||
|
||||
def log_message(self, format, *args): |
||||
SERVER_LOGGER = config.settings("Logger", "SERVER_LOGGER") |
||||
if SERVER_LOGGER: |
||||
logger.info(format % args) |
||||
else: |
||||
pass |
||||
|
||||
def home(self): |
||||
|
||||
file_path = self.rootPath + "/index.html" |
||||
home_page_file = open(file_path, 'r') |
||||
content = str(home_page_file.read()) |
||||
|
||||
self.send_response(200) |
||||
self.send_header("Content-Type", "text/html") |
||||
self.send_header("Content-Length", str(len(content))) |
||||
self.end_headers() |
||||
self.wfile.write(content.encode()) |
||||
|
||||
def file(self, url): |
||||
file_name = url.split("/")[-1] |
||||
file_sys_path = self.rootPath + url[:-len(file_name)] |
||||
file_path = "" |
||||
for root, dirs, files in os.walk(file_sys_path): |
||||
for file in files: |
||||
if file == file_name: |
||||
file_path = os.path.join(root, file) |
||||
else: |
||||
continue |
||||
if file_path != "": |
||||
self.send_response(200) |
||||
if file_path == "": |
||||
# file_path = self.rootPath + "/404.html" # Hard Code |
||||
self.noFound() |
||||
elif file_name[-5:] == ".html": |
||||
self.send_header("Content-Type", "text/html") |
||||
elif file_name[-4:] == ".css": |
||||
self.send_header("Content-Type", "text/css") |
||||
elif file_name[-3:] == ".js": |
||||
self.send_header("Content-Type", "application/javascript") |
||||
elif file_name[-4:] == ".png": # 二进制文件 |
||||
self.send_header("Content-Type", "img/png") |
||||
file_page_file = open(file_path, 'rb') |
||||
self.end_headers() |
||||
self.wfile.write(file_page_file.read()) |
||||
return |
||||
elif file_name[-4:] == ".jpg": # 二进制文件 |
||||
self.send_header("Content-Type", "img/jpg") |
||||
file_page_file = open(file_path, 'rb') |
||||
self.end_headers() |
||||
self.wfile.write(file_page_file.read()) |
||||
return |
||||
elif file_name[-4:] == ".ico": # 二进制文件 |
||||
self.send_header("Content-Type", "img/ico") |
||||
file_page_file = open(file_path, 'rb') |
||||
self.end_headers() |
||||
self.wfile.write(file_page_file.read()) |
||||
return |
||||
|
||||
file_page_file = open(file_path, 'r') |
||||
content = str(file_page_file.read()) |
||||
self.send_header("Content-Length", str(len(content))) |
||||
self.end_headers() |
||||
self.wfile.write(content.encode()) |
||||
|
||||
def api(self, url, request_data): |
||||
# ---------------------------------------------------------------- |
||||
# 此处写API |
||||
content = urls(url, request_data) |
||||
|
||||
# ---------------------------------------------------------------- |
||||
localtime = time.localtime(time.time()) |
||||
date = \ |
||||
localtime.tm_year.__str__() + '-' + \ |
||||
localtime.tm_mon.__str__() + '-' + \ |
||||
localtime.tm_mday.__str__() + ' ' + \ |
||||
localtime.tm_hour.__str__() + ':' + \ |
||||
localtime.tm_min.__str__() + ':' + \ |
||||
localtime.tm_sec.__str__() |
||||
jsondict = {} |
||||
jsondict["data"] = content |
||||
jsondict["time"] = date |
||||
res = json.dumps(jsondict) |
||||
self.send_response(200) |
||||
self.send_header("Content-Type", "text/html") |
||||
self.send_header("Content-Length", str(len(res))) |
||||
self.end_headers() |
||||
self.wfile.write(res.encode()) |
||||
|
||||
def noFound(self): |
||||
self.file("/404.html") |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
import json |
||||
from http.server import HTTPServer |
||||
from Logger.logger import logger |
||||
from Server.handler import RequestHandler |
||||
from Config.settings import config |
||||
|
||||
def server(): |
||||
NAME = config.settings("Server", "SERVER_NAME") |
||||
VERSION = config.settings("Server", "SERVER_VERSION") |
||||
DEBUG = config.settings("Debug", "DEBUG") |
||||
LOCAL_HOST = config.settings("Server", "LOCAL_HOST") |
||||
SERVER_HOST = config.settings("Server", "SERVER_HOST") |
||||
PORT = config.settings("Server", "PORT") |
||||
if DEBUG == True: |
||||
name = LOCAL_HOST |
||||
else: |
||||
name = SERVER_HOST |
||||
port = PORT |
||||
host = LOCAL_HOST |
||||
serverAddress = (host, port) |
||||
logger.info("{}-{}".format(NAME, VERSION)) |
||||
logger.info("http://{}:{}/".format(name, port)) |
||||
server = HTTPServer(serverAddress, RequestHandler) |
||||
server.serve_forever() |
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
from Server.api import log, systemInfo, serverConfig |
||||
|
||||
def urls(url, request): |
||||
if (url == "/log"): return log(request) |
||||
elif (url == "/system-info"): return systemInfo(request) |
||||
elif (url == "/config"): return serverConfig(request) |
||||
else: return "No Response" |
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
.data_dict, .data_dict_goods{ |
||||
display: none; |
||||
} |
||||
#form_container{ |
||||
width: 600px; |
||||
margin: 0 auto; |
||||
border: 1px solid gainsboro; |
||||
} |
||||
h1{ |
||||
text-align: center; |
||||
margin: 30px 0; |
||||
padding-bottom: 20px; |
||||
} |
||||
#account_input, #password_input{ |
||||
width: 300px; |
||||
} |
||||
#password_form{ |
||||
width: 380px; |
||||
} |
||||
.goods_input{ |
||||
width: 300px; |
||||
margin-right: 20px; |
||||
} |
||||
.num_select{ |
||||
width: 120px; |
||||
} |
||||
#add_button{ |
||||
margin-left: 150px; |
||||
margin-bottom: 30px; |
||||
} |
||||
#run_button{ |
||||
margin-left: 30px; |
||||
} |
@ -0,0 +1,180 @@
@@ -0,0 +1,180 @@
|
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta charset="UTF-8" /> |
||||
<title>订单自动提交</title> |
||||
<link rel="Shortcut Icon" href="title.ico" type="image/x-icon" /> |
||||
<link type="text/css" rel="stylesheet" href="css/element_index.css" /> |
||||
<link type="text/css" rel="stylesheet" href="css/index.css" /> |
||||
</head> |
||||
<body> |
||||
<div id="form_container"> |
||||
<h1>订单自动提交</h1> |
||||
<el-form ref="form" :model="form" label-width="80px"> |
||||
<el-form-item label="登录方式"> |
||||
<el-radio v-model="radio_login" label="1" @change="LoginMode" border |
||||
>自动登录</el-radio |
||||
> |
||||
<el-radio v-model="radio_login" label="2" @change="LoginMode" border |
||||
>手动登录</el-radio |
||||
> |
||||
</el-form-item> |
||||
<el-form-item label="账号"> |
||||
<el-input |
||||
id="account_input" |
||||
v-model="account_value" |
||||
placeholder="请输入账号" |
||||
:disabled="input_writeable" |
||||
></el-input> |
||||
</el-form-item> |
||||
<el-form-item label="密码" id="password_form"> |
||||
<el-input |
||||
id="password_input" |
||||
v-model="password_value" |
||||
placeholder="请输入密码" |
||||
:disabled="input_writeable" |
||||
show-password |
||||
></el-input> |
||||
</el-form-item> |
||||
<el-form-item label="运行时间"> |
||||
<el-select v-model="date_value" placeholder="选择日期(默认今天)"> |
||||
<el-option |
||||
v-for="item in date_options" |
||||
:key="item.date_value" |
||||
:label="item.label" |
||||
:value="item.date_value" |
||||
> |
||||
</el-option> |
||||
</el-select> |
||||
<el-time-picker |
||||
v-model="time_value" |
||||
:picker-options="{}" |
||||
placeholder="选择时间(默认现在)" |
||||
> |
||||
</el-time-picker> |
||||
</el-form-item> |
||||
<goods_link></goods_link> |
||||
<div v-for="(d,index) in goods_link_counter" :key="index"> |
||||
<goods_link></goods_link> |
||||
</div> |
||||
<el-button id="add_button" @click="addGoods">继续添加</el-button> |
||||
<el-button |
||||
id="run_button" |
||||
@click="changeRunStatus" |
||||
type="primary" |
||||
:class="run_status" |
||||
>开始运行</el-button |
||||
> |
||||
</el-form> |
||||
<ul class="data_dict"> |
||||
<!--登录方式, 账号, 密码, 运行时间, url--> |
||||
<li class="is_manual">{{is_manual}}</li> |
||||
<li class="jd_conut">{{account_value}}</li> |
||||
<li class="jd_password">{{password_value}}</li> |
||||
<li class="run_date">{{date_value}}</li> |
||||
<li class="run_time">{{time_value}}</li> |
||||
</ul> |
||||
</div> |
||||
<template id="goods_link"> |
||||
<el-form-item label="添加商品" id="goods_link_form"> |
||||
<el-input |
||||
class="goods_input" |
||||
v-model="goods_url" |
||||
placeholder="商品链接" |
||||
></el-input> |
||||
<el-input-number |
||||
class="num_select" |
||||
v-model="num" |
||||
@change="handleChange" |
||||
:min="1" |
||||
:max="999" |
||||
label="数量" |
||||
></el-input-number> |
||||
<ul class="data_dict_goods"> |
||||
<li class="goods_url">{{goods_url}}</li> |
||||
<li class="goods_num">{{num}}</li> |
||||
</ul> |
||||
</el-form-item> |
||||
</template> |
||||
</body> |
||||
<script src="js/vue.js"></script> |
||||
<script src="js/element_index.js"></script> |
||||
<script> |
||||
Vue.component("goods_link", { |
||||
template: "#goods_link", |
||||
data: function () { |
||||
return { |
||||
num: 1, |
||||
goods_url: "", |
||||
}; |
||||
}, |
||||
// props:{ |
||||
// num:{ |
||||
// type: Number, |
||||
// default: 1 |
||||
// }, |
||||
// goods_url: { |
||||
// type: String, |
||||
// default: '' |
||||
// } |
||||
// }, |
||||
methods: { |
||||
handleChange(value) {}, |
||||
}, |
||||
}); |
||||
new Vue({ |
||||
el: "#form_container", |
||||
data: function () { |
||||
return { |
||||
account_value: "", |
||||
password_value: "", |
||||
radio_login: "1", |
||||
is_manual: 0, |
||||
input_writeable: false, |
||||
run_status: "wait", |
||||
goods_link_counter: [], |
||||
date_value: "", |
||||
date_options: [ |
||||
{ |
||||
date_value: "today", |
||||
label: "今天", |
||||
}, |
||||
{ |
||||
date_value: "tomorrow", |
||||
label: "明天", |
||||
}, |
||||
], |
||||
// time_value: new Date(2016, 9, 10, 18, 40), |
||||
time_value: "", |
||||
form: { |
||||
name: "", |
||||
region: "", |
||||
}, |
||||
}; |
||||
}, |
||||
methods: { |
||||
LoginMode: function (value) { |
||||
if (this.radio_login === "1" || this.radio_login === 1) { |
||||
this.is_manual = 0; |
||||
this.input_writeable = false; |
||||
} else { |
||||
this.is_manual = 1; |
||||
this.input_writeable = true; |
||||
} |
||||
}, |
||||
addGoods: function () { |
||||
this.goods_link_counter.push({}); |
||||
}, |
||||
changeRunStatus: function () { |
||||
if (!this.date_value) { |
||||
this.date_value = "today"; |
||||
} |
||||
if (!this.time_value) { |
||||
this.time_value = new Date(); |
||||
} |
||||
this.run_status = "trigger_run"; |
||||
}, |
||||
}, |
||||
}); |
||||
</script> |
||||
</html> |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 894 B |
@ -1,48 +0,0 @@
@@ -1,48 +0,0 @@
|
||||
[config] |
||||
mode = |
||||
# eid, fp参数必须填写,具体请参考Wiki-常见问题 https://github.com/tychxn/jd-assistant/wiki/1.-%E4%BA%AC%E4%B8%9C%E6%8A%A2%E8%B4%AD%E5%8A%A9%E6%89%8B%E7%94%A8%E6%B3%95 |
||||
eid = "" |
||||
fp = "" |
||||
# area到area_id目录下人工查找 |
||||
area = |
||||
# 商品id |
||||
# 已经是XSS的sku_id了,用XSX换成100011513445 |
||||
sku_id = 100021890778 |
||||
# sku_id = 7816155 |
||||
# XSX-100011513445 XSS-100021890778 百事可乐-7816155 |
||||
# 设定时间 # 2020-12-09 10:00:00.100000 |
||||
# 修改成每天的几点几分几秒几毫秒 |
||||
buy_time = 2021-07-11 09:59:59.500 |
||||
# 提交订单失败重试次数 |
||||
retry = 10 |
||||
# 查询库存请求超时(秒),可选配置,默认10秒 |
||||
timeout = 10 |
||||
# 默认UA |
||||
DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" |
||||
# 是否使用随机 useragent,默认为 false |
||||
random_useragent = false |
||||
|
||||
[settings] |
||||
# 购买数量 |
||||
buy_amount = 1 |
||||
# 多进程数量 |
||||
work_count = 1 |
||||
|
||||
[account] |
||||
# 支付密码 |
||||
# 如果你的账户中有可用的京券(注意不是东券)或 在上次购买订单中使用了京豆, |
||||
# 那么京东可能会在下单时自动选择京券支付 或 自动勾选京豆支付。 |
||||
# 此时下单会要求输入六位数字的支付密码。请在下方配置你的支付密码,如 123456 。 |
||||
# 如果没有上述情况,下方请留空。 |
||||
payment_pwd = "" |
||||
|
||||
[messenger] |
||||
# 使用了Mirai_QQ的推送服务 |
||||
enable = False |
||||
# mode改成group发送到QQ群 |
||||
mode = user |
||||
# mode-user模式下填写QQ号 |
||||
user_id = NULL |
||||
# mode-group下填写群号 |
||||
group_id = NULL |
||||
server_address = NULL |
@ -1,23 +0,0 @@
@@ -1,23 +0,0 @@
|
||||
import logging |
||||
import logging.handlers |
||||
''' |
||||
日志模块 |
||||
''' |
||||
LOG_FILENAME = 'JD_SHOPPER.log' |
||||
logger = logging.getLogger() |
||||
|
||||
|
||||
def set_logger(): |
||||
logger.setLevel(logging.INFO) |
||||
fmt = '[%(asctime)s] (%(module)s.%(funcName)s): <%(levelname)s> %(message)s' |
||||
datefmt = "%Y-%m-%d %H:%M:%S" |
||||
formatter = logging.Formatter(fmt=fmt, datefmt=datefmt) |
||||
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() |
@ -1,77 +0,0 @@
@@ -1,77 +0,0 @@
|
||||
import json |
||||
import requests |
||||
|
||||
from logger import logger |
||||
from config import global_config |
||||
|
||||
def sendMessage(message): |
||||
enabled = global_config.getRaw("messenger", "enable") |
||||
if not enabled: |
||||
return |
||||
mode = global_config.getRaw("messenger", "mode") |
||||
if mode == "group": |
||||
groupid = global_config.getRaw("messenger", "group_id") |
||||
sendGroupMessage(message, groupid) |
||||
else: |
||||
userid = global_config.getRaw("messenger", "user_id") |
||||
sendFriendMessage(message, userid) |
||||
|
||||
def sendFriendMessage(message, userid): |
||||
URL = global_config.getRaw("messenger", "server_address") |
||||
path = "sendFriendMessage" |
||||
try: |
||||
URL = "http://{}/{}".format(URL, path) |
||||
body = { |
||||
"sessionKey": "YourSession", |
||||
"target": userid, |
||||
"messageChain": [ |
||||
{"type": "Plain", "text": message} |
||||
] |
||||
} |
||||
|
||||
# sender = requests.post(URL, params = params, data=json.dumps(body)) |
||||
sender = requests.post(URL, data=json.dumps(body)) |
||||
|
||||
mes = message.replace("\n", " ") |
||||
if len(mes) > 10: |
||||
mes = mes[:10] + "···" |
||||
logger.info("Send {}".format(mes)) |
||||
|
||||
|
||||
# print(sender.request.url) |
||||
# sender.raise_for_status() |
||||
# print(sender.text) |
||||
return True |
||||
except: |
||||
logger.error("Message Send Failed") |
||||
return False |
||||
|
||||
|
||||
def sendGroupMessage(message, groupid): |
||||
URL = global_config.getRaw("messenger", "server_address") |
||||
path = "sendGroupMessage" |
||||
try: |
||||
URL = "http://{}/{}".format(URL, path) |
||||
|
||||
body = { |
||||
"sessionKey": "YourSession", |
||||
"target": groupid, |
||||
"messageChain": [ |
||||
{"type": "Plain", "text": message} |
||||
] |
||||
} |
||||
|
||||
# sender = requests.post(URL, params = params, data=json.dumps(body)) |
||||
sender = requests.post(URL, data=json.dumps(body)) |
||||
mes = message.replace("\n", " ") |
||||
if len(mes) > 10: |
||||
mes = mes[:10] + "···" |
||||
logger.info("Send {}".format(mes)) |
||||
|
||||
# print(sender.request.url) |
||||
# sender.raise_for_status() |
||||
# print(sender.text) |
||||
return True |
||||
except: |
||||
logger.error("Message Send Failed") |
||||
return False |
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
from Core.core import main |
||||
from Logger.logger import logger |
||||
from Scheduler.scheduler import Timer |
||||
from Config.settings import config |
||||
from Server.server import server |
||||
from threading import Thread |
||||
from concurrent.futures import ProcessPoolExecutor |
||||
|
||||
def running(): |
||||
PROCESS_MODEL = config.settings("Server", "PROCESS_MODEL") |
||||
SCHEDULER = config.settings("Scheduler", "START_USING") |
||||
SERVER = config.settings("Server", "START_USING") |
||||
if not SCHEDULER: |
||||
thread_main = Thread(target=main) |
||||
thread_main.start() |
||||
else: # 调度器开启后main函数将被scheduler调度器代理,开启定时执行main |
||||
startTime = config.settings("Scheduler", "START_TIME") |
||||
skipWeekend = config.settings("Scheduler", "SKIP_WEEKEND") |
||||
scheduler = Timer(task=main, startTime=startTime, skipWeekend=skipWeekend) |
||||
thread_scheduler = Thread(target=scheduler.schedule) |
||||
thread_scheduler.start() |
||||
if SERVER: |
||||
if PROCESS_MODEL: |
||||
work_count = config.settings("Server", "PROCESS_COUNT") |
||||
server_process(work_count) |
||||
else: |
||||
thread_server = Thread(target=server) |
||||
thread_server.start() |
||||
|
||||
def server_process(work_count=4): |
||||
with ProcessPoolExecutor(work_count) as pool: |
||||
for i in range(work_count): |
||||
pool.submit(server()) |
||||
|
||||
if __name__ == "__main__": |
||||
DEBUG = config.settings("Debug", "DEBUG") |
||||
if DEBUG: |
||||
logger.info("\n===== DEBUG MODE =====") |
||||
main() |
||||
else: |
||||
running() |
||||
|
Loading…
Reference in new issue