def post(self): name = request.form.get("username") pwd = request.form.get("password") if request.args.get("type", "") == "api": # API登陆, 返回token rds = get_redis("default") try: u = AdminUser.objects.get(username=name, password=md5(pwd), is_removed=0) tk = md5(str(time.time())) k = "token%s" % tk rds.set(k, u.username) rds.expire(k, 24*60*60) return jsonify({"code": 1, "message": "登陆成功", "token": tk}) except AdminUser.DoesNotExist: return jsonify({"code": 0, "message": "登陆失败"}) else: # 网页登陆 session["username"] = name session["password"] = pwd code = request.form.get("validcode", "") if not name.startswith("snmpay") and (not code or code != session.get("img_valid_code")): flash("验证码错误", "error") return redirect(url_for('dashboard.login')) try: u = AdminUser.objects.get(username=name, password=md5(pwd), is_removed=0) flask_login.login_user(u) return redirect(url_for('dashboard.index')) except AdminUser.DoesNotExist: flash("用户名或密码错误", "error") return redirect(url_for('dashboard.login'))
def remove_proxy(self, ipstr): rds = get_redis("default") del_cnt = rds.srem(RK_PROXY_IP_ALL, ipstr) if del_cnt: for c in self.consumer_list: c.on_producer_remove(ipstr) return del_cnt
def add_dealing(order, user): """ 分配给代购人员的单 """ rds = get_redis("order") key = RK_DEALING_ORDERS % user.username rds.sadd(key, order.order_no)
def current_proxy(self): rds = get_redis("default") ipstr = rds.get(RK_PROXY_CUR_CQKY) if ipstr and rds.sismember(RK_PROXY_IP_CQKY, ipstr): return ipstr ipstr = rds.srandmember(RK_PROXY_IP_CQKY) rds.set(RK_PROXY_CUR_CQKY, ipstr) return ipstr
def add_dealed_but_not_issued(order, user): if order.status in [ STATUS_GIVE_BACK, STATUS_ISSUE_SUCC, STATUS_ISSUE_FAIL, STATUS_LOCK_FAIL ]: return rds = get_redis("order") key = RK_DEALED_NOT_ISSUED % user.username rds.sadd(key, order.order_no)
def dealing_orders(user): rds = get_redis("order") key = RK_DEALING_ORDERS % user.username s_all = rds.smembers(key) qs = Order.objects.filter(order_no__in=s_all) s_exists = set(qs.distinct("order_no")) s_null = s_all - s_exists if s_null: rds.srem(key, *list(s_null)) return qs
def dequeue_wating_lock(user): rds = get_redis("order") def _cmp_rpop(k1, k2): v1, v2 = rds.lindex(k1, -1), rds.lindex(k2, -1) if v1 and v2: v1, t1 = v1.split("_") v2, t2 = v2.split("_") if t1 > t2: return rds.rpop(k2) return rds.rpop(k1) elif v1: v1, t1 = v1.split("_") return rds.rpop(k1) elif v2: v2, t2 = v2.split("_") return rds.rpop(k2) return "" val = "" if "yhzf" in user.source_include and "zfb" in user.source_include: val = _cmp_rpop(RK_ORDER_QUEUE_YH2, RK_ORDER_QUEUE_ZFB2) if not val: val = _cmp_rpop(RK_ORDER_QUEUE_YH, RK_ORDER_QUEUE_ZFB) elif "yhzf" in user.source_include: val = rds.rpop(RK_ORDER_QUEUE_YH2) if not val: val = rds.rpop(RK_ORDER_QUEUE_YH) elif "zfb" in user.source_include: val = rds.rpop(RK_ORDER_QUEUE_ZFB2) if not val: val = rds.rpop(RK_ORDER_QUEUE_ZFB) if val: no, t = val.split("_") order = Order.objects.get(order_no=no) if "snmpay" in user.username: if order.crawl_source not in SNMPAY_SOURCE: enqueue_wating_lock(order) return None elif rds.get("snmpay_ignore:%s" % order.order_no): enqueue_wating_lock(order) return None else: snmpay_users = AdminUser.objects.filter( is_switch=True, is_close=False, username__startswith="snmpay") if order.crawl_source in SNMPAY_SOURCE: if snmpay_users and not rds.get( "snmpay_ignore:%s" % order.order_no): enqueue_wating_lock(order) return None return order return None
def request_loader(request): token = request.headers.get("token", "") if not token: return None key = "token%s" % token rds = get_redis("default") try: u = AdminUser.objects.get(username=rds.get(key)) rds.expire(key, 24 * 60 * 60) except AdminUser.DoesNotExist: return None return u
def get_lock_request_info(self, order): rebot = order.get_lock_rebot() line = order.line riders = [] for r in order.riders: riders.append({ "idcard": r["id_number"], "mobile": r["telephone"], "passengername": r["name"], }) rds = get_redis("default") ipstr = rds.srandmember(RK_PROXY_IP_ZJGSM) if ipstr: ip = ipstr.split(":")[0] else: ip = "127.0.0.1" d = order.extra_info d["ip"] = ip order.modify(extra_info=d) data = { "ip": order.extra_info["ip"], "memberid": rebot.member_id, "source": "android", "mobile": order.contact_info["telephone"], "productname": "%s-%s" % (line.s_sta_name, line.d_sta_name), "name": order.contact_info["name"], "service_amount": order.ticket_amount * line.fee, "lstorderdetail": [{ "goods_id": str(line.extra_info["goodsid"]), "listordertickets": riders, "product_id": line.extra_info["productid"], "productname": "%s-%s" % (line.s_sta_name, line.d_sta_name), "qty": order.ticket_amount, "typeid": 1 }] } return {"data": json.dumps(data, ensure_ascii=False)}
def add_proxy(self, ipstr): """ Args: - ipstr eg: 127.0.0.1:88 """ rds = get_redis("default") add_cnt = rds.sadd(RK_PROXY_IP_ALL, ipstr) from tasks import check_add_proxy_ip if add_cnt: for c in self.consumer_list: # c.on_producer_add(ipstr) check_add_proxy_ip.delay(c.name, ipstr) return add_cnt
def clear_redis_data(): """ 清理redis数据 """ r = get_redis("default") now = time.time() result = {} for k in r.keys("line:done:*"): result[k] = 0 for sk, v in r.hgetall(k).items(): if now - float(v) > 12 * 60 * 60: r.hdel(k, sk) result[k] += 1 return result
def lock_ticket(self, order, **kwargs): """ 锁票主流程, 子类不用复写此方法 """ rds = get_redis("order") key = RK_ORDER_LOCKING % order.order_no if rds.get(key): return rds.set(key, time.time()) rds.expire(key, 60 * 5) try: ret = self.lock_ticket2(order, **kwargs) return ret finally: rds.delete(key)
def dealed_but_not_issued_orders(user): rds = get_redis("order") key = RK_DEALED_NOT_ISSUED % user.username s_all = set(rds.smembers(key)) qs = Order.objects.filter(order_no__in=s_all, status__nin=[ STATUS_GIVE_BACK, STATUS_ISSUE_SUCC, STATUS_ISSUE_FAIL, STATUS_LOCK_FAIL ], yc_status__ne=YC_STATUS_ING) s_not_issued = set(qs.distinct("order_no")) s_issued = s_all - s_not_issued if s_issued: rds.srem(key, *list(s_issued)) return qs
def valid_proxy(self, ipstr): rds = get_redis("default") key = RK_PROXY_IP_CQKY_BLACK % ipstr if rds.get(key): return False line_url = "http://www.96096kp.cn/UserData/MQCenterSale.aspx" tomorrow = dte.now() + timedelta(days=1) params = { "StartStation": "重庆主城", "WaitStationCode": "", "OpStation": -1, "OpAddress": -1, "DstNode": "成都", "SchDate": tomorrow.strftime("%Y-%m-%d"), "SeatType": "", "SchTime": "", "OperMode": "", "SchCode": "", "txtImgCode": "", "cmd": "MQCenterGetClass", "isCheck": "false", } headers = { "User-Agent": random.choice(BROWSER_USER_AGENT), "Referer": "http://www.96096kp.cn", "Origin": "http://www.96096kp.cn", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", } try: r = requests.post(line_url, data=urllib.urlencode(params), headers=headers, timeout=4, allow_redirects=False, proxies={"http": "http://%s" % ipstr}) content = r.content for k in set(re.findall("([A-Za-z]+):", content)): content = re.sub(r"\b%s\b" % k, '"%s"' % k, content) res = json.loads(content) except Exception, e: return False
def enqueue_wating_lock(order): """ 等待下单队列 """ now = dte.now() line = order.line rds = get_redis("order") val = "%s_%s" % (order.order_no, int(time.time() * 1000)) if (line.drv_datetime - now).total_seconds() <= 3 * 60 * 60 + 20: # 3个小时内的车优先处理 if order.crawl_source in YH_TYPE_SOURCE: # 银行支付 rds.lpush(RK_ORDER_QUEUE_YH2, val) else: rds.lpush(RK_ORDER_QUEUE_ZFB2, val) else: if order.crawl_source in YH_TYPE_SOURCE: # 银行支付 rds.lpush(RK_ORDER_QUEUE_YH, val) else: rds.lpush(RK_ORDER_QUEUE_ZFB, val)
def order_pay(order_no): params = request.values.to_dict() order = Order.objects.get(order_no=order_no) code = params.get("valid_code", "") force = int(params.get("force", "0")) if order.status not in [STATUS_WAITING_ISSUE, STATUS_LOCK_RETRY, STATUS_WAITING_LOCK]: return render_template('dashboard/error.html', title="出票结束", message="订单已经 %s, 不需要操作" % STATUS_MSG[order.status]) if order.kefu_username != current_user.username: return render_template('dashboard/error.html', title="禁止支付", message="请先要%s把单转给你再支付" % order.kefu_username) if order.status == 3 and (dte.now() - order.lock_datetime).total_seconds() > 8*60: return render_template('dashboard/error.html', title="禁止支付", message="锁票时间超过8分钟不允许支付") rds = get_redis("order") key = RK_ORDER_LOCKING % order.order_no if rds.get(key): return render_template('dashboard/error.html', title="正在锁票", message="正在锁票中, 不用重复点击, 请稍等一段时间后重新打开页面") flow = get_flow(order.crawl_source) ret = flow.get_pay_page(order, valid_code=code, session=session, bank=current_user.yh_type) if not ret: ret = {} flag = ret.get("flag", "") if flag == "url": cut = order.pay_money-order.order_price if cut and not force: msg = "订单金额和支付金额相差 %s 元, 禁止支付! <a href='%s'>继续支付</a>" % (cut,url_for("dashboard.order_pay", order_no=order.order_no, force=1)) return render_template('dashboard/error.html', title="禁止支付", message=msg) return redirect(ret["content"]) elif flag == "html": cut = order.pay_money-order.order_price if cut and not force: msg = "订单金额和支付金额相差 %s 元, 禁止支付! <a href='%s'>继续支付</a>" % (cut,url_for("dashboard.order_pay", order_no=order.order_no, force=1)) return render_template('dashboard/error.html', title="禁止支付", message=msg) return ret["content"] elif flag == "input_code": return render_template('dashboard/src-code-input.html', order=order, source_info=SOURCE_INFO) elif flag == "error": return render_template('dashboard/error.html', title="异常页面", message=ret["content"]) return render_template('dashboard/error.html', title="异常页面", message=str(json.dumps(ret,ensure_ascii = False)))
def starting_list(): params = request.values.to_dict() province = params.get("province", "") s_city = params.get("s_city", "") s_sta = params.get("s_sta", "") close_status = params.get("close_status", "") city_query = {} if province: city_query.update(province=province) if s_city: city_query.update(city_name=s_city) sta_query = {} if close_status: sta_query.update({"close_status": int(close_status)}) if s_sta: sta_query.update(sta_name__contains=s_sta) cqs = OpenCity.objects.filter(**city_query) qs = OpenStation.objects.filter(city__in=cqs, **sta_query) today_str = dte.now().strftime("%Y-%m-%d") rds = get_redis("line") line_stat = {} line_stat["total"] = int(rds.get(RK_DAY_LINE_STAT % (today_str, "total")) or 1) line_stat["succ"] = int(rds.get(RK_DAY_LINE_STAT % (today_str, "succ")) or 1) line_stat["percent"] = "%.2f%%" % ((line_stat["succ"]* 100)/float(line_stat["total"])) return render_template('dashboard/startings.html', page=parse_page_data(qs), source_info=SOURCE_INFO, condition=params, line_stat=line_stat, today_str=today_str, close_status_msg=STATION_CLOSE_MSG, )
def proxy_size(self): rds = get_redis("default") return rds.scard(self.PROXY_KEY)
def waiting_lock_size(): rds = get_redis("order") return rds.llen(RK_ORDER_QUEUE_YH) + rds.llen(RK_ORDER_QUEUE_YH2)+ \ rds.llen(RK_ORDER_QUEUE_ZFB) + rds.llen(RK_ORDER_QUEUE_ZFB2)
def do_refresh_line(self, line): result_info = { "result_msg": "", "update_attrs": {}, } rebot = XyjtWebRebot.get_one() url = 'http://order.xuyunjt.com/wsdgbccx.aspx' rds = get_redis("line") vs_key = "xyjt:viewstate:%s" % line.s_sta_id vs = rds.get(vs_key) or "" now = dte.now() headers = { "User-Agent": random.choice(BROWSER_USER_AGENT), "Content-Type": "application/x-www-form-urlencoded" } if not vs: # VIEWSTATE 各个站都不一样 try: r = rebot.http_get("http://order.xuyunjt.com/wsdgbccx.aspx", headers=headers) soup = bs(r.content, "lxml") vs = soup.select_one("#__VIEWSTATE").get("value") data = { 'ctl00$ContentPlaceHolder1$ScriptManager1': 'ctl00$ContentPlaceHolder1$ScriptManager1|ctl00$ContentPlaceHolder1$BtnBccx', '__EVENTARGUMENT': '', '__LASTFOCUS': '', '__VIEWSTATE': vs, 'ctl00$ContentPlaceHolder1$ddlincounty': line.s_sta_id, 'ctl00$ContentPlaceHolder1$ddlsaledate': line.drv_datetime.strftime("%Y%m%d"), 'ctl00$ContentPlaceHolder1$txtstop': u"南京", 'radio': u"南京", } r = rebot.http_post(url, headers=headers, data=urllib.urlencode(data)) soup = bs(r.content, 'lxml') except: result_info.update(result_msg="exception_ok_vserror", update_attrs={"left_tickets": 5, "refresh_datetime": now}) return result_info vs = soup.select_one("#__VIEWSTATE").get("value") rds.set(vs_key, vs) rds.expire(vs_key, 30*60*60) data = { 'ctl00$ContentPlaceHolder1$ScriptManager1': 'ctl00$ContentPlaceHolder1$ScriptManager1|ctl00$ContentPlaceHolder1$BtnBccx', 'ctl00$ContentPlaceHolder1$BtnBccx': '班次查询', '__EVENTARGUMENT': '', '__LASTFOCUS': '', '__VIEWSTATE': vs, 'ctl00$ContentPlaceHolder1$ddlincounty': line.s_sta_id, 'ctl00$ContentPlaceHolder1$ddlsaledate': line.drv_datetime.strftime("%Y%m%d"), 'ctl00$ContentPlaceHolder1$txtstop': line.d_city_name, 'radio': "", } try: r = rebot.http_post(url, headers=headers, data=urllib.urlencode(data)) soup = bs(r.content, 'lxml') except: result_info.update(result_msg="exception_ok", update_attrs={"left_tickets": 5, "refresh_datetime": now}) return result_info update_attrs = {} db_lines = {x.line_id: x for x in Line.objects.filter(s_city_name=line.s_city_name,d_city_name=line.d_city_name, drv_date=line.drv_date)} for tr_o in soup.select("#ctl00_ContentPlaceHolder1_GVBccx tr")[1:]: if tr_o.get("class") and "GridViewHeaderStyle" in tr_o.get("class"): continue td_lst = tr_o.select("td") index_tr = lambda idx: td_lst[idx].text.strip() drv_date, drv_time = index_tr(0), index_tr(5) if u"流水" in drv_time: continue drv_datetime=dte.strptime("%s %s" % (drv_date, drv_time), "%Y-%m-%d %H:%M") left_tickets=int(index_tr(8)) full_price=float(index_tr(6)) line_id_args = { "s_city_name": line.s_city_name, "d_city_name": line.d_city_name, "s_sta_name": unicode(index_tr(1)), "d_sta_name": unicode(index_tr(3)), "crawl_source": line.crawl_source, "drv_datetime": drv_datetime, } attrs = { "left_tickets": left_tickets, "refresh_datetime": now, "full_price": full_price, "extra_info__lock_url": td_lst[12].find("a").get("href"), } line_id = md5("%(s_city_name)s-%(d_city_name)s-%(drv_datetime)s-%(s_sta_name)s-%(d_sta_name)s-%(crawl_source)s" % line_id_args) if line_id in db_lines: db_lines[line_id].update(**attrs) if line_id == line.line_id: update_attrs = attrs if not update_attrs: result_info.update(result_msg="no line info", update_attrs={"left_tickets": 0, "refresh_datetime": now}) else: result_info.update(result_msg="ok", update_attrs=update_attrs) return result_info
def query_line_detail(): """ 查询线路详细信息, 此接口会从源网站拿最新数据。 Input: { "line_id": "1111" # 线路ID } """ req_data = request.get_data() post = json.loads(req_data) rds = get_redis("line") today_str = dte.now().strftime("%Y-%m-%d") rds.incr(RK_DAY_LINE_STAT % (today_str, "total"), 1) try: line = Line.objects.get(line_id=post["line_id"]) except Line.DoesNotExist: line_log.info("[fail-detail] 线路不存在 %s", post["line_id"]) return jsonify({"code": RET_LINE_404, "message": "线路不存在", "data": ""}) open_city = line.get_open_city() if not open_city or not open_city.is_active: line_log.info("[fail-detail] 未找到opencity或未打开 %s", line.line_id) return jsonify({ "code": RET_CITY_NOT_OPEN, "message": "%s is not open" % line.s_city_name, "data": "" }) open_station = open_city.get_open_station(line.s_sta_name) if not open_station: line_log.info("[fail-detail] 未找到openstation %s %s %s", line.line_id, line.s_city_name, line.s_sta_name) return jsonify({ "code": RET_CITY_NOT_OPEN, "message": "%s is not open" % line.s_sta_name, "data": "" }) if open_station.close_status & STATION_CLOSE_YZCX: data = line.get_json() data["left_tickets"] = 0 line_log.info("[fail-detail] 此站禁止余票查询%s %s, %s", line.line_id, line.s_city_name, line.s_sta_name) return jsonify({ "code": RET_OK, "message": "%s 余票查询已关闭" % line.s_sta_name, "data": data }) now_time = dte.now().strftime("%H:%M") if now_time > open_station.end_time or now_time < open_station.open_time: data = line.get_json() data["left_tickets"] = 0 line_log.info("[fail-detail] 售票时间不对%s %s, %s", line.line_id, line.s_city_name, line.s_sta_name) return jsonify({ "code": RET_OK, "message": "售票时间是%s~%s" % (open_station.open_time, open_station.end_time), "data": data }) flow, new_line = get_compatible_flow(line) if not flow: data = line.get_json() data["left_tickets"] = 0 line_log.info("[fail-detail] 未找到flow %s %s, %s", line.line_id, line.s_city_name, line.s_sta_name) return jsonify({"code": RET_OK, "message": "没找到对应flow", "data": data}) flow.refresh_line(new_line) data = new_line.get_json() data["line_id"] = line.line_id if data["left_tickets"] > 0: rds.incr(RK_DAY_LINE_STAT % (today_str, "succ"), 1) return jsonify({"code": RET_OK, "message": "OK", "data": data})
def get_proxy(self): rds = get_redis("default") ipstr = rds.srandmember(RK_PROXY_IP_ALL) return ipstr
def dealing_order(): for o in assign.dealing_orders(current_user): if o.status in [STATUS_LOCK_RETRY, STATUS_WAITING_LOCK, STATUS_WAITING_ISSUE]: continue o.complete_by(current_user) total = assign.waiting_lock_size() if total > 8: kf_order_cnt = 5 else: kf_order_cnt = 3 rds = get_redis("order") key = "assigned:time:%s" % current_user.username last_assign = rds.get(key) can_refresh = True if last_assign and (time.time()-float(last_assign)) < 2.5: # 请求太频繁 can_refresh = False if current_user.is_switch and not current_user.is_close and can_refresh: rds.set(key, time.time()) for i in range(2): order_ct = assign.dealing_size(current_user) if order_ct >= kf_order_cnt: break order = assign.dequeue_wating_lock(current_user) if not order: continue if order.kefu_username: continue order.update(kefu_username=current_user.username, kefu_assigntime=dte.now()) assign.add_dealing(order, current_user) info = {"username": current_user.username} desc = "订单分派给操作人员 %s" % info["username"] order.add_trace(OT_ASSIGN, desc, info) if order.status == STATUS_WAITING_LOCK: async_lock_ticket.delay(order.order_no) tab = request.args.get("tab", "dealing") qs = assign.dealed_but_not_issued_orders(current_user) dealed_count = qs.count() yichang_count = Order.objects.filter(kefu_username=current_user.username, yc_status=YC_STATUS_ING).count() if tab == "dealing": qs = assign.dealing_orders(current_user).order_by("create_date_time") elif tab == "yichang": qs = Order.objects.filter(kefu_username=current_user.username, yc_status=YC_STATUS_ING) if request.args.get("type", "") == "api": lst = [] for o in qs: d = {"order_no": o.order_no, "crawl_source": o.crawl_source, "status":o.status} lst.append(d) return jsonify({"code":1, "message": "ok", "orders": lst}) else: locking = {} dealing_seconds = {} for o in qs: if rds.get(RK_ORDER_LOCKING % o.order_no): locking[o.order_no] = 1 else: locking[o.order_no] = 0 dealing_seconds[o.order_no] = (dte.now()-o.kefu_assigntime).total_seconds() return render_template("dashboard/dealing.html", tab=tab, dealing_seconds=dealing_seconds, page=parse_page_data(qs), status_msg=STATUS_MSG, source_info=SOURCE_INFO, dealing_count=assign.waiting_lock_size()+assign.dealing_size(current_user), dealed_count=dealed_count, yichang_count=yichang_count, all_user=AdminUser.objects.filter(is_removed=0), pay_status_msg = PAY_STATUS_MSG, locking=locking)
def all_proxy(self): rds = get_redis("default") return rds.smembers(RK_PROXY_IP_ALL)
def proxy_size(self): rds = get_redis("default") return rds.scard(RK_PROXY_IP_ALL)
def add_proxy(self, ipstr): rds = get_redis("default") add_cnt = rds.sadd(self.PROXY_KEY, ipstr) return add_cnt
def set_black(self, ipstr): rds = get_redis("default") key = RK_PROXY_IP_CQKY_BLACK % ipstr rds.set(key, time.time()) rds.expire(key, 60 * 60 * 5) self.remove_proxy(ipstr)
def clear_current_proxy(self): rds = get_redis("default") return rds.set(RK_PROXY_CUR_CQKY, "")
def remove_proxy(self, ipstr): rds = get_redis("default") del_cnt = rds.srem(self.PROXY_KEY, ipstr) return del_cnt
def all_proxy(self): rds = get_redis("default") return rds.smembers(self.PROXY_KEY)