diff --git "a/docs/source_code/\346\212\245\350\255\246\345\217\212\347\233\221\346\216\247.md" "b/docs/source_code/\346\212\245\350\255\246\345\217\212\347\233\221\346\216\247.md" index 91c2cfe0..b8224434 100644 --- "a/docs/source_code/\346\212\245\350\255\246\345\217\212\347\233\221\346\216\247.md" +++ "b/docs/source_code/\346\212\245\350\255\246\345\217\212\347\233\221\346\216\247.md" @@ -18,6 +18,28 @@ DINGDING_WARNING_URL = "" # 钉钉机器人api DINGDING_WARNING_PHONE = "" # 报警人 支持列表,可指定多个 ``` +## 微信报警 + +条件:需要企业微信群,并获取企业微信机器人的Webhook地址 + +获取方式:https://weibanzhushou.com/blog/330 + +报警简介: + +- 仅支持文本模式 +- 当用户手机号码为空字符串或`WECHAT_WARNING_ALL`为`True`时将会`@全体成员` + + +相关设置: + +```python +# 企业微信报警 +WECHAT_WARNING_URL = "" # 企业微信机器人api +WECHAT_WARNING_PHONE = "" # 报警人 将会在群内@此人, 支持列表,可指定多人 +WECHAT_WARNING_ALL = False # 是否提示所有人, 默认为False +``` + + ## 邮件报警 相关配置: diff --git a/feapder/core/scheduler.py b/feapder/core/scheduler.py index d49b4093..0b72401e 100644 --- a/feapder/core/scheduler.py +++ b/feapder/core/scheduler.py @@ -446,6 +446,10 @@ def send_msg(self, msg, level="debug", message_prefix=""): msg, message_prefix=message_prefix, title=self._spider_name ) + if setting.WECHAT_WARNING_URL: + keyword = "feapder报警系统\n" + tools.wechat_warning(keyword + msg, message_prefix=message_prefix) + def spider_begin(self): """ @summary: start_monitor_task 方式启动,此函数与spider_end不在同一进程内,变量不可共享 diff --git a/feapder/setting.py b/feapder/setting.py index 70a23322..b2679ffc 100644 --- a/feapder/setting.py +++ b/feapder/setting.py @@ -99,7 +99,7 @@ ITEM_FILTER_ENABLE = False # item 去重 REQUEST_FILTER_ENABLE = False # request 去重 -# 报警 支持钉钉及邮件,二选一即可 +# 报警 支持钉钉、企业微信、邮件 # 钉钉报警 DINGDING_WARNING_URL = "" # 钉钉机器人api DINGDING_WARNING_PHONE = "" # 报警人 支持列表,可指定多个 @@ -107,6 +107,10 @@ EAMIL_SENDER = "" # 发件人 EAMIL_PASSWORD = "" # 授权码 EMAIL_RECEIVER = "" # 收件人 支持列表,可指定多个 +# 企业微信报警 +WECHAT_WARNING_URL = "" # 企业微信机器人api +WECHAT_WARNING_PHONE = "" # 报警人 将会在群内@此人, 支持列表,可指定多人 +WECHAT_WARNING_ALL = False # 是否提示所有人, 默认为False # 时间间隔 WARNING_INTERVAL = 3600 # 相同报警的报警时间间隔,防止刷屏; 0表示不去重 WARNING_LEVEL = "DEBUG" # 报警级别, DEBUG / ERROR diff --git a/feapder/templates/project_template/setting.py b/feapder/templates/project_template/setting.py index 7c300551..6538a2d6 100644 --- a/feapder/templates/project_template/setting.py +++ b/feapder/templates/project_template/setting.py @@ -75,10 +75,14 @@ # ITEM_FILTER_ENABLE = False # item 去重 # REQUEST_FILTER_ENABLE = False # request 去重 # -# # 报警 支持钉钉及邮件,二选一即可 +# 报警 支持钉钉、企业微信、邮件 # # 钉钉报警 # DINGDING_WARNING_URL = "" # 钉钉机器人api # DINGDING_WARNING_PHONE = "" # 报警人 支持列表,可指定多个 +# # 企业微信报警 +# WECHAT_WARNING_URL = "" # 企业微信机器人api +# WECHAT_WARNING_PHONE = "" # 报警人 将会在群内@此人, 支持列表,可指定多人 +# WECHAT_WARNING_ALL = False # 是否提示所有人, 默认为False # # 邮件报警 # EAMIL_SENDER = "" # 发件人 # EAMIL_PASSWORD = "" # 授权码 diff --git a/feapder/utils/tools.py b/feapder/utils/tools.py index bde49441..574ddfec 100644 --- a/feapder/utils/tools.py +++ b/feapder/utils/tools.py @@ -2291,3 +2291,47 @@ def linkedsee_warning(message, rate_limit=3600, message_prefix=None, token=None) data = {"content": message} response = requests.post(url, data=json.dumps(data), headers=headers) return response + + +def wechat_warning( + message, + message_prefix=None, + rate_limit=setting.WARNING_INTERVAL, + url=setting.WECHAT_WARNING_URL, + user_phone=setting.WECHAT_WARNING_PHONE, + all_users=setting.WECHAT_WARNING_ALL, +): + """企业微信报警""" + if isinstance(user_phone, str): + user_phone = [user_phone] if user_phone else [] + + if all_users is True or not user_phone: + user_phone = ["@all"] + + if not all([url, message]): + return + + if is_in_rate_limit(rate_limit, url, user_phone, message_prefix or message): + log.info("报警时间间隔过短,此次报警忽略。 内容 {}".format(message)) + return + + data = { + "msgtype": "text", + "text": {"content": message, "mentioned_mobile_list": user_phone}, + } + + headers = {"Content-Type": "application/json"} + + try: + response = requests.post( + url, headers=headers, data=json.dumps(data).encode("utf8") + ) + result = response.json() + response.close() + if result.get("errcode") == 0: + return True + else: + raise Exception(result.get("errmsg")) + except Exception as e: + log.error("报警发送失败。 报警内容 {}, error: {}".format(message, e)) + return False