tornado_api.py 18 KB

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