tornado_api.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. from wechat_action.sql_models import DB
  2. from settings import using_config
  3. import tornado.log
  4. import tornado.ioloop
  5. import tornado.web
  6. import json
  7. from wechat_api.get_wechat_info import WechatApi
  8. from wechat_action.login_ad import LogIn
  9. from wechat_action import sql_tools
  10. import threading
  11. from web_module import user_action
  12. from sqlalchemy import Table
  13. import pickle
  14. # TODO:需要添加上supervisor,来维护进程
  15. # TODO:有时间需要对tornado进行改进
  16. # TODO:需要有一套上线工具,来维持线上稳定
  17. db = DB(config=using_config)
  18. wechat_cookies_table = Table('wechat_cookies', db.metadata,
  19. autoload=True, autoload_with=db.engine)
  20. layout_typesetting_table = Table('layout_typesetting', db.metadata,
  21. autoload=True, autoload_with=db.engine)
  22. ad_plan_typesetting_table = Table('ad_plan_typesetting', db.metadata,
  23. autoload=True, autoload_with=db.engine)
  24. # 1.实现本机服务
  25. # 2.实现线上docker-selenium服务
  26. class BaseHandler(tornado.web.RequestHandler):
  27. def options(self):
  28. pass
  29. def set_default_headers(self):
  30. self.set_header('Access-Control-Allow-Origin', '*')
  31. self.set_header('Access-Control-Allow-Headers', '*')
  32. self.set_header('Access-Control-Max-Age', 1000)
  33. self.set_header('Content-type', '*')
  34. self.set_header('Access-Control-Allow-Methods', '*')
  35. class create_ad_plan_remote(BaseHandler):
  36. # 1.批量创建计划
  37. # 返回创建计划是否已经开始
  38. def post(self):
  39. user_id = self.get_argument("user_id", None)
  40. ad_plan_name = self.get_argument("ad_plan_name", None)
  41. # wechat_json :[{'service_name':'one','wechat_name':''},{'service_name':'','wechat_name':''}]
  42. wechat_json = self.get_argument('wechat_json', None)
  43. log_ad, cookie_canuse = ad_human_info.refresh_wechat_cookies(self, user_id=user_id)
  44. threading.Thread(target=user_action.create_ad_plan,
  45. args=(user_id, ad_plan_name, wechat_json, log_ad, db, cookie_canuse)).start()
  46. class create_ad_plan_local(BaseHandler):
  47. def post(self):
  48. user_id = self.get_argument("user_id", None)
  49. ad_plan_typesetting = self.get_argument("plan_typesetting", None)
  50. ad_plan_name = self.get_argument("plan_name", None)
  51. print(user_id, ad_plan_typesetting, ad_plan_name)
  52. sql_session = db.DBSession()
  53. if user_id is None or ad_plan_name is None or ad_plan_typesetting is None:
  54. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  55. return
  56. # 落地页名字精确到毫秒,默认是全局唯一
  57. # TODO:检查一下plan--内容 有无问题-----和前端确定一下
  58. ad_plan_typesetting_info = {'user_id': user_id, 'name': ad_plan_name, 'typesetting': ad_plan_typesetting}
  59. ad_plan_typesetting_inserte = sql_tools.save_ad_plan_typesetting_info(
  60. ad_plan_typesetting_info=ad_plan_typesetting_info,
  61. table_ad_plan_typesetting=ad_plan_typesetting_table)
  62. sql_session.execute(ad_plan_typesetting_inserte)
  63. sql_session.commit()
  64. self.write({'status': {'msg': 'success', "RetCode": 200}})
  65. class get_ad_plan_local(BaseHandler):
  66. def get(self):
  67. user_id = self.get_argument('user_id', None)
  68. layout_name = self.get_argument('plan_name', None)
  69. sql_session = db.DBSession()
  70. if user_id is None:
  71. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  72. return
  73. # 落地页名字精确到毫秒,默认是全局唯一
  74. if layout_name:
  75. result = sql_tools.get_plan_typesetting_rough(sql_session=sql_session, user_id=user_id,
  76. typesetting_name=layout_name)
  77. else:
  78. # TODO:之后修改一下,让其查询效率高点,like效率过低
  79. layout_name = ''
  80. result = sql_tools.get_plan_typesetting_rough(sql_session=sql_session, user_id=user_id,
  81. typesetting_name=layout_name)
  82. print(result)
  83. result_ = []
  84. for i in range(len(result)):
  85. print(result[i])
  86. typesetting, name, create_time, update_time = result[i]
  87. _ = {}
  88. _['typesetting'] = json.loads(typesetting)
  89. _['ad_plan_name'] = name
  90. _['id'] = i
  91. _['create_time'] = create_time.strftime("%Y-%m-%d %H:%M:%S")
  92. _['update_time'] = update_time.strftime("%Y-%m-%d %H:%M:%S")
  93. result_.append(_)
  94. self.write({'statu': {'msg': 'success', "RetCode": 200},
  95. 'local_ad_plan_info': result_})
  96. class create_ad_layout_remote(BaseHandler):
  97. # 1.批量创建落地页
  98. def post(self):
  99. user_id = self.get_argument("user_id", None)
  100. layout_name = self.get_argument("layout_name", None)
  101. # wechat_json :[{'service_name':'one','wechat_name':''},{'service_name':'','wechat_name':''}]
  102. wechat_json = self.get_argument('wechat_json', None)
  103. log_ad, cookie_canuse = ad_human_info.refresh_wechat_cookies(self, user_id=user_id)
  104. threading.Thread(target=user_action.create_layout,
  105. args=(user_id, layout_name, wechat_json, log_ad, db, cookie_canuse)).start()
  106. class create_ad_layout_local(BaseHandler):
  107. def post(self):
  108. # TODO:返回一个layout_name重复的一个信息
  109. request_dict = json.loads(self.request.body)
  110. user_id = request_dict['user_id']
  111. layout_typesetting = request_dict['layout_typesetting']
  112. layout_name = request_dict['layout_name']
  113. print(user_id, layout_typesetting, layout_name)
  114. print('layout-typesetting', type(layout_typesetting), layout_typesetting)
  115. sql_session = db.DBSession()
  116. if user_id is None or layout_name is None or layout_typesetting is None:
  117. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  118. return
  119. # 落地页名字精确到毫秒,默认是全局唯一
  120. layout_typesetting_info = {'user_id': user_id, 'name': layout_name,
  121. 'typesetting': layout_typesetting}
  122. layout_typesetting_inserte = sql_tools.save_layout_typesetting_info(
  123. layout_typesetting_info=layout_typesetting_info,
  124. table_layout_typesetting=layout_typesetting_table)
  125. sql_session.execute(layout_typesetting_inserte)
  126. sql_session.commit()
  127. self.write({'status': {'msg': 'success', "RetCode": 200}})
  128. class get_ad_layout_local(BaseHandler):
  129. def get(self):
  130. user_id = self.get_argument('user_id', None)
  131. layout_name = self.get_argument('layout_name', None)
  132. sql_session = db.DBSession()
  133. if user_id is None:
  134. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  135. return
  136. # 落地页名字精确到毫秒,默认是全局唯一
  137. if layout_name:
  138. result = sql_tools.get_layout_typesetting_rough(sql_session=sql_session, user_id=user_id,
  139. typesetting_name=layout_name)
  140. else:
  141. # TODO:之后修改一下,让其查询效率高点,like效率过低
  142. layout_name = ''
  143. result = sql_tools.get_layout_typesetting_rough(sql_session=sql_session, user_id=user_id,
  144. typesetting_name=layout_name)
  145. print(result)
  146. result_ = []
  147. for i in range(len(result)):
  148. print(result[i])
  149. typesetting, name, create_time, update_time = result[i]
  150. _ = {}
  151. _['typesetting'] = json.loads(typesetting)
  152. _['layout_name'] = name
  153. _['id'] = i
  154. _['create_time'] = create_time.strftime("%Y-%m-%d %H:%M:%S")
  155. _['update_time'] = update_time.strftime("%Y-%m-%d %H:%M:%S")
  156. result_.append(_)
  157. self.write({'statu': {'msg': 'success', "RetCode": 200},
  158. 'local_layout_info': result_})
  159. # TODO:wechat_info,human_info 这两张表有空时需要进行对应改进
  160. class ad_status(BaseHandler):
  161. def get(self):
  162. user_id = self.get_argument("user_id", None)
  163. if user_id is None:
  164. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  165. return
  166. sql_session = db.DBSession()
  167. lines = sql_tools.get_ad_status(sql_session=sql_session, user_id=user_id)
  168. result = []
  169. for line in lines:
  170. action_type, wechat_name, service_name, update_time, create_time, status = line
  171. result.append(
  172. {'action_type': json.loads(action_type), 'wechat_name': wechat_name, 'service_name': service_name,
  173. 'update_time': update_time.strftime("%Y-%m-%d %H:%M:%S"),
  174. 'create_time': create_time.strftime("%Y-%m-%d %H:%M:%S"), 'status': status})
  175. # result = json.loads(result)
  176. print(result)
  177. self.write({'status': {'msg': 'success', "RetCode": 200},
  178. 'ad_status_info': result})
  179. class ad_human_info(BaseHandler):
  180. # TODO:不允许短时间,刷新
  181. @staticmethod
  182. def refresh_wechat_cookies(tornado_web, user_id):
  183. # 1.返回二维码链接
  184. # ----1.查看cookie是否可用
  185. sql_session = db.DBSession()
  186. cookie_db = sql_tools.get_wechat_cookies(sql_session, user_id=user_id)
  187. # 进行登录操作
  188. log_ad = LogIn()
  189. # 使driver可以使用
  190. cookie_canuse = False
  191. if cookie_db:
  192. cookie_db = pickle.loads(cookie_db)
  193. # TODO:log 日志需要进行对应配置
  194. if not log_ad.wechat_cookies_check_alive(cookie_db):
  195. # cookie 不能使用
  196. wechat_code = log_ad.log_in()
  197. tornado_web.write({'status': {'msg': 'success', "RetCode": 200},
  198. 'wechat_code': wechat_code})
  199. print('cookie can not use')
  200. else:
  201. # cookie 可以继续使用
  202. cookie_canuse = True
  203. log_ad.driver.get('https://a.weixin.qq.com/index.html')
  204. tornado_web.write({'status': {'msg': 'success', "RetCode": 200}})
  205. else:
  206. # cookie 不能使用
  207. wechat_code = log_ad.log_in()
  208. tornado_web.write({'status': {'msg': 'success', "RetCode": 200},
  209. 'wechat_code': wechat_code})
  210. return log_ad, cookie_canuse
  211. # 1.人群包获取
  212. def get(self):
  213. # TODO:添加分页
  214. # 0.是否刷新
  215. # 1.获取userid,以及是否刷新
  216. user_id = self.get_argument("user_id", None)
  217. human_package_name = self.get_argument('human_package_name', None)
  218. is_refresh = self.get_argument("is_refresh", None)
  219. wechat_name = self.get_argument('wechat_name', None)
  220. service_name = self.get_argument('service_name', None)
  221. print(user_id, is_refresh)
  222. if user_id is None or is_refresh is None or wechat_name is None or service_name is None:
  223. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  224. return
  225. sql_session = db.DBSession()
  226. # TODO:一个涉及到selenium-driver的请求-生命周期.----看一下tornado是怎么处理请求的生命周期
  227. if int(is_refresh) == 1:
  228. log_ad, cookie_canuse = self.refresh_wechat_cookies(self, user_id=user_id)
  229. threading.Thread(target=user_action.get_human_info,
  230. args=(
  231. user_id, log_ad, db, cookie_canuse)).start()
  232. else:
  233. # 1.查看是否在刷新,
  234. # 在刷新中,
  235. # 返回正在刷新
  236. # -------不管上面逻辑让他们多刷新几次
  237. # 不在刷新
  238. # 返回对应数据
  239. # 2.获取userid对应数据
  240. result = sql_tools.get_human_info(sql_session=sql_session,
  241. service_name=service_name, wechat_name=wechat_name)
  242. print(result)
  243. result = json.loads(result)
  244. if human_package_name:
  245. result = [_ for _ in result if human_package_name in _['name']]
  246. result_ = []
  247. for i in range(len(result)):
  248. _ = result[i]
  249. _['id'] = i
  250. result_.append(_)
  251. self.write({'status': {'msg': 'success', "RetCode": 200},
  252. 'human_info': result})
  253. class ad_wechat_info(BaseHandler):
  254. # 1.公众号相关信息获取
  255. def get(self):
  256. # TODO:添加分页,
  257. # 公众号,服务商,唯一id设计或者获取
  258. # 0.是否刷新
  259. # 1.获取userid,以及是否刷新
  260. user_id = self.get_argument("user_id", None)
  261. is_refresh = self.get_argument("is_refresh", None)
  262. print(user_id, is_refresh)
  263. if user_id is None or is_refresh is None:
  264. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  265. return
  266. sql_session = db.DBSession()
  267. # TODO:一个涉及到selenium-driver的请求-生命周期.----看一下tornado是怎么处理请求的生命周期
  268. if int(is_refresh) == 1:
  269. log_ad, cookie_canuse = ad_human_info.refresh_wechat_cookies(self, user_id=user_id)
  270. threading.Thread(target=user_action.get_human_info,
  271. args=(
  272. user_id, log_ad, db, cookie_canuse)).start()
  273. else:
  274. # 1.查看是否在刷新,
  275. # 在刷新中,
  276. # 返回正在刷新
  277. # -------不管上面逻辑让他们多刷新几次
  278. # 不在刷新
  279. # 返回对应数据
  280. # 2.获取userid对应数据
  281. result = sql_tools.get_wechat_info(sql_session=sql_session, user_id=user_id)
  282. result_list = []
  283. for _ in result:
  284. service_name, wechat_name = _
  285. result_list.append({'service_name': service_name, 'wechat_name': wechat_name})
  286. print(result_list)
  287. self.write({'status': {'msg': 'success', "RetCode": 200},
  288. 'wechat_info': result_list})
  289. class delete_ad_layout(BaseHandler):
  290. def get(self):
  291. user_id = self.get_argument('user_id', None)
  292. layout_name = self.get_argument('layout_name', None)
  293. sql_session = db.DBSession()
  294. if user_id is None or layout_name is None:
  295. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  296. return
  297. # 落地页名字精确到毫秒,默认是全局唯一
  298. sql_tools.delete_layout_typesetting_vir(sql_session=sql_session, user_id=user_id,
  299. typesetting_name=layout_name)
  300. self.write({'status': {'msg': 'success', "RetCode": 200}})
  301. class delete_ad_plan(BaseHandler):
  302. def get(self):
  303. user_id = self.get_argument('user_id', None)
  304. plan_name = self.get_argument('plan_name', None)
  305. sql_session = db.DBSession()
  306. if user_id is None or plan_name is None:
  307. self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
  308. return
  309. # 落地页名字精确到毫秒,默认是全局唯一
  310. sql_tools.delete_ad_plan_typesetting_vir(sql_session=sql_session, user_id=user_id,
  311. typesetting_name=plan_name)
  312. self.write({'status': {'msg': 'success', "RetCode": 200}})
  313. def make_app():
  314. return tornado.web.Application([
  315. ("/create_ad_plan_local", create_ad_plan_local),
  316. ("/create_ad_layout_local", create_ad_layout_local),
  317. ("/get_layout_local", get_ad_layout_local),
  318. ("/get_ad_plan_local", get_ad_plan_local),
  319. ("/delete_layout_local", delete_ad_layout),
  320. ("/delete_ad_plan_local", delete_ad_plan),
  321. ("/create_ad_plan_remote", create_ad_plan_remote),
  322. ("/create_ad_layout_remote", create_ad_layout_remote),
  323. ("/ad_human_info", ad_human_info),
  324. ("/ad_wechat_info", ad_wechat_info),
  325. ("/ad_status", ad_status)
  326. ], debug=True, autoreload=True)
  327. if __name__ == "__main__":
  328. tornado.log.LogFormatter()
  329. app = make_app()
  330. app.listen(8888)
  331. tornado.ioloop.IOLoop.current().start()