ent_interface_dingtalk.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. import base64
  2. import hashlib
  3. import hmac
  4. import sys
  5. import re
  6. import os
  7. import urllib
  8. import time
  9. import requests
  10. abspath = os.path.abspath(__file__)
  11. root_path = re.sub(r"tendata-warehouse.*", "tendata-warehouse", abspath)
  12. sys.path.append(root_path)
  13. from dw_base.utils.config_utils import parse_args
  14. from dw_base.spark.spark_sql import SparkSQL
  15. import http.client
  16. import json
  17. from cryptography.hazmat.primitives.asymmetric import rsa, padding
  18. from cryptography.hazmat.primitives import serialization
  19. from base64 import b64encode
  20. # 公钥
  21. public_key_pem = b"""
  22. -----BEGIN PUBLIC KEY-----
  23. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSaL/mqfq/30d5w6/05EL4073z
  24. ZgsomKTDI9wKUyz+ETkGwWzaNQm8BAXk9nJMCPz25fCTPd2BkifrS2KFKK2+e4hU
  25. pQxs+FQGaSeR8YEBWsCwh8bWaFWgxKuWpPPdfP6Vcnid/pTAsjbnw0KIHT7x83WZ
  26. qQTu3GUdyXkfyB41CQIDAQAB
  27. -----END PUBLIC KEY-----
  28. """
  29. class UserInfo:
  30. """公司名称"""
  31. company_name: str
  32. """真实名称"""
  33. name: str
  34. """用户id"""
  35. user_id: int
  36. """用户名"""
  37. username: str
  38. def __init__(self, company_name: str, name: str, user_id: int, username: str) -> None:
  39. self.company_name = company_name
  40. self.name = name
  41. self.user_id = user_id
  42. self.username = username
  43. def __str__(self) -> str:
  44. return (f"UserInfo:\n"
  45. f" Company Name: {self.company_name}\n"
  46. f" Name: {self.name}\n"
  47. f" User ID: {self.user_id}\n"
  48. f" Username: {self.username}")
  49. def encrypt_user_id(user_id):
  50. public_key = serialization.load_pem_public_key(public_key_pem)
  51. encrypted = public_key.encrypt(
  52. user_id.encode(),
  53. padding.PKCS1v15()
  54. )
  55. return b64encode(encrypted).decode()
  56. def get_user_info(user_id):
  57. encrypted_user_id = encrypt_user_id(user_id)
  58. conn = http.client.HTTPConnection("192.168.11.6", 18080)
  59. payload = json.dumps({
  60. "encryptUserId": encrypted_user_id
  61. })
  62. headers = {
  63. 'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
  64. 'Content-Type': 'application/json'
  65. }
  66. try:
  67. conn.request("POST", "/account/personal", payload, headers)
  68. res = conn.getresponse()
  69. resdata = res.read().decode("utf-8")
  70. res_json = json.loads(resdata)
  71. user_info = UserInfo(res_json['companyName'], res_json['name'], res_json['userId'], res_json['username'])
  72. return user_info
  73. except Exception as e:
  74. print("Error:", e)
  75. finally:
  76. conn.close()
  77. spark = SparkSQL(udf_files=['dw_base/spark/udf/contacts/ctc_common.py',
  78. 'dw_base/spark/udf/spark_id_generate_udf.py'])
  79. def get_sign(secret):
  80. timestamp = str(round(time.time() * 1000))
  81. secret_enc = secret.encode('utf-8')
  82. string_to_sign = '{}\n{}'.format(timestamp, secret)
  83. string_to_sign_enc = string_to_sign.encode('utf-8')
  84. hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
  85. sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
  86. return timestamp, sign
  87. def send_dingtalk_markdown(msg):
  88. headers = {"Content-Type": "application/json"}
  89. data = {
  90. "msgtype": "markdown",
  91. "markdown": {"title": '企业库告警', "text": msg, }
  92. }
  93. json_data = json.dumps(data)
  94. secret = 'SECffb7fe1b4c3aacc7be85d3b03de88fdbf93dfb48fe1c13ea7dba34a84847675e'
  95. timestamp, sign = get_sign(secret)
  96. url = f'https://oapi.dingtalk.com/robot/send?access_token=ffdb7df856220a925196e911107a4aa259acb2fd1160fee8b11d0c3c800974fc&timestamp={timestamp}&sign={sign}'
  97. response = requests.post(url=url, data=json_data, headers=headers)
  98. response.raise_for_status()
  99. def send_dingtalk_notification(msg):
  100. headers = {"Content-Type": "application/json"}
  101. data = {
  102. "msgtype": "text",
  103. "text": {"content": msg}
  104. }
  105. json_data = json.dumps(data)
  106. url = 'https://oapi.dingtalk.com/robot/send?access_token=5183dfe1ecbe06261bcac7b45c1a6b5ae101fec67877d74120a6a95c88d1f917'
  107. # url = 'https://oapi.dingtalk.com/robot/send?access_token=c4086d8ba377fdade2dff869e71063733095bc718d3bafdfbe8be0966aa050d6'
  108. # url = 'https://oapi.dingtalk.com/robot/send?access_token=bee997dbf61e839a17de087830ffef6e864c3109fef62a956703bdfe043b0e10'
  109. response = requests.post(url=url, data=json_data, headers=headers)
  110. response.raise_for_status()
  111. # shh非核心业务调用数
  112. def get_shh_non_core_interface_cnt(dt):
  113. sql = f'''
  114. SELECT sum(cnt) cnt
  115. FROM
  116. (SELECT count(1) cnt
  117. FROM ent_raw.interface_base
  118. WHERE topic = "ent_monitor_interface"
  119. AND dt = "{dt}"
  120. AND GET_JSON_OBJECT(ori_json, "$.type") != "EXPORT"
  121. AND GET_JSON_OBJECT(ori_json, "$.source")= 'CONTACT'
  122. UNION ALL SELECT count(1) cnt
  123. FROM ent_raw.interface_base
  124. WHERE topic = "ent_shh_bizr_interface"
  125. AND dt = "{dt}"
  126. AND GET_JSON_OBJECT(ori_json, "$.type") IN("ROOT",
  127. "COMPANY_COUNT")
  128. AND GET_JSON_OBJECT(ori_json, "$.source")= 'BIZR'
  129. UNION ALL SELECT count(1) cnt
  130. FROM ent_raw.interface_base
  131. WHERE topic = "ent_shh_mecs_interface"
  132. AND dt = "{dt}"
  133. AND GET_JSON_OBJECT(ori_json, "$.type") IN("CORP",
  134. "SITE")
  135. AND GET_JSON_OBJECT(ori_json, "$.source")= 'MECS'
  136. UNION ALL SELECT count(1) cnt
  137. FROM ent_raw.interface_base
  138. WHERE topic = "ent_shh_interface"
  139. AND dt = "{dt}"
  140. AND GET_JSON_OBJECT(ori_json, "$.type")= "BIZR"
  141. AND GET_JSON_OBJECT(ori_json, "$.source")= "BIZR"
  142. )t
  143. '''
  144. return spark.query(sql)[0].collect()[0]['cnt']
  145. def get_shh_company_interface_cnt(dt):
  146. sql = f'select count(1) cnt from ent_ods.ent_shh_api_company_logs where dt = "{dt}" and source != "SCRIPT"'
  147. return spark.query(sql)[0].collect()[0]['cnt']
  148. def get_shh_company_interface_script_cnt(dt):
  149. sql = f'select count(1) cnt from ent_ods.ent_shh_api_company_logs where dt = "{dt}" and source = "SCRIPT"'
  150. return spark.query(sql)[0].collect()[0]['cnt']
  151. def get_shh_contact_interface_cnt(dt):
  152. sql = f'select count(1) cnt from ent_raw.interface_base where topic = "ctc_shh_interface" and dt = "{dt}" and GET_JSON_OBJECT(ori_json, "$.source") != "SCRIPT"'
  153. return spark.query(sql)[0].collect()[0]['cnt']
  154. def get_shh_contact_interface_script_cnt(dt):
  155. sql = f'select count(1) cnt from ent_raw.interface_base where topic = "ctc_shh_interface" and dt = "{dt}" and GET_JSON_OBJECT(ori_json, "$.source") = "SCRIPT"'
  156. return spark.query(sql)[0].collect()[0]['cnt']
  157. def get_snv_contact_interface_cnt(dt):
  158. sql = f'select count(1) cnt from ent_raw.interface_base where topic = "ctc_snovio_interface" and dt = "{dt}" and GET_JSON_OBJECT(ori_json, "$.source") != "MANUAL_CONSUME" '
  159. return spark.query(sql)[0].collect()[0]['cnt']
  160. def get_snv_contact_interface_script_cnt(dt):
  161. sql = f'select count(1) cnt from ent_raw.interface_base where topic = "ctc_snovio_interface" and dt = "{dt}" and GET_JSON_OBJECT(ori_json, "$.source") = "MANUAL_CONSUME" '
  162. return spark.query(sql)[0].collect()[0]['cnt']
  163. def ent_user_top(dt):
  164. sql = (f"select GET_JSON_OBJECT(ori_json, '$.params.userId') as user ,count(1) as cnt from ent_raw.interface_base "
  165. f"where dt='{dt}' and topic = 'ent_tendata_interface' and GET_JSON_OBJECT(ori_json, '$.type') = 'BRIEF_RESULT' group by GET_JSON_OBJECT(ori_json, '$.params.userId') order by count(1) desc limit 10"
  166. )
  167. body = ''
  168. for row in spark.query(sql)[0].collect():
  169. userid = row.user
  170. user_info = get_user_info(userid)
  171. body += f'{user_info.username},{user_info.name},{user_info.company_name},**{row.cnt}**次 \n\n'
  172. return body
  173. def get_manual_request_cnt(dt):
  174. sql = f'''SELECT count(DISTINCT GET_JSON_OBJECT(ori_json, '$.params.traceId')) manual_request_cnt,
  175. count(distinct GET_JSON_OBJECT(ori_json, '$.params.userId')) as user_cnt
  176. FROM ent_raw.interface_base
  177. WHERE topic = 'ent_tendata_interface'
  178. AND dt = '{dt}'
  179. AND get_json_object(ori_json, '$.source') = 'BING'
  180. AND get_json_object(ori_json, '$.type') = 'MANUAL_REFRESH'
  181. AND get_json_object(ori_json, '$.result.canRefresh') = 'true'
  182. '''
  183. return spark.query(sql)[0].collect()[0]
  184. def get_ggl_res(dt):
  185. sql = f'''WITH MANUAL AS
  186. (SELECT DISTINCT GET_JSON_OBJECT(ori_json, '$.params.traceId') trace_id
  187. FROM ent_raw.interface_base
  188. WHERE topic = 'ent_tendata_interface'
  189. AND dt = '{dt}'
  190. AND get_json_object(ori_json, '$.source') = 'BING'
  191. AND get_json_object(ori_json, '$.type') = 'MANUAL_REFRESH'
  192. AND get_json_object(ori_json, '$.result.canRefresh') = 'true'), auto AS
  193. (SELECT DISTINCT GET_JSON_OBJECT(ori_json, '$.params.traceId') trace_id
  194. FROM ent_raw.interface_base
  195. WHERE topic = 'ent_tendata_interface'
  196. AND dt = '{dt}'
  197. AND get_json_object(ori_json, '$.source') = 'BING'
  198. AND get_json_object(ori_json, '$.type') = 'AUTO_REFRESH'
  199. AND get_json_object(ori_json, '$.result.canRefresh') = 'true'),
  200. ods AS
  201. (SELECT GET_JSON_OBJECT(ori_json, '$.params.traceId') trace_id,
  202. GET_JSON_OBJECT(ori_json, '$.result.status_code') res_code
  203. FROM ent_raw.interface_base
  204. WHERE topic = 'ctc_google_interface'
  205. AND dt = '{dt}'),
  206. manual_res AS
  207. (SELECT 'manual',
  208. sum(if(ods.res_code = '200',1,0)) as cnt
  209. FROM ods
  210. JOIN MANUAL ON ods.trace_id = manual.trace_id),
  211. auto_res AS
  212. (SELECT 'auto',
  213. sum(if(ods.res_code = '200',1,0)) as cnt
  214. FROM ods
  215. JOIN auto ON ods.trace_id = auto.trace_id),
  216. ctc_cnt AS
  217. (SELECT 'ctc_cnt',
  218. count(1) as cnt
  219. FROM ctc_mid.ctc_main_pre
  220. WHERE dt = '{dt}'
  221. AND SOURCE LIKE '%google%' )
  222. SELECT *
  223. FROM manual_res
  224. UNION ALL
  225. SELECT *
  226. FROM auto_res
  227. UNION ALL
  228. SELECT *
  229. FROM ctc_cnt
  230. '''
  231. row = spark.query(sql)[0].collect()
  232. return row
  233. def get_manual_base(dt):
  234. sql = f'''
  235. select count(1) as cnt,
  236. count(distinct GET_JSON_OBJECT(ori_json, '$.params.userId')) as user_cnt,
  237. nvl(sum(if(get_json_object(ori_json, '$.result.data.website') is not null, 1, 0)),0) as web_cnt
  238. from ent_raw.interface_base
  239. where topic = 'ent_tendata_interface'
  240. and dt = '{dt}'
  241. and get_json_object(ori_json, '$.source') = 'BING'
  242. and get_json_object(ori_json, '$.type') = 'MANUAL'
  243. '''
  244. row = spark.query(sql)[0].collect()[0]
  245. return row
  246. def get_auto_base(dt):
  247. sql = f'''
  248. select count(1) as cnt,
  249. count(distinct GET_JSON_OBJECT(ori_json, '$.params.userId')) as user_cnt,
  250. sum(if(get_json_object(ori_json, '$.result.data.website') is not null, 1, 0)) as web_cnt
  251. from ent_raw.interface_base
  252. where topic = 'ent_tendata_interface'
  253. and dt = '{dt}'
  254. and get_json_object(ori_json, '$.source') = 'BING'
  255. and get_json_object(ori_json, '$.type') = 'AUTO'
  256. '''
  257. row = spark.query(sql)[0].collect()[0]
  258. return row
  259. def get_manual_cnt(dt):
  260. sql = f'''
  261. with webs as (select distinct get_json_object(ori_json, '$.result.data.website') as website
  262. from ent_raw.interface_base
  263. where topic = 'ent_tendata_interface'
  264. and dt = '{dt}'
  265. and get_json_object(ori_json, '$.source') = 'BING'
  266. and get_json_object(ori_json, '$.type') = 'MANUAL'
  267. and get_json_object(ori_json, '$.result.data.website') is not null),
  268. tids as (select website, generate_tid(clean_website(website), 'not_null', null) as tid
  269. from webs),
  270. pre as (select i.id, i.tid, i.source
  271. from ctc_mid.ctc_main_pre i
  272. join tids t on i.tid = t.tid
  273. where i.dt = '{dt}'),
  274. shh as (select 'shh' as source,
  275. count(distinct tid) as res_cnt,
  276. count(id) as ctc_cnt
  277. from pre
  278. where source like '%shh_%'),
  279. snovio as (select 'snovio' as source,
  280. count(distinct tid) as res_cnt,
  281. count(id) as ctc_cnt
  282. from pre
  283. where source like '%snovio%'),
  284. all_t as (select 'all' as source,
  285. count(distinct tid) as res_cnt,
  286. count(id) as ctc_cnt
  287. from pre
  288. where source like '%snovio%'
  289. or source like '%shh_%')
  290. select *
  291. from shh
  292. union all
  293. select *
  294. from snovio
  295. union all
  296. select *
  297. from all_t
  298. '''
  299. res = spark.query(sql)[0].collect()
  300. return res
  301. def get_auto_cnt(dt):
  302. sql = f'''
  303. with webs as (select distinct get_json_object(ori_json, '$.result.data.website') as website
  304. from ent_raw.interface_base
  305. where topic = 'ent_tendata_interface'
  306. and dt = '{dt}'
  307. and get_json_object(ori_json, '$.source') = 'BING'
  308. and get_json_object(ori_json, '$.type') = 'AUTO'
  309. and get_json_object(ori_json, '$.result.data.website') is not null),
  310. tids as (select website, generate_tid(clean_website(website), 'not_null', null) as tid
  311. from webs),
  312. pre as (select i.id, i.tid, i.source
  313. from ctc_mid.ctc_main_pre i
  314. join tids t on i.tid = t.tid
  315. where i.dt = '{dt}'),
  316. shh as (select 'shh' as source,
  317. count(distinct tid) as res_cnt,
  318. count(id) as ctc_cnt
  319. from pre
  320. where source like '%shh_%'),
  321. snovio as (select 'snovio' as source,
  322. count(distinct tid) as res_cnt,
  323. count(id) as ctc_cnt
  324. from pre
  325. where source like '%snovio%'),
  326. all_t as (select 'all' as source,
  327. count(distinct tid) as res_cnt,
  328. count(id) as ctc_cnt
  329. from pre
  330. where source like '%snovio%'
  331. or source like '%shh_%')
  332. select *
  333. from shh
  334. union all
  335. select *
  336. from snovio
  337. union all
  338. select *
  339. from all_t
  340. '''
  341. res = spark.query(sql)[0].collect()
  342. return res
  343. if __name__ == '__main__':
  344. CONFIG, _ = parse_args(sys.argv[1:])
  345. dts = CONFIG.get('dt').split(',')
  346. for dt in dts:
  347. format_dt = f'{dt[:4]}-{dt[4:6]}-{dt[6:]}'
  348. shh_company_interface_cnt = get_shh_company_interface_cnt(dt)
  349. shh_company_interface_script_cnt = get_shh_company_interface_script_cnt(dt)
  350. shh_contact_interface_cnt = get_shh_contact_interface_cnt(dt)
  351. shh_contact_interface_script_cnt = get_shh_contact_interface_script_cnt(dt)
  352. snv_contact_interface_cnt = get_snv_contact_interface_cnt(dt)
  353. snv_contact_interface_script_cnt = get_snv_contact_interface_script_cnt(dt)
  354. shh_non_core_interface_cnt = get_shh_non_core_interface_cnt(dt)
  355. msg = f'''【接口调用量统计】------------------------------------------
  356. 统计日期: {format_dt}
  357. 1、单接口调用公司信息次数: {shh_company_interface_cnt + shh_company_interface_script_cnt}
  358. ①自然调用次数: {shh_company_interface_cnt}
  359. ②脚本调用次数: {shh_company_interface_script_cnt}
  360. 2、单接口调用联系人次数: {shh_contact_interface_cnt + shh_contact_interface_script_cnt}
  361. ①自然调用次数: {shh_contact_interface_cnt}
  362. ②脚本调用次数: {shh_contact_interface_script_cnt}
  363. 3、snovio调用联系人次数: {snv_contact_interface_cnt + snv_contact_interface_script_cnt}
  364. ①自然调用次数: {snv_contact_interface_cnt}
  365. ②脚本调用次数: {snv_contact_interface_script_cnt}
  366. 4、单接口非核心业务调用次数:{shh_non_core_interface_cnt}
  367. ---------------------------------------------------------------'''
  368. print(msg)
  369. send_dingtalk_notification(msg)
  370. ent_user_top_cnt = ent_user_top(dt)
  371. msg = f'''### 企业主页接口调用统计top10
  372. > **统计日期 : {format_dt}**
  373. {ent_user_top_cnt}
  374. '''
  375. print(msg)
  376. send_dingtalk_markdown(msg)
  377. manual_base = get_manual_base(dt)
  378. auto_base = get_auto_base(dt)
  379. manual_cnt = get_manual_cnt(dt)
  380. auto_cnt = get_auto_cnt(dt)
  381. manual_request_res = get_manual_request_cnt(dt)
  382. manual_request_cnt = manual_request_res['manual_request_cnt']
  383. manual_user_cnt = manual_request_res['user_cnt']
  384. # 处理分母可能为0的情况
  385. # manual_user_cnt = manual_base['user_cnt']
  386. manual_cnt_total = manual_base['cnt']
  387. manual_web_cnt = manual_base['web_cnt']
  388. auto_user_cnt = auto_base['user_cnt']
  389. auto_cnt_total = auto_base['cnt']
  390. auto_web_cnt = auto_base['web_cnt']
  391. manual_avg_requests = manual_request_cnt / manual_user_cnt if manual_user_cnt != 0 else 0
  392. manual_web_percentage = 100 * manual_web_cnt / manual_cnt_total if manual_cnt_total != 0 else 0
  393. manual_single_interface_percentage = 100 * manual_cnt[0][
  394. 'res_cnt'] / manual_web_cnt if manual_web_cnt != 0 else 0
  395. manual_snovio_percentage = 100 * manual_cnt[1]['res_cnt'] / manual_web_cnt if manual_web_cnt != 0 else 0
  396. manual_solution_percentage = 100 * manual_cnt[2]['res_cnt'] / manual_cnt_total if manual_cnt_total != 0 else 0
  397. auto_avg_requests = auto_cnt_total / auto_user_cnt if auto_user_cnt != 0 else 0
  398. auto_web_percentage = 100 * auto_web_cnt / auto_cnt_total if auto_cnt_total != 0 else 0
  399. auto_single_interface_percentage = 100 * auto_cnt[0]['res_cnt'] / auto_web_cnt if auto_web_cnt != 0 else 0
  400. auto_snovio_percentage = 100 * auto_cnt[1]['res_cnt'] / (auto_web_cnt - auto_cnt[0]['res_cnt']) if (
  401. auto_web_cnt -
  402. auto_cnt[
  403. 0][
  404. 'res_cnt']) != 0 else 0
  405. auto_solution_percentage = 100 * (
  406. auto_cnt[0]['res_cnt'] + auto_cnt[1]['res_cnt']) / auto_cnt_total if auto_cnt_total != 0 else 0
  407. ggl_res = get_ggl_res(dt)
  408. manual_ggl_cnt = ggl_res[0]['cnt']
  409. auto_ggl_cnt = ggl_res[1]['cnt']
  410. ctc_ggl_cnt = ggl_res[2]['cnt']
  411. msg = f'''【手动/自动更新效果统计】------------------------------------------
  412. 统计日期: {format_dt}
  413. 1、手动更新
  414. ①手动更新请求总人数:{manual_user_cnt}人
  415. ②手动更新请求总次数:{manual_request_cnt}次
  416. ③人均请求次数:{manual_avg_requests:.2f}次
  417. ④手动请求bing网址总次数:{manual_cnt_total}次
  418. ⑤bing获取到网址的次数及占比:{manual_web_cnt}次,{manual_web_percentage:.2f}%
  419. ⑥单接口获取到联系人次数及占比:{manual_cnt[0]['res_cnt']}次,{manual_single_interface_percentage:.2f}%
  420. ⑦单接口获取到联系人去重总数:{manual_cnt[0]['ctc_cnt']}
  421. ⑧snovio接口获取到联系人次数及占比:{manual_cnt[1]['res_cnt']}次,{manual_snovio_percentage:.2f}%
  422. ⑨snovio接口获取到联系人去重总数:{manual_cnt[1]['ctc_cnt']}
  423. ⑩当日手动更新获得联系方式的总次数:{manual_cnt[2]['res_cnt']}
  424. ⑪当日手动更新解决问题的百分比:{manual_solution_percentage:.2f}%
  425. 2、自动更新
  426. ①自动更新对应的总人数:{auto_user_cnt}人
  427. ②自动更新请求总次数:{auto_cnt_total}次
  428. ③人均对应自动更新次数:{auto_avg_requests:.2f}次
  429. ④bing获取到网址的次数及占比:{auto_web_cnt}次,{auto_web_percentage:.2f}%
  430. ⑤单接口获取到联系人次数及占比:{auto_cnt[0]['res_cnt']}次,{auto_single_interface_percentage:.2f}%
  431. ⑥单接口获取到联系人去重总数:{auto_cnt[0]['ctc_cnt']}
  432. ⑦snovio接口获取到联系人次数及占比:{auto_cnt[1]['res_cnt']}次,{auto_snovio_percentage:.2f}%
  433. ⑧snovio接口获取到联系人去重总数:{auto_cnt[1]['ctc_cnt']}
  434. ⑨当日自动更新获得联系方式的总次数:{auto_cnt[0]['res_cnt'] + auto_cnt[1]['res_cnt']}
  435. ⑩当日自动更新解决问题的百分比:{auto_solution_percentage:.2f}%
  436. 3、google补充
  437. ①手动触发google爬虫获取到联系人次数:{manual_ggl_cnt}次
  438. ②自动触发google爬虫获取到联系人次数:{auto_ggl_cnt}次
  439. ③google爬虫获取到联系人去重数:{ctc_ggl_cnt}人
  440. --------------------------------------------------------------- '''
  441. print(msg)
  442. send_dingtalk_notification(msg)