cxyu преди 3 години
родител
ревизия
403f195a4d
променени са 6 файла, в които са добавени 179 реда и са изтрити 50 реда
  1. 19 5
      web_module/tornado_api.py
  2. 65 16
      wechat_action/create_ad_layout.py
  3. 67 10
      wechat_action/create_ad_plan.py
  4. 6 4
      wechat_action/create_ad_plan_idea.py
  5. 15 8
      wechat_action/login_ad.py
  6. 7 7
      wechat_action/sql_tools.py

+ 19 - 5
web_module/tornado_api.py

@@ -1,5 +1,6 @@
 from wechat_action.sql_models import DB
 from settings import using_config
+import tornado.log
 import tornado.ioloop
 import tornado.web
 import json
@@ -13,7 +14,7 @@ import pickle
 
 # TODO:需要添加上supervisor,来维护进程
 # TODO:有时间需要对tornado进行改进
-
+# TODO:需要有一套上线工具,来维持线上稳定
 
 db = DB(config=using_config)
 wechat_cookies_table = Table('wechat_cookies', db.metadata,
@@ -175,9 +176,12 @@ class ad_human_info(BaseHandler):
         # 0.是否刷新
         # 1.获取userid,以及是否刷新
         user_id = self.get_argument("user_id", None)
+        human_package_name = self.get_argument('human_package_name', None)
         is_refresh = self.get_argument("is_refresh", None)
+        wechat_name = self.get_argument('wechat_name', None)
+        service_name = self.get_argument('service_name', None)
         print(user_id, is_refresh)
-        if user_id is None or is_refresh is None:
+        if user_id is None or is_refresh is None or wechat_name is None or service_name is None:
             self.write({'status': {'msg': 'url parameter error', "RetCode": 400}})
             return
         sql_session = db.DBSession()
@@ -197,9 +201,17 @@ class ad_human_info(BaseHandler):
             #     不在刷新
             #       返回对应数据
             # 2.获取userid对应数据
-            result = sql_tools.get_human_info(sql_session=sql_session, user_id=user_id)
-            result = [json.loads(x) for x in result]
+            result = sql_tools.get_human_info(sql_session=sql_session,
+                                              service_name=service_name, wechat_name=wechat_name)
             print(result)
+            result = json.loads(result)
+            if human_package_name:
+                result = [_ for _ in result if human_package_name in _['name']]
+            result_ = []
+            for i in range(len(result)):
+                _ = result[i]
+                _['id'] = i
+                result_.append(_)
             self.write({'status': {'msg': 'success', "RetCode": 200},
                         'human_info': result})
 
@@ -208,7 +220,8 @@ class ad_wechat_info(BaseHandler):
 
     # 1.公众号相关信息获取
     def get(self):
-        # TODO:添加分页
+        # TODO:添加分页,
+        #  公众号,服务商,唯一id设计或者获取
 
         # 0.是否刷新
         # 1.获取userid,以及是否刷新
@@ -257,6 +270,7 @@ def make_app():
 
 
 if __name__ == "__main__":
+    tornado.log.LogFormatter()
     app = make_app()
     app.listen(8888)
     tornado.ioloop.IOLoop.current().start()

+ 65 - 16
wechat_action/create_ad_layout.py

@@ -3,7 +3,9 @@ from selenium.webdriver.common.keys import Keys
 from selenium.webdriver import ActionChains
 from logging import handlers
 import logging
+import requests
 import random
+import shutil
 import time
 import re
 import os
@@ -17,6 +19,7 @@ class CreateAd:
         self.driver = login_ad.get_driver_loged()
         self.get_into_create_page()
         self.send_file_limit_num = 8
+        self.img_dir = './img'
 
     def get_into_create_page(self):
         # 进入创建页面
@@ -25,9 +28,9 @@ class CreateAd:
         time.sleep(random.uniform(5, 7))
 
         WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element_by_class_name('ui-fl-r'))
