From 3294231002381b76f3041a185861b03f2ceca21b Mon Sep 17 00:00:00 2001 From: louisyoungx <1462648167@qq.com> Date: Sat, 13 Nov 2021 13:57:37 +0800 Subject: [PATCH] feat(web-ui): append web ui --- Config/config.ini | 16 +-- Core/core.py | 3 +- Core/login.py | 10 +- Core/spider.py | 38 ++--- Core/timer.py | 26 ++-- Core/util.py | 6 +- Message/message.py | 6 +- Server/api.py | 68 ++++++--- Server/app.py | 42 ++++++ Server/handler.py | 25 +++- Server/url.py | 5 +- Static/404.html | 267 ++++++++++++++++++++++++++++++++++++ Static/css/index.css | 36 ++++- Static/img/qr_code.png | Bin 0 -> 776 bytes Static/index.html | 250 +++++++++++++-------------------- Static/js/element_index.js | 10 +- Static/js/index.js | 200 +++++++++++++++++++++++++++ Static/js/vue.js | 4 + cookies/Louis_Young.cookies | Bin 0 -> 2629 bytes 19 files changed, 781 insertions(+), 231 deletions(-) create mode 100644 Server/app.py mode change 100755 => 100644 Server/handler.py create mode 100644 Static/404.html create mode 100644 Static/img/qr_code.png create mode 100644 Static/js/index.js create mode 100644 cookies/Louis_Young.cookies diff --git a/Config/config.ini b/Config/config.ini index 71edffa..b64a3b2 100755 --- a/Config/config.ini +++ b/Config/config.ini @@ -3,21 +3,21 @@ eid = "2PBCMB2WINZUQI6XRDCSKOZXTCHEOHLDABNAVSAEYTS6DBH2DWOACQPUEKXGHV7ZYTKCRDXZX34SPL2XI3KQYVNVSM" fp = "63a2c6fceb97a082753cdf00710f4f46" # area到area_id目录下人工查找,例如:江西省南昌市昌北区蛟桥镇的area是21_1827_4101_40925 -area = 21_1827_4101_40925 +area = "21_1827_4101_40925" # 商品id -sku_id = 10027576824361 +sku_id = "10027576824361" # 购买数量 amount = 1 # 设定时间 # 2020-12-09 10:00:00.100000(修改成每天的几点几分几秒几毫秒) -buy_time = 2021-11-13 04:30:00.000 +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 +# 是否使用随机 useragent,默认为 False +random_useragent = False # 多进程数量 work_count = 1 @@ -33,8 +33,8 @@ payment_pwd = "" # 使用了Server酱的推送服务 # 如果想开启下单成功后消息推送,则将 enable 设置为 true,默认为 false 不开启推送 # 开启消息推送必须填入 sckey,如何获取请参考 http://sc.ftqq.com/3.version。感谢Server酱~ -enable = false -sckey = ??????? +enable = False +sckey = "?????" @@ -86,7 +86,7 @@ SERVER_VERSION = "0.4.8" START_USING = True SERVER_HOST = "www.server.com" LOCAL_HOST = "0.0.0.0" -PORT = 12020 +PORT = 12021 PROCESS_MODEL = False PROCESS_COUNT = 4 diff --git a/Core/core.py b/Core/core.py index 0172f00..336e825 100755 --- a/Core/core.py +++ b/Core/core.py @@ -1,3 +1,2 @@ def main(): - # 此处填写业务 - print("===== 此处业务处理 =====") + pass diff --git a/Core/login.py b/Core/login.py index 0baf915..26cf773 100644 --- a/Core/login.py +++ b/Core/login.py @@ -5,10 +5,10 @@ import functools import json import os import pickle -from logger import logger -from config import global_config -from exception import SKException -from util import ( +from Logger.logger import logger +from Config.settings import config +from Core.exception import SKException +from Core.util import ( parse_json, wait_some_time, response_status, @@ -21,7 +21,7 @@ class SpiderSession: """ def __init__(self): self.cookies_dir_path = "./cookies/" - self.user_agent = global_config.getRaw('config', 'DEFAULT_USER_AGENT') + self.user_agent = config.settings('Spider', 'DEFAULT_USER_AGENT') self.session = self._init_session() diff --git a/Core/spider.py b/Core/spider.py index 550f5e7..8a854e2 100644 --- a/Core/spider.py +++ b/Core/spider.py @@ -7,30 +7,31 @@ import json import random import sys from concurrent.futures import ProcessPoolExecutor -from exception import SKException +from Core.exception import SKException from bs4 import BeautifulSoup from Config.settings import config from Logger.logger import logger -from login import SpiderSession, QrLogin +from Core.login import SpiderSession, QrLogin from Message.message import sendMessage -from timer import Timer -from util import parse_json +from Core.timer import Timer +from Core.util import parse_json class Waiter(): def __init__(self, - skuids=config.global_config.getRaw("Spider", "sku_id"), - area=config.global_config.getRaw("Spider", "area"), - eid=config.global_config.getRaw("Spider", "eid"), - fp=config.global_config.getRaw("Spider", "fp"), - count=config.global_config.getRaw("Spider", "amount"), - payment_pwd=config.global_config.getRaw( + skuids=config.settings("Spider", "sku_id"), + area=config.settings("Spider", "area"), + eid=config.settings("Spider", "eid"), + fp=config.settings("Spider", "fp"), + count=config.settings("Spider", "amount"), + payment_pwd=config.settings( "Account", "payment_pwd"), - retry=eval(config.global_config.getRaw("Spider", "retry")), - work_count=eval(config.global_config.getRaw( - 'Spider', 'work_count')), - timeout=float(config.global_config.getRaw( - "Spider", "timeout")) + retry=config.settings("Spider", "retry"), + work_count=config.settings( + 'Spider', 'work_count'), + timeout=float(config.raw( + "Spider", "timeout")), + date=config.settings('Spider', 'buy_time').__str__() ): self.skuids = skuids @@ -42,6 +43,7 @@ class Waiter(): self.retry = retry self.work_count = work_count self.timeout = timeout + self.buyTime = date self.spider_session = SpiderSession() self.spider_session.load_cookies_from_local() @@ -51,7 +53,7 @@ class Waiter(): self.item_cat = {} self.item_vender_ids = {} # 记录商家id self.headers = {'User-Agent': self.user_agent} - self.timers = Timer() + self.timers = Timer(self.buyTime) def login_by_qrcode(self): """ @@ -82,9 +84,11 @@ class Waiter(): return func(self, *args, **kwargs) return new_func + @ check_login def waitForSell(self): self._waitForSell() - + + @ check_login def waitTimeForSell(self): self._waitTimeForSell() diff --git a/Core/timer.py b/Core/timer.py index 1a08cf4..627fb58 100644 --- a/Core/timer.py +++ b/Core/timer.py @@ -9,10 +9,10 @@ from Config.settings import config class Timer(object): - def __init__(self, sleep_interval=0.5): + def __init__(self, buyTime, sleep_interval=0.5): # '2018-09-28 22:45:50.000' # buy_time = 2020-12-22 09:59:59.500 - buy_time_everyday = config.global_config.getRaw('config', 'buy_time').__str__() + buy_time_everyday = buyTime localtime = time.localtime(time.time()) #self.buy_time = datetime.strptime( # localtime.tm_year.__str__() + '-' + localtime.tm_mon.__str__() + '-' + localtime.tm_mday.__str__() @@ -52,15 +52,13 @@ class Timer(object): def start(self): logger.info('正在等待到达设定时间:{}'.format(self.buy_time)) logger.info('正检测本地时间与京东服务器时间误差为【{}】毫秒'.format(self.diff_time)) - mode = config.global_config.getMode() - if mode != '3': - while True: - # 本地时间减去与京东的时间差,能够将时间误差提升到0.1秒附近 - # 具体精度依赖获取京东服务器时间的网络时间损耗 - if self.local_time() - self.diff_time >= self.buy_time_ms: - logger.info('时间到达,开始执行……') - break - else: - time.sleep(self.sleep_interval) - else: - pass + + while True: + # 本地时间减去与京东的时间差,能够将时间误差提升到0.1秒附近 + # 具体精度依赖获取京东服务器时间的网络时间损耗 + if self.local_time() - self.diff_time >= self.buy_time_ms: + logger.info('时间到达,开始执行……') + break + else: + time.sleep(self.sleep_interval) + diff --git a/Core/util.py b/Core/util.py index 8a25526..cfb434e 100644 --- a/Core/util.py +++ b/Core/util.py @@ -79,13 +79,13 @@ def wait_some_time(): def send_wechat(message): """推送信息到微信""" - url = 'http://sc.ftqq.com/{}.send'.format(config.global_config.getRaw('messenger', 'sckey')) + url = 'http://sc.ftqq.com/{}.send'.format(config.settings('messenger', 'sckey')) payload = { "text":'抢购结果', "desp": message } headers = { - 'User-Agent':config.global_config.getRaw('config', 'DEFAULT_USER_AGENT') + 'User-Agent':config.settings('config', 'DEFAULT_USER_AGENT') } requests.get(url, params=payload, headers=headers) @@ -111,6 +111,6 @@ def open_image(image_file): def save_image(resp, image_file): - with open(image_file, 'wb') as f: + with open(config.path() + '/Static/img/' + image_file, 'wb') as f: for chunk in resp.iter_content(chunk_size=1024): f.write(chunk) diff --git a/Message/message.py b/Message/message.py index 1579f4d..ac131ef 100644 --- a/Message/message.py +++ b/Message/message.py @@ -5,8 +5,8 @@ import json import requests -from logger import logger -from config import global_config +from Logger.logger import logger +from Config.settings import config class Messenger(object): @@ -41,7 +41,7 @@ class Messenger(object): logger.error('Fail to send message [text: %s, desp: %s]: %s', text, desp, e) -sckey = global_config.getRaw("messenger", "sckey") +sckey = config.settings("Message", "sckey") message = Messenger(sckey) diff --git a/Server/api.py b/Server/api.py index cabeddb..051dff5 100644 --- a/Server/api.py +++ b/Server/api.py @@ -1,28 +1,25 @@ import copy -import psutil - from Config.settings import config +from Core.spider import Waiter +from threading import Thread +class Global(object): + + def __init__(self): + self.waiter = None + self.login = None + self.thread= None + + def update(self): + self.login = self.waiter.qrlogin.is_login + +glo = Global() def log(request): - file_path = config.path() + config.settings("Logger", "FILE_PATH") + config.settings("Logger", "FILE_NAME") + 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) @@ -32,3 +29,38 @@ def serverConfig(request): value = appConfig[model][item] # DEBUG print(model, item, value, type(value)) return appConfig + + +def jdShopper(request): + mode = request['mode'] + date = request['date'] + skuids = request['skuid'] + area = request['area'] + eid = request['eid'] + fp = request['fp'] + count = request['count'] + retry = request['retry'] + work_count = request['work_count'] + timeout = request['timeout'] + if mode == '1': + glo.waiter = Waiter(skuids=skuids, area=area, eid=eid, fp=fp, count=count, + retry=retry, work_count=work_count, timeout=timeout) + glo.thread = Thread(target=glo.waiter.waitForSell) + glo.thread.start() + elif mode == '2': + date = date.replace("T", " ") + date = date.replace("Z", "") + glo.waiter = Waiter(skuids=skuids, area=area, eid=eid, fp=fp, count=count, + retry=retry, work_count=work_count, timeout=timeout, date=date) + glo.thread = Thread(target=glo.waiter.waitTimeForSell) + glo.thread.start() + glo.update() + print(glo.login) + return glo.login + +def loginStatus(request): + try: + glo.update() + except: + pass + return glo.login diff --git a/Server/app.py b/Server/app.py new file mode 100644 index 0000000..2558257 --- /dev/null +++ b/Server/app.py @@ -0,0 +1,42 @@ +import subprocess +import sys +import os +from flask import request, Flask, make_response, render_template + +HOME = os.path.dirname(os.path.abspath(__file__)) + +app = Flask(__name__, + instance_path=HOME, + instance_relative_config=True, + template_folder="../Static", + static_folder="../Static", + static_url_path='') + +app.config['JSON_AS_ASCII'] = False + +@app.route("/") +def homePage(): + return render_template('index.html') + +@app.route('/api/zpy', methods=['POST', 'OPTIONS']) +def zpy(): + if request.method == 'POST': + code = request.json['code'] + output = subprocess.check_output([sys.executable, '-c', code]) + print(output.decode().encode()) + response = make_response(output.decode()) + response.headers['Access-Control-Allow-Origin'] = '*' + response.headers['Access-Control-Allow-Methods'] = 'GET,POST' + response.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type' + return response + else: + # CORS跨域配置 + response = make_response() + response.headers['Access-Control-Allow-Origin'] = '*' + response.headers['Access-Control-Allow-Methods'] = 'GET,POST' + response.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type' + return response + + +if __name__ == '__main__': + app.run(debug=False, host='0.0.0.0', port=5000) diff --git a/Server/handler.py b/Server/handler.py old mode 100755 new mode 100644 index 9f9e5bf..d5aaa1e --- a/Server/handler.py +++ b/Server/handler.py @@ -1,5 +1,4 @@ -import os, json -import time +import os, json, urllib, time from Logger.logger import logger from http.server import BaseHTTPRequestHandler @@ -16,6 +15,7 @@ class RequestHandler(BaseHTTPRequestHandler): def do_GET(self): self.rootPath = config.path() + "/Static" url = self.requestline[4:-9] + print(url) request_data = {} # 存放GET请求数据 try: if url.find('?') != -1: @@ -25,15 +25,35 @@ class RequestHandler(BaseHTTPRequestHandler): for i in parameters: key, val = i.split('=', 1) request_data[key] = val + #request_data['body'] = self.rfile.read() except: logger.error("URL Format Error") if (url == "/"): self.home() + elif (url == ""): + self.noFound() elif ("/api" in url): self.api(url[4:], request_data) else: self.file(url) + def do_POST(self): + LOCAL_HOST = config.settings("Server", "LOCAL_HOST") + PORT = config.settings("Server", "PORT") + hostLen = len(f'/{LOCAL_HOST}:{PORT}') + 5 + self.rootPath = config.path() + "/Static" + url = self.requestline[hostLen:-9] + request_data = json.loads(self.rfile.read(int(self.headers['content-length'])).decode()) + if (url == "/"): + self.home() + elif (url == ""): + self.noFound() + 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: @@ -103,7 +123,6 @@ class RequestHandler(BaseHTTPRequestHandler): # ---------------------------------------------------------------- # 此处写API content = urls(url, request_data) - # ---------------------------------------------------------------- localtime = time.localtime(time.time()) date = \ diff --git a/Server/url.py b/Server/url.py index a48662f..60c3604 100644 --- a/Server/url.py +++ b/Server/url.py @@ -1,7 +1,8 @@ -from Server.api import log, systemInfo, serverConfig +from Server.api import log, serverConfig, jdShopper, loginStatus def urls(url, request): if (url == "/log"): return log(request) - elif (url == "/system-info"): return systemInfo(request) elif (url == "/config"): return serverConfig(request) + elif (url == "/jd-shopper"): return jdShopper(request) + elif (url == "/jd-login-status"): return loginStatus(request) else: return "No Response" \ No newline at end of file diff --git a/Static/404.html b/Static/404.html new file mode 100644 index 0000000..5626558 --- /dev/null +++ b/Static/404.html @@ -0,0 +1,267 @@ + +
+ +NOT FOUND
+ + +