rabin 7 years ago
parent
commit
e6e87e7c51
12 changed files with 334 additions and 50 deletions
  1. 43 5
      admin/page/site.py
  2. 1 1
      admin/templates/main.html
  3. 1 0
      conf/dev.conf
  4. 3 2
      conf/env.conf
  5. 14 36
      cron.py
  6. 14 4
      demo/ssgdfs.py
  7. 18 0
      model/order.py
  8. 1 2
      model/product.py
  9. 21 0
      service/__load__.py
  10. 54 0
      service/product.py
  11. 150 0
      service/ssgdfs.py
  12. 14 0
      task.py

+ 43 - 5
admin/page/site.py

@@ -64,27 +64,38 @@ class product_path(Load):
 			,width = '600'
 			,height = '600'
 			,search = (('label-1','cdate-time-start','cdate-time-end','site_id-select-','name-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'选择站点',u'商品名'))
-			,thead = (u'所属站点', u'商品名', u'商品链接', u'更新时间')
-			,tbody = ('site', 'name', 'link', 'cdate')
+			,thead = (u'所属站点', u'商品名', u'状态', u'更新时间')
+			,tbody = ('site', 'name', 'status', 'cdate')
 			,state = True
 		)
 		self.data['common']['search_site_id-select-'] = self.service('common').list('site')
 		self.commonList('product')
+		status = {}
+		status[1] = '待机'
+		status[2] = '入队'
+		status[3] = '抢购中'
+		status[4] = '抢购完成'
 		if self.data['list']:
 			for key, value in enumerate(self.data['list']):
 				site = self.service('common').one('site', id=value['site_id'])
 				self.data['list'][key]['site'] = site['name']
+				self.data['list'][key]['status'] = '<a href="/site/order?search_product_id-select-='+str(value['id'])+'">'+status[value['status']]+'[查看二维码]</a>'
+
 		self.commonView('list')
 
 class product_update_path(Load):
 	@Web.auth
 	@Web.setting
 	def get(self):
+		status = [
+			{'id':'1', 'name': '待机-如果之前抢购完成,选择此项可以重新开始抢购'},
+		]
 		self.common(
 			path = '/site/product'
-			,label = (u'所属站点', u'商品名称', u'商品链接')
-			,update = ('site_id-select-required', 'name-input-required','link-input-required')
+			,label = (u'所属站点', u'商品名称', u'商品链接', u'状态控制')
+			,update = ('site_id-select-required', 'name-input-required','link-input-required', 'status-select-required')
 			,update_site_id = self.service('common').list('site')
+			,update_status = status
 		)
 		self.commonOne('product')
 		self.commonView('update')
@@ -95,4 +106,31 @@ class product_update_path(Load):
 	@Web.auth
 	@Web.setting
 	def delete(self):
-		self.commonDelete('product')
+		self.commonDelete('product')
+
+class order_path(Load):
+	@Web.auth
+	@Web.setting
+	def get(self):
+		self.common(
+			name = u'商品订单列表'
+			,path = '/site/order'
+			,width = '600'
+			,height = '600'
+			,edit = False
+			,add = False
+			,search = (('label-1','cdate-time-start','cdate-time-end', 'orderID-input-mlike'), (u'日期范围',u'开始时间',u'截止时间',u'订单ID'))
+			,thead = (u'商品名称', u'订单ID', u'二维码', u'更新时间')
+			,tbody = ('name', 'orderID', 'pic', 'cdate')
+			,state = False
+		)
+		#self.data['common']['search_product_id-select-'] = self.service('common').list('product')
+		self.commonList('order')
+		if self.data['list']:
+			for key, value in enumerate(self.data['list']):
+				product = self.service('common').one('product', id=value['product_id'])
+				self.data['list'][key]['name'] = product['name']
+				value['pic'] = value['pic'].replace(Demeter.path + 'runtime', '')
+				self.data['list'][key]['pic'] = '<img src="'+value['pic']+'" width="200px" />'
+
+		self.commonView('list')

+ 1 - 1
admin/templates/main.html

@@ -6,7 +6,7 @@
     <body>
         <div class="x-body">
             <blockquote class="layui-elem-quote">
-                欢迎使用农小盒后台管理系统<span class="f-14">v1.0.0</span>
+                欢迎使用Demeter后台管理系统<span class="f-14">v1.0.0</span>
             </blockquote>
 
             <table class="layui-table" style="display:none;">

+ 1 - 0
conf/dev.conf

@@ -4,6 +4,7 @@
 name				= 抢购平台
 site				= http://www.dever.cc/
 copyright			= 2017 dever.cc v1.0.0
+phantomjs			= http://192.168.15.10:8910/
 
 [db]
 rdb					= postgresql

+ 3 - 2
conf/env.conf

@@ -4,10 +4,11 @@
 name				= 抢购程序
 site				= http://www.dever.cc/
 copyright			= 2017 dever.cc v1.0.0
+phantomjs			= http://py-phantomjs:8910/
 
 [db]
-rdb					= mysql
-;tsdb				= influxdb
+;rdb				= mysql
+rdb					= postgresql
 
 [mysql]
 host				= buy-mysql

+ 14 - 36
cron.py

@@ -1,54 +1,32 @@
-#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 """
     demeter web
-    name:admin.py
+    name:cron.py
     author:rabin
 """
 import time
 from demeter.core import *
 from gevent import monkey; monkey.patch_socket()
 import gevent
-from pic import pic
-from demeter.mqtt import *
-# 处理定时命令、周期命令、条件控制、消息、设备状态等
-timeSleep = 10
-				
-# 更改设备状态(离线)
-def device():
-	while 1:
-		model = Demeter.model('device_info')
-		cur = Demeter.time() - 1800
-		model.cdate.assgin(cur, '<=')
-		model.status = True
-		data = model.select()
-		for v in data:
-			model.id = v['id']
-			if v['hardware_type'] == 5:
-				model.update(value='0', status=False)
-			elif v['hardware_type'] != 7 and v['hardware_type'] != 6:
-				model.update(status=False)
-		gevent.sleep(60)
+timeSleep = 60
 
-def savePic():
-	while 1:
-		pic()
-		gevent.sleep(1800)
 
-# 同步时间,24小时同步一次
-def timeSync():
+def run(id, name):
+	product = Demeter.service('product')
+	config = product.get(id)
+	if config:
+		service = Demeter.service(name)
+		service.init(config)
+		service.start()
+
+def ssgdfs():
 	while 1:
-		pub = Pub()
-		key = 'time/bh'
-		value = Demeter.date(Demeter.time())
-		pub.push(key, value)
-		gevent.sleep(3600*24)
+		run(1, 'ssgdfs')
+		gevent.sleep(timeSleep)
 
 def handle():
 	gevent.joinall([
-		gevent.spawn(device),
-		#gevent.spawn(savePic),
-		gevent.spawn(timeSync),
+		gevent.spawn(ssgdfs),
 	])
 
 handle()

+ 14 - 4
site/ssgdfs.py → demo/ssgdfs.py

@@ -1,5 +1,6 @@
 # -*- coding: utf-8 -*-
 import unittest
+import requests
 from selenium import webdriver
 from time import sleep
 from selenium.webdriver.common.keys import Keys
@@ -8,7 +9,7 @@ from selenium.webdriver.support import expected_conditions as EC
 from selenium.webdriver.common.by import By
 from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
 
-class PythonOrgSearch(unittest.TestCase):
+class Ssgdfs(object):
 
 	def setUp(self):
 		#self.driver = webdriver.Chrome('E:\chromedriver_win32/chromedriver')
@@ -21,7 +22,7 @@ class PythonOrgSearch(unittest.TestCase):
 		self.config['product'] = 'http://cn.ssgdfs.com/shop/product/productDetail?recopick=25&prdtCode=79519000009';
 		self.config['chuguo'] = '3239636'
 
-	def test_search_in_python_org(self):
+	def test_start(self):
 		# 登录
 		self.login()
 		# 下单
@@ -31,6 +32,16 @@ class PythonOrgSearch(unittest.TestCase):
 		# 支付截图
 		self.crop()
 
+	def check():
+		r = requests.get(self.config['product'])
+		# 缺货标识
+		string = 'http://image2.ssgdfs.com/images/shop/cn/renewal/content/btn_soldout.gif'
+		data = r.text
+		if string in data:
+			return False
+		else:
+			return True
+
 	def login(self):
 		self.driver.get(self.config['login'])
 		self.driver.find_element_by_id('login-id').send_keys(self.config['username'])
@@ -100,6 +111,5 @@ class PythonOrgSearch(unittest.TestCase):
 		self.driver.close()
 		#pass
 
-
 if __name__ == "__main__":
-	unittest.main()
+    unittest.main()

+ 18 - 0
model/order.py

@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter database
+    name:order.py
+    author:rabin
+"""
+from __load__ import *
+
+class Order(Model):
+	__table__ = 'order'
+	__comment__ = '订单表'
+	id = Fields(type='int', primaryKey=True, autoIncrement=True, comment='订单ID')
+	orderID = Fields(type='varchar(500)', comment='原订单ID')
+	pic = Fields(type='varchar(300)', comment='订单图片')
+	site_id = Fields(type='int', comment='所属站点')
+	product_id = Fields(type='int', comment='商品id')
+	state = Fields(type='boolean', default='True', comment='数据存在状态')
+	cdate = Fields(type='int', default='time', comment='创建时间')

+ 1 - 2
model/product.py

@@ -14,6 +14,5 @@ class Product(Model):
 	link = Fields(type='varchar(500)', comment='商品链接')
 	site_id = Fields(type='int', comment='所属站点')
 	state = Fields(type='boolean', default='True', comment='数据存在状态')
-	qdate = Fields(type='int', comment='抢购生成网页截图的时间')
-	status = Fields(type='boolean', default='False', comment='抢购状态')
+	status = Fields(type='int', default='1', comment='抢购状态1待机2入队3抢购中4抢购完成')
 	cdate = Fields(type='int', default='time', comment='创建时间')

+ 21 - 0
service/__load__.py

@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+    demeter service
+    name:__load__.py
+    author:rabin
+"""
+import unittest
+import requests
+from selenium import webdriver
+from time import sleep
+from selenium.webdriver.common.keys import Keys
+from selenium.webdriver.support.wait import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.common.by import By
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from demeter.core import *
+from product import *
+from gevent import monkey; monkey.patch_socket()
+import gevent
+import random

+ 54 - 0
service/product.py

@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter service
+    name:product.py 商品业务
+    author:rabin
+"""
+from demeter.core import *
+import random
+
+class Product(object):
+	def get(self, site_id):
+		model = Demeter.model('site')
+		model.id = site_id
+		site = model.select(type='fetchone')
+		if site:
+			model = Demeter.model('product')
+			model.site_id = site_id
+			model.status = 1
+			product = model.select()
+			if product:
+				site['product'] = product
+				return site
+		return False
+
+	def status(self, id, value):
+		model = Demeter.model('product')
+		model.id = id
+		return model.update(status=value)
+
+	def order(self, order, pic, site_id, product_id):
+		model = Demeter.model('order')
+		model.orderID = order
+		model.pic = pic
+		model.site_id = site_id
+		model.product_id = product_id
+		return model.insert()
+
+	def createOrderId(self, order, site_id, product_id):
+		if not order:
+			order = self.code(product_id)
+		return order
+
+	def code(self, product_id):
+		cdate = Demeter.date(Demeter.time(), '%Y%m%d%H%M%S')
+		min = 1000
+		max = 9999
+		order = 'CN' + str(product_id + 10000) + '-' + str(cdate) + str(random.randint(min, max))
+		model = Demeter.model('order')
+		model.orderID = order
+		info = model.select(type='fetchone')
+
+		if info:
+			return self.get(self, product_id)
+		return order

+ 150 - 0
service/ssgdfs.py

@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter service
+    name:ssgdfs.py ssgdfs网站抢单业务
+    author:rabin
+"""
+from __load__ import *
+
+class Ssgdfs(object):
+	def init(self, config):
+		self.config = config
+
+	def start(self):
+		if 'product' in self.config and self.config['product']:
+			# 打开浏览器
+			self.open()
+			# 登录
+			self.login()
+			# 开始进入抢购下单核心程序
+			self.core()
+			# 关闭
+			self.close()
+
+	def core(self):
+		# 开启多任务
+		task = []
+		for v in self.config['product']:
+			task.append(gevent.spawn(self.buy, v))
+		gevent.joinall(task)
+
+	def buy(self, config):
+		product = Demeter.service('product')
+		product.status(config['id'], 2)
+		while 1:
+			state = self.check(config['link'])
+			if state == True:
+				try:
+					product.status(config['id'], 3)
+					# 下单
+					self.order(config['link'])
+					# 支付并获取支付id
+					order = product.createOrderId(self.pay(), config['site_id'], config['id'])
+					# 支付截图
+					pic = self.crop(order, config['id'])
+					# 生成订单
+					product.order(order, pic, config['site_id'], config['id'])
+					product.status(config['id'], 4)
+					break
+				except Exception:
+					print 'error'
+					continue
+				else:
+					continue
+			else:
+				gevent.sleep(30)
+
+	def check(self, product):
+		r = requests.get(product)
+		# 缺货标识
+		string = 'http://image2.ssgdfs.com/images/shop/cn/renewal/content/btn_soldout.gif'
+		data = r.text
+		if string in data:
+			return False
+		else:
+			return True
+
+	def open(self):
+		self.driver = webdriver.Remote(command_executor=Demeter.config['setting']['phantomjs'], desired_capabilities=DesiredCapabilities.PHANTOMJS)
+
+	def login(self):
+		self.driver.get(self.config['login_link'])
+		self.driver.find_element_by_id('login-id').send_keys(self.config['username'])
+		self.driver.find_element_by_id('login-password').send_keys(self.config['password'])
+		self.driver.find_element_by_xpath('//input[@alt="login"]').click()
+		self.driver.implicitly_wait(5)
+
+	def order(self, product):
+		self.driver.get(product)
+		# 立刻购买
+		self.driver.execute_script('directOrderProduct()')
+		# 等待加载页面完成
+		self.wait('long-sub')
+		# 等待弹层关闭
+		self.waitNot('pay_popup')
+		# 输入下单信息
+		self.order_content()
+		# 确认订单
+		self.driver.execute_script('goPaymentCheck()')
+		# 等待加载页面完成
+		self.wait('order-agree2')
+
+	def order_content(self):
+		# 选择护照信息
+		#self.driver.execute_script('setExitInfoHistory("' + self.config['chuguo'] + '")')
+		#self.driver.execute_script('setExitInfoHistory("3239636")')
+		self.driver.find_element_by_class_name('btn-popup-exitInfo').click()
+		exit = self.driver.find_elements_by_class_name('btn-red')
+		exitLength = len(exit)-1
+		rand = random.randint(0, exitLength)
+		exit[rand].click()
+
+		# 使用优惠券
+		# 使用积分
+		self.driver.find_element_by_xpath('//input[@name="nowUse" and @value="0"]').click()
+
+	def pay(self):
+		# 等待弹层关闭
+		self.waitNot('loding_popup')
+		# 输入支付信息
+		self.pay_content()
+		# 确认按钮
+		self.driver.execute_script('window.confirm = function(msg) { return true; }');
+		# 同意付款
+		self.driver.execute_script('$("a.goPayment").click()')
+		#self.driver.switch_to_alert().accept()
+		#self.wait('qrcode-img-wrapper')
+		self.wait('qrcode')
+		sleep(2)
+		# 获取当前链接,没啥用
+		#link = self.driver.execute_script('return location.href')
+		# 获取订单号 这里获取不到,直接生成吧
+		order = False
+		return order
+
+	def pay_content(self):
+		# 确认取货处
+		self.driver.find_element_by_id('exitDestInfo').click()
+		# 同意收集个人信息
+		self.driver.find_element_by_id('agree').click()
+		# 同意订购
+		self.driver.find_element_by_id('agree01').click()
+		# 选择支付方式:支付宝21 微信00
+		self.driver.find_element_by_xpath('//input[@id="pymntMeansCode" and @value="00"]').click()
+
+	def crop(self, order, id):
+		path = Demeter.path + 'runtime/upload/'
+		if not File.exists(path):
+			File.mkdir(path)
+		pic = path + str(id) + '_' + str(order) + '.png'
+		self.driver.save_screenshot(pic)
+		return pic
+
+	def waitNot(self, name):
+		WebDriverWait(self.driver, 100).until_not(lambda x: x.find_element_by_class_name(name).is_displayed())
+
+	def wait(self, name):
+		WebDriverWait(self.driver, 100).until(lambda x: x.find_element_by_class_name(name).is_displayed())
+
+	def close(self):
+		self.driver.close()

+ 14 - 0
task.py

@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+"""
+    demeter web
+    name:site.py
+    author:rabin
+"""
+from demeter.core import *
+from celery import Celery,platforms
+platforms.C_FORCE_ROOT = True
+app = Celery('task',  backend='redis://0.0.0.0:6379/0', broker='redis://0.0.0.0:6379/0') #配置好celery的backend和broker
+ 
+@app.task  #普通函数装饰为 celery task
+def add(x, y):
+    return x + y