-        create_element=self.driver.find_element_by_class_name('ui-fl-r')
-        WebDriverWait(self.driver, 10).until(lambda driver: create_element.is_displayed() and create_element.is_enabled())
-
+        create_element = self.driver.find_element_by_class_name('ui-fl-r')
+        WebDriverWait(self.driver, 10).until(
+            lambda driver: create_element.is_displayed() and create_element.is_enabled())
 
         self.driver.find_element_by_class_name('ui-fl-r').click()
         WebDriverWait(self.driver, 5).until(lambda driver: driver.find_element_by_css_selector(
@@ -62,11 +65,10 @@ class CreateAd:
 
     def set_head_assemb(self, info):
         def single_page_set():
-
             self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/div[1]/div/div[1]/div/div').click()
             time.sleep(random.uniform(0.1, 0.2))
 
-            file_name = os.path.basename(info_v)
+            file_name = re.split('\/', info_v)[-1]
             self.driver.find_element_by_class_name('upload-img-item-inner-2gsg7NjaZ8').click()
             WebDriverWait(self.driver, 10).until(
                 lambda x: len([_ for _ in self.driver.find_elements_by_class_name('title-29sncpKgTl') if
@@ -128,6 +130,7 @@ class CreateAd:
             logging.info('头版首页单图上传结束')
 
         def multi_page_set():
+            # TODO:现在图片设置为素材库,需要对应下载然后存储
             self.driver.find_element_by_css_selector(
                 '#stage-sidebar > div.topArea-qOwEAeNuIn > div > div:nth-child(2)').click()
             time.sleep(random.uniform(0.1, 0.2))
@@ -185,6 +188,7 @@ class CreateAd:
             logging.info('头版多图选择 结束')
 
         def movie_set():
+            # TODO:视频转为链接,
             file_name = os.path.basename(info_v)
             self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/div[1]/div/div[3]/div/div').click()
             self.driver.find_element_by_xpath('//*[@class="comptEditButton-2JsnAFdOGZ"]').click()
@@ -244,12 +248,13 @@ class CreateAd:
         # 设置头部组件
         pass
 
-    def set_page(self, page_path):
+    def set_page(self, page_link):
         # 设置图片模块
         self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/section/div[2]/div[1]/div/div').click()
         time.sleep(random.uniform(0.1, 0.2))
 
-        file_name = os.path.basename(page_path)
+        file_name = re.split('\/', page_link)[-1]
+
         upload_elements = self.driver.find_elements_by_class_name('upload-img-item-inner-2gsg7NjaZ8')
         for _ in upload_elements:
             if _.is_displayed() and _.is_enabled():
@@ -319,6 +324,8 @@ class CreateAd:
         logging.info('图片模块设置结束')
 
     def set_content(self, config_info):
+        # TODO:长文本需要优化输入时间
+
         # 设置文本模块
         # 1.文本内容2.文本颜色3.是否加粗4.文本位置设置5.文本大小
 
@@ -626,7 +633,17 @@ class CreateAd:
         time.sleep(1000)
         self.driver.execute_script('window.close();')
 
-    def send_file(self, file_path, err_num=0):
+    def send_file(self, file_link, err_num=0):
+        # 下载图片,存储于
+
+        if not os.path.exists(self.img_dir):
+            os.makedirs(self.img_dir)
+        link_pra = re.split('\/', file_link)
+        file_path = os.getcwd() + '/' + self.img_dir + '/' + link_pra[-1]
+
+        rsp = requests.get(file_link)
+        with open(file_path, 'wb') as f:
+            f.write(rsp.content)
         # 有问题,暂时不使用
         self.driver.execute_script('location.reload();')
         self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(file_path)
@@ -634,6 +651,8 @@ class CreateAd:
     def send_file_alone(self, layout):
         # 上传文件,单线程
         # 上传文件,文件上传与整体流程切割开
+        WebDriverWait(self.driver, 10).until(
+            lambda x: len(re.findall('token=(\d+)', self.driver.current_url)))
         token = re.findall('token=(\d+)', self.driver.current_url)
         url_ = 'https://mp.weixin.qq.com/promotion/frame?t=ad_system/common_frame&t1=material_std/material_library&token={}'.format(
             token[0])
@@ -689,6 +708,29 @@ class CreateAd:
         self.driver.find_element_by_xpath('/html/body/div[6]/div/div/div[2]/div/div[3]/button[2]').click()
         time.sleep(1)
 
+    def check_sucess(self, layout_name):
+        # 进入素材中心
+        WebDriverWait(self.driver, 100).until(
+            lambda x: self.driver.find_element_by_id('material'))
+        self.driver.find_element_by_id('material').click()
+
+        # 输入--落地页名字
+        input_element = self.driver.find_element_by_xpath('//*[@class="adui-input-base"]')
+        input_element.send_keys(layout_name)
+        time.sleep(random.uniform(0.5, 0.6))
+        input_element.send_keys(Keys.RETURN)
+        # TODO:有空去除掉时间
+        time.sleep(random.uniform(3, 5))
+        # 查询有无
+        result = self.driver.find_elements_by_xpath('//*[@class="namelink-1V-GPp_906"]')
+        print('结果', len(result))
+        if len(result):
+            return True
+
+    def remove_all_file(self):
+        shutil.rmtree(os.getcwd() + '/' + self.img_dir)
+        pass
+
     def create_layout(self, layout, err_num=0):
         #
         try:
@@ -710,23 +752,30 @@ class CreateAd:
                     self.set_follow_button_(info_v)
 
             self.set_share_content(layout[str(-3)])
-            self.driver.execute_script('window.close();')
-            # 切回到前一页
-            self.driver.switch_to.window(self.driver.window_handles[-1])
 
-            return {'sucess': True, 'result_info': ''}
+            self.remove_all_file()
+            if self.check_sucess(layout_name=layout[-4]['layout_name']):
+                return {'sucess': True, 'result_info': ''}
+            else:
+                if err_num > 3:
+                    return {'sucess': False, 'result_info': '过程中全程无错误,失败'}
+                else:
+
+                    self.log_ad.refresh_driver()
+                    self.log_ad.select_ad_master(service_name=self.service_name, wechat_name=self.wechat_name)
+                    self.get_into_create_page()
+                    return self.create_layout(layout, err_num=err_num + 1)
         except Exception as e:
             raise
             # TODO:有空时讲 e 内容设置为原始内容
             if err_num > 3:
                 return {'sucess': False, 'result_info': str(e)}
             else:
+                self.log_ad.refresh_driver()
+                self.log_ad.select_ad_master(service_name=self.service_name, wechat_name=self.wechat_name)
+                self.get_into_create_page()
                 return self.create_layout(layout, err_num=err_num + 1)
 
-    def check_sucess(self):
-        # TODO: 添加一个页面检查,查看落地页是否已经在微信后台创建
-        pass
-
 
 if __name__ == '__main__':
     logging.basicConfig(

+ 67 - 10
wechat_action/create_ad_plan.py

@@ -10,6 +10,7 @@ from wechat_action.login_ad import LogIn
 from selenium.webdriver import ChromeOptions
 import re
 import time
+import logging
 import random
 
 
@@ -25,15 +26,22 @@ class CreateAdPlan():
         self.ad_human_action = HumanAd(self.driver)
 
     def set_ad_title(self):
+        # TODO:广告和投放计划,都需要修改名字,修改成一个名字
+        logging.info('开始设置广告标题')
         title_ = self.driver.find_element_by_xpath('//*[@class="input-2lFnByGCRh"]')
         for i in range(40):
             title_.send_keys(Keys.BACKSPACE)
+        title_.click()
+        time.sleep(0.1)
         title_.send_keys(self.task['title'])
         title_.send_keys(Keys.RETURN)
+        time.sleep(random.uniform(0.1, 0.2))
 
     def set_ad_cpm(self):
         # TODO:设置完之后,test函数中进行对应修改
+        logging.info('开始设置cpm')
         if self.task['cpm']['cpm_set'] == 2:
+            self.driver.save_screenshot('cpm{}.png'.format(time.time()))
             self.driver.find_element_by_xpath(
                 '//*[@id="wxadcontainer"]/div[1]/div/div[2]/main/div/div[2]/div[1]/div/div[2]/div/div[1]/section[2]/form/div/div[1]/div[1]/button[2]/span').click()
             time.sleep(0.1)
@@ -47,6 +55,7 @@ class CreateAdPlan():
                     time.sleep(0.1)
 
     def set_ad_locations(self):
+        logging.info('设置对应广告位')
         gg_button = self.driver.find_element_by_class_name(
             'adui-button-hasLeftIcon')
         gg_button.click()
@@ -88,6 +97,7 @@ class CreateAdPlan():
         next_button.click()
 
     def set_ad_time(self):
+        logging.info('设置对应投放时间')
         WebDriverWait(self.driver, 10).until(
             lambda driver: self.driver.find_elements_by_xpath('//*[@class="adui-input-base"]'))
         input_elements = self.driver.find_elements_by_xpath('//*[@class="adui-input-base"]')
@@ -119,8 +129,13 @@ class CreateAdPlan():
             for _ in self.task['date_set']['date_list'][1][1:]:
                 time.sleep(random.uniform(0.1, 0.2))
                 input_elements[1].send_keys(_)
+        self.driver.save_screenshot('time-{}.png'.format(time.time()))
+        # self.driver.find_element_by_xpath(
+        #     '//*[@id="wxadcontainer"]/div[1]/div/div[2]/main/div/div[2]/div[1]/div/div[2]/div/div[1]/section[1]/div[2]/form/div[2]/div/div/div/svg').click()
+        time.sleep(0.1)
 
     def set_ad_human_location(self):
+        logging.info('设置对应人群信息-非人群包')
         WebDriverWait(self.driver, 10).until(
             lambda driver: self.driver.find_element_by_css_selector('#area_input > div > i'))
         self.driver.find_element_by_css_selector('#area_input > div > i').click()
@@ -139,15 +154,30 @@ class CreateAdPlan():
     def set_ad_cost(self):
         # 投放计划创建
         # 广告创建
-
+        logging.info('设置对应广告花销')
         day_cost = self.driver.find_element_by_css_selector('#budget_input')
         WebDriverWait(self.driver, 10).until(lambda x: (day_cost.is_displayed() and day_cost.is_enabled()))
 
-        day_cost.send_keys('100')
+        day_cost.send_keys('101')
+        time.sleep(5)
         self.driver.find_element_by_css_selector('#target_next_step').click()
+        self.driver.save_screenshot('click{}.png'.format(time.time()))
+
+        time_element = self.driver.find_element_by_xpath('//*[@class="title-1CSarR7XgH"]')
+        ActionChains(self.driver).move_to_element(time_element).perform()
+        time.sleep(10)
+        self.driver.save_screenshot('click-2-{}.png'.format(time.time()))
+        for i in range(4):
+            if len(self.driver.find_elements_by_css_selector('#target_next_step')) == 0:
+                break
+            self.driver.find_element_by_css_selector('#target_next_step').click()
+            time.sleep(5)
+            ActionChains(self.driver).move_to_element(time_element).perform()
+            self.driver.save_screenshot('click-{}-{}.png'.format((2 + i), time.time()))
 
     def set_ad_human(self):
         # TODO:检查人群是否正常
+        logging.info('设置人群包')
         self.driver.find_element_by_xpath('//*[@id="test-dmp-container"]/div[2]/span/span[1]').click()
         time.sleep(0.1)
         select_human_element = self.driver.find_element_by_xpath(
@@ -166,7 +196,7 @@ class CreateAdPlan():
             human_input.click()
             human_input.send_keys(_)
             human_input.send_keys(Keys.RETURN)
-            time.sleep(random.uniform(0.5, 0.6))
+            time.sleep(random.uniform(1, 1.2))
             human_names = self.driver.find_elements_by_xpath('//*[@class="adui-table-cellInner"]')
             for human_name in human_names:
                 if human_name.text == _:
@@ -179,6 +209,7 @@ class CreateAdPlan():
 
     def set_ad_idea(self):
         # 创意创建
+        logging.info('设置创意')
         if self.task['localtion'] == 'gzh_botoom':
             self.ad_idea_action.idea_gzh_bottom()
         if self.task['localtion'] == 'gzh_movie':
@@ -195,6 +226,7 @@ class CreateAdPlan():
 
     def push_ad(self):
         # 提交
+        logging.info('提交广告')
         time.sleep(random.uniform(3, 4))
         agreement_element = self.driver.find_element_by_class_name('label-3_CrbQVNtc')
         if agreement_element.get_attribute('aria-checked') != 'true':
@@ -214,13 +246,35 @@ class CreateAdPlan():
         #     exit()
         pass
 
-    def check_ad_plan_alive(self):
-        # TODO:通过宿舍检查ad_plan是否已经存在
-        pass
+    def check_is_sucess(self, plan_name):
+        logging.info('检查广告计划创建是否成功')
+        # TODO:进一步修改
 
-    def check_is_sucess(self):
-        # TODO: 检查是否创建成功
-        pass
+        # 进入搜索页面,
+        click_elements = self.driver.find_elements_by_xpath('//*[contains(@class, "navItem-3MjWMCbkWT")]/span')
+        for _ in click_elements:
+            if '广告' in _.text:
+                _.click()
+
+        time.sleep(random.uniform(0.1, 0.2))
+        # 设置状态为--审核中
+        choice_elements = self.driver.find_elements_by_xpath('//*[contains(@class, "tag-3loTlkncVq")]/span')
+        for _ in choice_elements:
+            if '状态' in _.text:
+                _.click()
+        time.sleep(random.uniform(0.1, 0.2))
+        lable_elements = self.driver.find_elements_by_xpath('//*[contains(@class, "label-2ZOAbuO31o")]/span')
+        for _ in lable_elements:
+            if '审核中' in _.text:
+                _.click()
+
+        # 输入搜索字段
+        input_element = self.driver.find_element_by_xpath('//*[contains(@class, "search-2yiDvyFHoH")]/span')
+        input_element.click()
+        time.sleep(random.uniform(0.1, 0.2))
+        input_element.send_keys()
+
+        # 查看有无对应数据
 
     def run(self, err_num=0):
         try:
@@ -238,9 +292,12 @@ class CreateAdPlan():
 
             # 切回到前一页
             self.driver.switch_to.window(self.driver.window_handles[-1])
-
+            logging.info('创建广告计划成功')
             return {'sucess': True, 'result_info': ''}
         except Exception as e:
+            time.sleep(5)
+            self.driver.save_screenshot('liuyi{}.png'.format(time.time()))
+            time.sleep(5)
             raise
             # TODO:有空时讲 e 内容设置为原始内容
             if err_num > 3:

+ 6 - 4
wechat_action/create_ad_plan_idea.py

@@ -2,6 +2,7 @@ import time
 import random
 from selenium.webdriver.common.keys import Keys
 from selenium.webdriver.support.wait import WebDriverWait
+import logging
 
 
 class IdeaAction:
@@ -220,9 +221,8 @@ class IdeaAction:
         self.push_promotion_page()
 
     def idea_pyq(self):
-        # TODO: 选择相关落地页
-        print(self.driver.current_url)
-        '//*[@id="wxadcontainer"]/div[1]/div/div[2]/main/div/div[2]/div[2]/div/div[1]/div[1]/div[2]/form/div[2]/div/div[1]/div[2]/div'
+
+        logging.info('朋友圈--文案设置')
         WebDriverWait(self.driver, 100).until(
             lambda driver: self.driver.find_element_by_xpath('//*[@class="ql-editor ql-blank"]'))
         self.driver.find_element_by_xpath(
@@ -240,6 +240,7 @@ class IdeaAction:
                 _.click()
 
         # 朋友圈推广页选择
+        logging.info('朋友圈--推广页设置')
         self.driver.find_element_by_xpath('//*[@id="choose_template"]').click()
 
         input_elements = self.driver.find_elements_by_xpath('//*[@class="adui-input-base"]')
@@ -247,6 +248,8 @@ class IdeaAction:
             if _.get_attribute("placeholder") == '输入关键字搜索推广页':
                 _.send_keys(self.task['idea']['jump_type-page_type'])
                 _.send_keys(Keys.RETURN)
+        # TODO:有空去除这个时间,使用等待
+        time.sleep(random.uniform(0.5, 1))
         WebDriverWait(self.driver, 30).until(
             lambda driver: self.driver.find_elements_by_xpath('//*[@class="adui-table-cellInner"]'))
 
@@ -261,7 +264,6 @@ class IdeaAction:
         '//*[@id="test_creative_next_step"]'
         time.sleep(random.uniform(0.1, 0.2))
 
-
         time.sleep(random.uniform(0.1, 0.5))
         if self.task['idea']['data_show'] == 2:
             self.driver.find_element_by_xpath(

+ 15 - 8
wechat_action/login_ad.py

@@ -14,7 +14,7 @@ from settings import using_config
 from wechat_action.sql_models import DB
 import requests
 import json
-
+import logging
 
 class LogIn:
     # TODO:整体运行使用逻辑,需要修改几次
@@ -30,20 +30,21 @@ class LogIn:
         options = ChromeOptions()
         # 防止selenium快速崩坏
         options.add_argument("--disable-dev-shm-usage")
-        # options.add_experimental_option('excludeSwitches', ['enable-automation'])
+        options.add_experimental_option('excludeSwitches', ['enable-automation'])
         # prefs = {"profile.managed_default_content_settings.images": 2, 'permissions.default.stylesheet': 2}
         # options.add_experimental_option("prefs", prefs)
-        # #
-        # driver = webdriver.Remote(
-        #     command_executor='http://118.31.53.105:4444/wd/hub',
-        #     options=options)
-        driver = webdriver.Chrome(options=options)
+
+        driver = webdriver.Remote(
+            # command_executor='http://192.168.1.101:4444/wd/hub',
+            command_executor='http://118.31.53.105:4555/wd/hub',
+            options=options)
+        # driver = webdriver.Chrome(options=options)
         driver.maximize_window()
         return driver
 
     def log_in(self):
         # self.wechat_cookie_use()
-
+        logging.info('开始登录')
         self.driver.get('https://a.weixin.qq.com/index.html')
 
         img_selector = 'body > div.old-template > div > div > div.waiting.panelContent > div.wrp_code > img'
@@ -58,8 +59,11 @@ class LogIn:
     def log_in_wait(self):
         # 默认等待6分钟
         WebDriverWait(self.driver, 6 * 60).until(lambda driver: self.driver.find_elements_by_link_text('广告投放'))
+        logging.info('登录成功')
+
 
     def select_ad_master(self, service_name, wechat_name):
+        logging.info('开始切换服务商')
         time.sleep(5)
         self.driver.execute_script('''
                     window.scroll(0,1000000);
@@ -89,6 +93,7 @@ class LogIn:
         elements = self.driver.find_elements_by_link_text('广告投放')
         elements[0].click()
         time.sleep(1)
+        logging.info('切换服务商成功')
         # 切换窗口,点击创建广告,切到广告页面
 
         self.driver.switch_to.window(self.driver.window_handles[-1])
@@ -151,6 +156,7 @@ class LogIn:
 
     def refresh_driver(self):
         err_num = 0
+        logging.info('开始刷新chrome')
         while True:
             try:
                 if len(self.driver.window_handles) > 1:
@@ -168,3 +174,4 @@ class LogIn:
                 err_num = err_num + 1
                 if err_num > 3:
                     break
+        logging.info('刷新chrome 结束')

+ 7 - 7
wechat_action/sql_tools.py

@@ -83,16 +83,14 @@ def delete_wechat_info(sql_session, user_id):
     sql_session.commit()
 
 
-def get_human_info(sql_session, user_id):
+def get_human_info(sql_session, service_name, wechat_name):
     sql = '''
         select human_info from human_info hi 
-        where concat(service_name ,wechat_name ) in
-        (select concat(service_name ,wechat_name) from wechat_info
-        where user_id ='{}') ;
-    '''.format(user_id)
+        where service_name='{service_name}' and wechat_name='{wechat_name}' ;
+    '''.format(service_name=service_name, wechat_name=wechat_name)
     cursor = sql_session.execute(sql)
     lines = cursor.fetchall()
-    result_list = [line[0] for line in lines]
+    result_list = lines[0][0]
     return result_list
 
 
@@ -132,6 +130,7 @@ def get_undo_action(sql_session, user_id):
     result_list = [line for line in lines]
     return result_list
 
+
 def get_ad_status(sql_session, user_id):
     sql = '''
        select  action_type ,wechat_name ,service_name,max(update_time ),max(create_time),status from action_record  
@@ -143,6 +142,7 @@ group by  action_type ,wechat_name ,service_name,status ;
     result = [line for line in lines]
     return result
 
+
 def get_action_status(sql_session, user_id):
     # TODO:sql 里面添加doing,error状态的挑选
     sql = '''
@@ -199,7 +199,7 @@ def check_plan_alive(sql_session, service_name, wechat_name, plan_name):
            and action_type like '%{plan_name}%'
            and status='done'
        '''.format(service_name=service_name, wechat_name=wechat_name, plan_name=plan_name)
-    print('plan ',sql)
+    print('plan ', sql)
     cursor = sql_session.execute(sql)
     num = cursor.fetchall()[0][0]
     return num