From 661fd3edb55a3a0f41c15f292aacaa5e276304dd Mon Sep 17 00:00:00 2001 From: maojian <550076202@qq.com> Date: Wed, 8 Jan 2025 15:02:57 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=B0=B4=E5=86=9B=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E5=BA=94=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/asr.iml | 11 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/workspace.xml | 824 +++++++++++++++++++++ config.ini | 23 + environment.txt | 3 + log_util/__pycache__/set_logger.cpython-36.pyc | Bin 0 -> 840 bytes log_util/__pycache__/set_logger.cpython-38.pyc | Bin 0 -> 858 bytes log_util/set_logger.py | 33 + logs/results.log | 0 manage.py | 18 + src.py | 35 + start.sh | 1 + stop_uwsgi.sh | 1 + test.py | 103 +++ text_analysis/__init__.py | 0 text_analysis/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 184 bytes text_analysis/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 156 bytes .../__pycache__/cusException.cpython-38.pyc | Bin 0 -> 753 bytes .../__pycache__/read_config.cpython-38.pyc | Bin 0 -> 390 bytes text_analysis/__pycache__/settings.cpython-36.pyc | Bin 0 -> 1937 bytes text_analysis/__pycache__/settings.cpython-38.pyc | Bin 0 -> 1847 bytes text_analysis/__pycache__/urls.cpython-36.pyc | Bin 0 -> 402 bytes text_analysis/__pycache__/urls.cpython-38.pyc | Bin 0 -> 392 bytes text_analysis/__pycache__/views.cpython-36.pyc | Bin 0 -> 3357 bytes text_analysis/__pycache__/views.cpython-38.pyc | Bin 0 -> 9644 bytes text_analysis/__pycache__/wsgi.cpython-36.pyc | Bin 0 -> 612 bytes text_analysis/__pycache__/wsgi.cpython-38.pyc | Bin 0 -> 604 bytes text_analysis/bak/views.py0928 | 207 ++++++ text_analysis/bak/views.py_0226 | 327 ++++++++ text_analysis/bak/views.py_0607 | 335 +++++++++ text_analysis/cusException.py | 9 + text_analysis/linshi.py | 101 +++ text_analysis/model/bot_user.pkl | Bin 0 -> 594441 bytes text_analysis/read_config.py | 10 + text_analysis/request.py | 14 + text_analysis/settings.py | 148 ++++ text_analysis/src.py | 90 +++ .../tools/__pycache__/cusException.cpython-36.pyc | Bin 0 -> 1979 bytes .../tools/__pycache__/db_pool.cpython-38.pyc | Bin 0 -> 2900 bytes .../tools/__pycache__/mysql_helper.cpython-36.pyc | Bin 0 -> 7561 bytes .../tools/__pycache__/process.cpython-36.pyc | Bin 0 -> 1584 bytes .../tools/__pycache__/to_kafka.cpython-36.pyc | Bin 0 -> 1533 bytes .../tools/__pycache__/to_kafka.cpython-38.pyc | Bin 0 -> 1068 bytes .../tools/__pycache__/tool.cpython-36.pyc | Bin 0 -> 5015 bytes .../tools/__pycache__/tool.cpython-38.pyc | Bin 0 -> 2710 bytes .../tools/__pycache__/tools.cpython-36.pyc | Bin 0 -> 4106 bytes text_analysis/tools/cusException.py | 25 + text_analysis/tools/db_pool.py | 131 ++++ text_analysis/tools/kakfa_util.py | 67 ++ text_analysis/tools/mysql_helper.py | 338 +++++++++ text_analysis/tools/process.py | 51 ++ text_analysis/tools/seleniumTest.py | 171 +++++ text_analysis/tools/to_kafka.py | 25 + text_analysis/tools/tool.py | 155 ++++ text_analysis/urls.py | 13 + text_analysis/views.py | 383 ++++++++++ text_analysis/views.py_20240920 | 340 +++++++++ text_analysis/wsgi.py | 16 + txt/postData-user.txt | 85 +++ uwsgi.ini | 8 + wsgi.log | 86 +++ wsgi.py | 36 + 63 files changed, 4235 insertions(+) create mode 100644 .idea/asr.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/workspace.xml create mode 100644 config.ini create mode 100644 environment.txt create mode 100644 log_util/__pycache__/set_logger.cpython-36.pyc create mode 100644 log_util/__pycache__/set_logger.cpython-38.pyc create mode 100644 log_util/set_logger.py create mode 100644 logs/results.log create mode 100644 manage.py create mode 100644 src.py create mode 100644 start.sh create mode 100644 stop_uwsgi.sh create mode 100644 test.py create mode 100644 text_analysis/__init__.py create mode 100644 text_analysis/__pycache__/__init__.cpython-36.pyc create mode 100644 text_analysis/__pycache__/__init__.cpython-38.pyc create mode 100644 text_analysis/__pycache__/cusException.cpython-38.pyc create mode 100644 text_analysis/__pycache__/read_config.cpython-38.pyc create mode 100644 text_analysis/__pycache__/settings.cpython-36.pyc create mode 100644 text_analysis/__pycache__/settings.cpython-38.pyc create mode 100644 text_analysis/__pycache__/urls.cpython-36.pyc create mode 100644 text_analysis/__pycache__/urls.cpython-38.pyc create mode 100644 text_analysis/__pycache__/views.cpython-36.pyc create mode 100644 text_analysis/__pycache__/views.cpython-38.pyc create mode 100644 text_analysis/__pycache__/wsgi.cpython-36.pyc create mode 100644 text_analysis/__pycache__/wsgi.cpython-38.pyc create mode 100644 text_analysis/bak/views.py0928 create mode 100644 text_analysis/bak/views.py_0226 create mode 100644 text_analysis/bak/views.py_0607 create mode 100644 text_analysis/cusException.py create mode 100644 text_analysis/linshi.py create mode 100644 text_analysis/model/bot_user.pkl create mode 100644 text_analysis/read_config.py create mode 100644 text_analysis/request.py create mode 100644 text_analysis/settings.py create mode 100644 text_analysis/src.py create mode 100644 text_analysis/tools/__pycache__/cusException.cpython-36.pyc create mode 100644 text_analysis/tools/__pycache__/db_pool.cpython-38.pyc create mode 100644 text_analysis/tools/__pycache__/mysql_helper.cpython-36.pyc create mode 100644 text_analysis/tools/__pycache__/process.cpython-36.pyc create mode 100644 text_analysis/tools/__pycache__/to_kafka.cpython-36.pyc create mode 100644 text_analysis/tools/__pycache__/to_kafka.cpython-38.pyc create mode 100644 text_analysis/tools/__pycache__/tool.cpython-36.pyc create mode 100644 text_analysis/tools/__pycache__/tool.cpython-38.pyc create mode 100644 text_analysis/tools/__pycache__/tools.cpython-36.pyc create mode 100644 text_analysis/tools/cusException.py create mode 100644 text_analysis/tools/db_pool.py create mode 100644 text_analysis/tools/kakfa_util.py create mode 100644 text_analysis/tools/mysql_helper.py create mode 100644 text_analysis/tools/process.py create mode 100644 text_analysis/tools/seleniumTest.py create mode 100644 text_analysis/tools/to_kafka.py create mode 100644 text_analysis/tools/tool.py create mode 100644 text_analysis/urls.py create mode 100644 text_analysis/views.py create mode 100644 text_analysis/views.py_20240920 create mode 100644 text_analysis/wsgi.py create mode 100644 txt/postData-user.txt create mode 100644 uwsgi.ini create mode 100644 wsgi.log create mode 100644 wsgi.py diff --git a/.idea/asr.iml b/.idea/asr.iml new file mode 100644 index 0000000..73af2a0 --- /dev/null +++ b/.idea/asr.iml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..62002bf --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..edc8d49 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..c1022cb --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,824 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + KafkaClient + open + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1692600024256 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..591a836 --- /dev/null +++ b/config.ini @@ -0,0 +1,23 @@ +[database] +;数据库地址 +host=node-01 +;端口 +port=3306 +;用户名 +username=root +;密码 +password=bw@2025 +;数据库 +db=analyze + +[zookeeper] +;zk地址 +zkhost=node-01:12181,node-02:12181,node-03:12181 +;节点 +node=/analyze + +[kafka] +;服务器地址 +bootstrap_servers=node-01:19092,node-02:19092,node-03:19092 +;topic +topic=produce_analyze diff --git a/environment.txt b/environment.txt new file mode 100644 index 0000000..7a1f644 --- /dev/null +++ b/environment.txt @@ -0,0 +1,3 @@ +1.python>3.7 +2.pandas=1.4.4 +3.sklearn=0.24.2 \ No newline at end of file diff --git a/log_util/__pycache__/set_logger.cpython-36.pyc b/log_util/__pycache__/set_logger.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..296101068e1cd4e08c5ae78ac5e883c749e93543 GIT binary patch literal 840 zcmYjO!EVz)5ZztdiQ~FbPqf@}z*2ljgjx<&g%DD!w3TR(pa(F9Xz^|mhqWDf*QE{V zDcler!kw?#E2n+}oS3yEwQJ4njA!1=+nIyyZSU~!Z}!7M=nr~u2-q({C%{Y5gD5}zYI!pyWqd612 zOt49TV}Z0mjzQ!*PzufQ3a#-iUg0?b&st-Ql)VBrjF>*m`RUve)>@IVqgwMeYp*fb z?uyJiknb^fjSU9yTPxC7z^XIS?#21Z==}8Ta_LlR(m%X2Eba`2(9!M$=;buy+WtD@ zxpsM;6bxu%5 zW*>qcm5G8$gz{q-yhT|gT*{Eup5Rwpn7$_3?*_fBV3h!G5cDQho{Z{Hw+G&aU?`7* zo=9_^7az1r0lk{4XlIwO- zWDBSd&%Ra{R3$U*17=v18CCFl-MKeC%GhR)p;fl(Ql=*_Bj0cw&zdFwLgg+5{|!%$ zVlG6=V|e+TCo0~5x_=PUoQfN%x>U+kDw?Y}nNfARP%#u6S1J`TFc>$L2a6l+-MbyA zD<6SE#It;x;2o=F`NYOHb}bK=k0BDa%PqJxDWtaKjnq4)6bxpt;V0`clsk}A18TMp X)Sf}R&zpU`Fe8&5C>NX0herPa(^%?Q literal 0 HcmV?d00001 diff --git a/log_util/__pycache__/set_logger.cpython-38.pyc b/log_util/__pycache__/set_logger.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a628ab7d9d6db8aee14d69ff30a82b6d3bcb9df GIT binary patch literal 858 zcmYjQOK;Oa5Z+xs;v}xbt>xB3Eyah#65>!HR3R0WMxsH2B7u2Cu6L6fY_GMuE^SC} z+z|gEIr5kG%Bg>W17+5Z)b48M;n{EI^Njs=YpaJ~{p%O=pAJHQjB|exaGt@D`yeQy zI7e}-af}Pp%%4&pxCAO4GNtbK%+^B_0DNlF#4LSL}lgtD9hP# zQqr7>6q_rXWr6O%IfNtMflz3LmuQWz@e;3yLSL*k#z@&qU_^H@k)y)`x%!1tG=wSZZ7qP>&x^U3(d@#(^;)oi$bW0>3+3ZbLD8Bi>f zf@%BPIV-it%9K-}uDz^OOk5n zw2|id-lF&r3=)|t=td|%?SfYco-!#z+ITs;V7aMlqQl)_P;gr3;EjU8tS-|@6WSes zw;>qHC&3`kN>=iahAjs2C366UzV1NTx#8WNGxZW|CbTEPG=;Q1o*carX4u-5^=y`1 zY9g5Kq`asgKfLy(I!RP|u6@89aZw}+-d=a_%w9t2W|pBP+$NQ&$wcfMj??pY(7%z` zhTz|Wh*v5~$|S#9uqdf283}&I)tItUWwR`WFNBxTD1s!@T4i|zm8WgSQFWzzcWxK* z$vqH=^eo>dn4rzRb#2%3iH&VcZpp3f^ssmc_ri|ogVKacZOJRCADG0@p3#P-Y?>h+ ez@-MzaK0yY4BC6zPUXNfPMROd!)E)~v;G6-SnI+7 literal 0 HcmV?d00001 diff --git a/log_util/set_logger.py b/log_util/set_logger.py new file mode 100644 index 0000000..e735461 --- /dev/null +++ b/log_util/set_logger.py @@ -0,0 +1,33 @@ +#coding:utf8 +import logging +import os +import sys +from logging.handlers import TimedRotatingFileHandler +import re +# cur_dir = os.path.dirname( os.path.abspath(__file__)) or os.getcwd() +# sys.path.append(cur_dir + '/log_util') +def set_logger(filename): + # 创建logger对象。传入logger名字 + logger = logging.getLogger(filename) + # log_path = os.path.join(cur_dir, filename) + # 设置日志记录等级 + logger.setLevel(logging.INFO) + # interval 滚动周期, + # when="MIDNIGHT", interval=1 表示每天0点为更新点,每天生成一个文件 + # backupCount 表示日志保存个数 + file_handler = TimedRotatingFileHandler( + filename=filename, when="MIDNIGHT",encoding="utf-8", interval=1, backupCount=3 + ) + # filename="mylog" suffix设置,会生成文件名为mylog.2020-02-25.log + file_handler.suffix = "%Y-%m-%d.log" + # extMatch是编译好正则表达式,用于匹配日志文件名后缀 + # 需要注意的是suffix和extMatch一定要匹配的上,如果不匹配,过期日志不会被删除。 + file_handler.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}.log$") + # 定义日志输出格式 + file_handler.setFormatter( + logging.Formatter( + "[%(asctime)s] [%(process)d] [%(levelname)s] - %(module)s.%(funcName)s (%(filename)s:%(lineno)d) - %(message)s" + ) + ) + logger.addHandler(file_handler) + return logger diff --git a/logs/results.log b/logs/results.log new file mode 100644 index 0000000..e69de29 diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..ea99051 --- /dev/null +++ b/manage.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +import os +import sys +import threading +from text_analysis.views import predict +import django + +if __name__ == "__main__": + t = threading.Thread(target=predict, name='predict') + t.daemon = True + t.start() + + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "text_analysis.settings") + django.setup() + from django.core.management import execute_from_command_line + execute_from_command_line(sys.argv) + + diff --git a/src.py b/src.py new file mode 100644 index 0000000..f799490 --- /dev/null +++ b/src.py @@ -0,0 +1,35 @@ +#coding:utf8 +import requests + +def upload(): + url="https://realtime.pdeepmatrix.com/apis/media/analysis/upload" + # 定义form-data参数 + data = { + 'fromLanguage': 'zh' + } + # 定义文件参数 + files = { + 'file': open('inputdata/lKTZNen6aak.mp4', 'rb') + } + response = requests.post(url, data=data, files=files) + print(response.text) + + #结果—{"code":200,"message":"SUCCESS","data":"3a42ea9594b641c39e40d1497ca29be9"} + +def getResults(): + url="https://realtime.pdeepmatrix.com/apis/media/analysis/getResult" + # 定义参数 + #'taskId': '3a42ea9594b641c39e40d1497ca29be9' + params = { + 'taskId': '5ee948446ab64d5d8a1d92ecfa6c2c93' + } + response = requests.get(url, params=params) + # 打印响应结果 + print(response.text) + #{"code":200,"message":"SUCCESS","data":{"sentences":[{"silence_duration":0,"end_time":5108,"speech_rate":150,"begin_time":1130,"channel_id":0,"emotion_value":"5.0","text":"视频解析、语音识别。"}]... +# upload() +getResults() + + + + diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..b2da032 --- /dev/null +++ b/start.sh @@ -0,0 +1 @@ +../../environment/python3.8/bin/uwsgi --ini uwsgi.ini --file wsgi.py --daemonize wsgi.log \ No newline at end of file diff --git a/stop_uwsgi.sh b/stop_uwsgi.sh new file mode 100644 index 0000000..ea46313 --- /dev/null +++ b/stop_uwsgi.sh @@ -0,0 +1 @@ +lsof -i:9020 |grep -v 'PID' | awk '{print $2}'| xargs kill -9 diff --git a/test.py b/test.py new file mode 100644 index 0000000..4398de2 --- /dev/null +++ b/test.py @@ -0,0 +1,103 @@ +#coding=utf8 +import sys +import requests +import json +import time + +# #url = 'http://0.0.0.0:5033' +# """ +# url = 'http://20.0.2.6:5055/classify_event' +# url = 'http://20.0.2.6:5055/is_about_china' +# url = 'http://20.0.2.6:5055/associated_words' +# """ +# url = 'http://127.0.0.1:9008/paper' +# +# # url_file ="http://172.18.1.130:9985/group33/default/20230415/09/15/1/“GF-1”影像质量评价及矿区土地利用分类潜力研究_陈明.docx" +# url_file="/opt/Project_kongtianyuan/inputfile/" +# filename = "“GF-1”影像质量评价及矿区土地利用分类潜力研究" +# +# data = {"url":url_file,"filename":filename} +# data_str = json.dumps(data) +# +# r = requests.post(url,data=str(data_str)) +# print(r.text) +# # res =json.loads(r.text) +# # print(res) +raw_data={ + "metadata":{ + "address":"http://172.24.12.126:9013/ASR/", + "index":0, + "admin":{ + "datasource":"2_任务提取" + }, + "output":{ + "output_type":"table", + "label_col":[ + "ASR识别内容" + ] + }, + "input":{ + "input_type":"text", + "label":[ + "2_任务提取" + ] + }, + "user":{ + "tag":"" + } + }, + "data":{ + "1_文件上传":"{\"fileId\":\"53aa330b4e484c9bdeb7ff35e335a6f6\",\"fileName\":\"lKTZNen6aak.mp4\",\"filePath\":\"/group33/default/20230828/15/48/1/lKTZNen6aak.mp4\",\"fileType\":\"mp4\",\"fileUrl\":\"http://172.18.1.130:9985/group33/default/20230828/15/48/1/lKTZNen6aak.mp4\",\"ossPath\":\"/group33/default/20230828/15/48/1/lKTZNen6aak.mp4\"}", + "businessKey":"19615b029da477fb", + "2_任务提取":"[{\"fileId\":\"53aa330b4e484c9bdeb7ff35e335a6f6\",\"fileName\":\"lKTZNen6aak.mp4\",\"filePath\":\"/group33/default/20230828/15/48/1/lKTZNen6aak.mp4\",\"fileType\":\"mp4\",\"fileUrl\":\"http://172.18.1.130:9985/group33/default/20230828/15/48/1/lKTZNen6aak.mp4\",\"ossPath\":\"/group33/default/20230828/15/48/1/lKTZNen6aak.mp4\"}]" + }, + "created":1691004265000, + "module":"ASR", + "start_tag":"false", + "multi_branch":0, + "last_edit":1693417201000, + "next_app_id":[ + { + "start_id":154, + "edge_id":75, + "end_id":155 + } + ], + "transfer_id":3, + "version":1, + "blueprint_id":4, + "scenes_id":5, + "scenario":{ + "dataloss":1, + "autoCommitTriggerLast":1, + "maxErrors":3, + "autoCommit":1, + "freshVariables":1 + }, + "wait_condition":[ + + ], + "scheduling":{ + "interval":-1, + "type":"single" + }, + "name":"ASR", + "businessKey":"19615b029da477fb", + "id":154, + "position":[ + 100, + 200 + ], + "describe":"ASR识别" +} +allFile = raw_data["data"]["2_任务提取"] +currentFile = eval(allFile) +print(currentFile) +print(type(currentFile)) +# filejson = json.loads(currentFile) +# file = currentFile["fileUrl"] +# fileName = currentFile["fileName"] + +# print(file) + + diff --git a/text_analysis/__init__.py b/text_analysis/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/text_analysis/__pycache__/__init__.cpython-36.pyc b/text_analysis/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92820a9402949d68fb7edc2ddf520e21d2edc6b8 GIT binary patch literal 184 zcmXr!<>fNbUKzdl-k3@`#24nSPY0whuxf*CX!{Z=v*frJsn*CZg<#VRH>CnqyC zrl2T4D>bl|PDCYUfT~C*+d^vN`%hfZUcC@`*xbyk!buj@DCGpw$dFdsYiFuW! ziFxq_i3O=eu6{8ksTC#hiFt`RmBpFGG4b)4d6^~g@p=W7w>WHa^HWN5Qtd$27XvW^ E05q~WS^xk5 literal 0 HcmV?d00001 diff --git a/text_analysis/__pycache__/__init__.cpython-38.pyc b/text_analysis/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c93f47b6c0bc5048247631caaa4d30e9084e85ce GIT binary patch literal 156 zcmWIL<>g`kf`8n(=^*+sh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o6vJKfjoSidMgDZj)sB{i=kGc7YYu_QA;PhU^JB(9;~i7vsgbqJ~J<~BtBlR Wpz;=nO>TZlX-=vg$mq{N%m4r@z$Qfi literal 0 HcmV?d00001 diff --git a/text_analysis/__pycache__/cusException.cpython-38.pyc b/text_analysis/__pycache__/cusException.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1cf0f8ab14fa501176a76994d935c7dbe54cb141 GIT binary patch literal 753 zcmbVJu};G<5Vez(h884LF)_1rX?_5qN~j=~E{G+I6=D}fN|RtGQrnddEJzH%H;@6u zM%7R8gamE>0SSq7NGVz1-5jw)+4teEv;lI00cSZ*Q;O^v88%Y=xS6QWcI z^*X|Xy;b>*-?VmWNRyDj=`uoOg^+GY6X=u3Ekdpm$Dg0@ja=uSVqQ{vs%;&R)iQC$ z*Yh|EMZB)ZlhNbk`EJqUxlX0*zhc#jnJZTAtQIcZ;pOEAvhT|JuEK#j%==cnUDxGi Y@f(>HTTcJQXYW1OTs?>gD}t9r5HEXKYLk{oHz`RL+|s>y^&j-;FXigV zKM+B1(xU9ZyqU+mydiTxn@s@YXS%Mxuzm!x9~8+YraeaBz)1s3;FL$tuq2$^K^A}F z1Qun$zX-2l%sHk#LEvNu4qnL{>_|@@X+LL;V-S~kK**uR5GaR2ue)2(BLDw=I4SkbnY z8U3K$4HwGEN|uF_TCtot@#I#6&Pvpv>uR*j+pV8A`k#mY+29Q%rU^YFCR{S3Cc-lG Y!{$9W#DP!F*P3q{aY2yTaHu5u1&m%@=l}o! literal 0 HcmV?d00001 diff --git a/text_analysis/__pycache__/settings.cpython-36.pyc b/text_analysis/__pycache__/settings.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed23213b5bb0c6ff4c74e2fcc378698fd1f10efe GIT binary patch literal 1937 zcmb6Z+j81QR00_Y@!d|`CTT|Q*puMa!Zw~JlW963AQL7Sc`Q-48m1bdU0{ij6zyUg zz4jOS*dOQz^k?+iCqMViPdyUg5bT+@EPJ$j?zcUKg@x?Z-+!XDHIDm>oBCzo{027t z4FKYF4)G{q^E!|DUZR(rf&!lVm5-L5LP-W)`K9ANr91_q2^bl>JFVL4Af$-?j?*d3IpvU?mdZI6(uk>ZmwE}w;_8NMsucIyf z0ov3bqJ+xjw$0Z($7Rbs)9JV(#f%ZBL&di1i+Y#zi0K$7zT3kVGtO{J#r`?5u;`6Y zQZ`$`4)#rkk=PoF&rqyp*F=5dh?JQ=8*@Gr2NV>GV>|oOOOQPRBYoG$B5}Z8-(a5zgFYm@o}Asb(qK9qw>e^DnH_Z%ZWrKN5T~#rk5#7ZY+Z?MD&rkOpGK9W*648^k2?Y2o8h zHm0P$yCVpjSRZ<(^#OWV`sv6w`&jX!cBNBtySL>iwgx_7LrB%=FvY&g@Fg=$$Fzr( zP-)=XG{}!tFx>ZScvVshY+?sZ`d%u>4@?`AX}B7<0O)}iVL>FWPlM;PN^bK=2)72E zVCO$@`uHQf4i)q+QSskxb8n^2D_d=CHFnpkcD1m4ZwjCJ=N*{t6}>M>v7wu99%d zrTpmQ!=3ZzB9MweIs(zajyVa(EpxezFl`txcMKy;xHJ?zlXb&1BEAD15T?x*jWHR+ zh+d6h=$W@gRgQcPv#MM=l{MqN{Bt;0mftoi;X<)iQ_keF@lH`SHC(LLRSi&pfI!tS zdt5D-Yw}s~R1W7)6-6@|r?rw&KML<@^6^QnsL5)$e5O{a5r3^(Dn>a87iz_NrBSTN zMoB5lz*{|*4PB|rVWt7TRQF%jN2l8UUOh}jI86ulG!QRECiKOIQBx{M)tYRmRbAGX zKHW=7qptnI`P)%)B5++TziMLJCb&5s!p(!dgFA@cgwnaDQ15gx}Il z{wc%e1x)q>ELgAvT)?7NunMGbCjK;+TO~68b0Hm85zkpAELmkd?-r~DT(l~5S{9^Zc z_@s+B&%IIa)7|({ceK?TZEe#XK0@w!Y$k=xS~1?31f@8E&m-DZvh>C4v(zE)#~;rS zQwZ@nABTj+cV?K3Fa{~T&KLj#xq!Gki{MZMCrv$zcV~H1ZOVXR?2!u;5yhC$4zDP2 zZHmeXL6HW5uhg@@e-UL-PpQN54J8*j(Wf)MAjn1D4-NK^2I^!zlmpHNaT$3Yd^pKQ z4)w(iL3q@8eTJOZ(8bEP`w<$DPM9_<%i*@J;}~&<5#?h@)#N27zQ)Oj+sH@Wm{Fz- zBag-ER0Su4(1UZObipR^@nz>LjqHe-Q#MQ1vK9b6a3&mxB#2o2XjaK}83mK>(2Y0$ zgJeYB!1>_uXH(g$Hcg9ggXXk2@y?9!RpM^|T=HsCQrgq%uk>~!ks8foBPnY~M|SpB z>KvKPPTPn-c|U0v%%utnLnu#H`*@!CTSFFCHAazY^x<0TBN~@gxQ(Dc)Y|Q&WZQ6+ z*mfcYERjOQ`$-AY$cK_9CDdgZrEJ^jF|ci`yr&s@>O@j8^!l-G+OPEQlKFb=rDTJ^^2v+t1pQx7POKc2Z1f zrUmYq0I#Peeifp7a4BWWpPCwkT+P}nCMx8LsZr1kcoU~brZ-KTs;KW}_UeLD!f{gm zY7pR|N4|z{g}@rHNY%1bjq!npZ5~rj1 EH~GhM9{>OV literal 0 HcmV?d00001 diff --git a/text_analysis/__pycache__/urls.cpython-36.pyc b/text_analysis/__pycache__/urls.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..586db08dd25f729e385f48d457a35aab0beba4f5 GIT binary patch literal 402 zcmZut%SuBr5KVHQ)m94n0o~qBk#;9iT)1%~h`SJ!^k!Oe$)hBxTK~Zh@hAL{yLII+ zxH8d&3JuKR%nWnROy;A}!Q_p=8YA?M{=6dcix_?pK_Gz@(wJgRD8VTwD$_a5zj>w# zUD6UGAR>pdt3)Bnmu!t`Evj48)E`j;HKebkY1LLhpKYCLa9?ntrAg#L!lQpaxpQ`D z!<7IN23!JY%4g1h#RugEp|)>1@t^B*KLIs1vve gY|pCfpBqaHPB**0KG#-k6)fVJ5ViN04P>K8aEWc!7l4SCh6d5NAad5u;>e$s?FEuMa1f3|yP~7w3KWQO z8bHcOewsI<_dGLqRds?O-X7jXhY|XSw*>-iG*jO*iLxPi51j0b}nH_|ByObpG25POe=Ri&YTM zVZ{tnJ1@P9tGWVUJOy>nLJ-dQSLCL#5#j5S*glYhVlN2mdryuGMH=$YnZ#k5em9mE V+VVk(C0rW$5@3O6c$Uq-e*pL7ZEXMm literal 0 HcmV?d00001 diff --git a/text_analysis/__pycache__/views.cpython-36.pyc b/text_analysis/__pycache__/views.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..616804e7ff926c12568828e84db50831f00ca6fd GIT binary patch literal 3357 zcmb7G&5s;M6|d^<>FN30*`3+%^#@;q0klqRJ_523l2L@E$O&Ae>6HTGLxeE#!32;ZL4<_F0j%VL<5=R%zfec;F4XazA&SHRrTuk zUcGwn)vLNvtCgSp*Jl4%N9bSZ%+G=T_u&&O7$J%%juFXQOt2YS#9~%tGaNZlfm+nQ zZ!zpU3`K5KG}L3I5gy^e%P=aB5UGs08c}8Ws5Y`jnAAaw8!fQP2xBzv*LB~l)F2IL zop`aoM3xM%5I6fR(lUKFUhc0DFcUDvc(uPq)4O2rrji)rrjc2raec_ zL0gK?_s^5_hHXqi^-A<*}ETBWsnhRQ7{*d;!$6DDKr$KjSqDO4eiqOQeAnO;_kd(5f)MRneD7de;>d!rJ;H}rLTEAw z0Y=gVeo=>sI`3PwK;8S`_?rluzx1M#EJu|QY;uAvQg0TUtc|r4X=!$bB5+6f260|{ z_2wHV+RWhskWU}|?fAo=AOGc#M~@$W_Vj0MOF7^mrtH4xz1+s6$`Uc;%nw8-47m~8 znutXrO^*NY^yulk&mP|g9smB|ub^Z2r3v8py^mq?x5SYI_wXGD(YxJ994mF zo^n-^Jm|39ptG;a-IVtO3DN7cEmGtRR0yd&9^CdJPQjlMUja@3dHo09-C=PYvYi1> zBi4~SmtVMiWhY32_&~^ufe@jPK_Yi}x|_=DlqE9khMho$X|f~P9qH%LQ0%-FvfE;N zaG;vc!EVB0VhISc%GknHT*hnI#dW-4@ipLf^pyUs!WY43a^@Wyp$GPzw+Jy&}Qyiz*IEv|!K7L0s(M!r0= zibgdIsxpJB%%K(ysyc(J&Y_kJsy2hF&7qnGRi8oC=TI$!T9`pC%%PSIsxgCV%%N5c zYH;O}x)$*Nf`t7i*YBU{XtdT_yDlv!D674`68Q$iJ^YpZz` zt3=h)(P1lVMYXI6`LmoYQ@oBcOxLdhh1}Y>iex=n$aHqC=={%Cv{taG#PV;^u z(TEmDP8FPZzo<~#CKWO4beIs=po$XD6sK3xo`N!DE(}r{3da3z z7&B5zxC3lurMq#ss~mkfsN#S#8g?YFflA)c zq^U{Etf22;P#QBfXs_~R&9lMEvDbC=C(9-Py6aE;@4rY|Q}$^X{L5#-laTmV&ax-r z@xO7FJqeZnO|mgnJsURvTjRhP!xl{pjbSE)VAS%IH3=tJwLWFfgcdAYnNCf^45lqj z`FY5}uEvz7!w=S+F~OvQ|7}vAg5XYliL|EU(-iT)L%c2vB)k&@@lNxEp9Alc+Uc$9 z>kHmoygAWFiGLNySKt#L0YTV-OVPnC?0HpaEqoEKNquFWwyp8_`K^OJT(-2_^XLCx zzSh@(^{ZeNPz$u+11+r0GqIW3IG5A literal 0 HcmV?d00001 diff --git a/text_analysis/__pycache__/views.cpython-38.pyc b/text_analysis/__pycache__/views.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..036b3d59df1c3052821c58cc815de76c4923edf7 GIT binary patch literal 9644 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 literal 0 HcmV?d00001 diff --git a/text_analysis/bak/views.py0928 b/text_analysis/bak/views.py0928 new file mode 100644 index 0000000..1363c0b --- /dev/null +++ b/text_analysis/bak/views.py0928 @@ -0,0 +1,207 @@ +#coding:utf8 +import os, sys +import io +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8') +cur_dir = os.path.dirname(os.path.abspath(__file__)) or os.getcwd() +par_dir = os.path.abspath(os.path.join(cur_dir, os.path.pardir)) +sys.path.append(cur_dir) +sys.path.append(par_dir) +import json +from django.http import HttpResponse +from text_analysis.tools import to_kafka +from django.views.decorators.csrf import csrf_exempt +from log_util.set_logger import set_logger +logging=set_logger('logs/results.log') +import traceback +import queue +import requests +import time +from datetime import datetime +import os +import joblib +#任务队列 +global task_queue +task_queue = queue.Queue() + + +@csrf_exempt +def robotIdentification(request): + if request.method == 'POST': + try: + raw_data = json.loads(request.body) + task_queue.put(raw_data) + return HttpResponse(json.dumps({"code": 1, "msg": "请求正常!"}, ensure_ascii=False)) + except: + logging.error(traceback.format_exc()) + return HttpResponse(json.dumps({"code": 0, "msg": "请求json格式不正确!"}, ensure_ascii=False)) + else: + return HttpResponse(json.dumps({"code": 0, "msg": "请求方式错误,改为post请求"}, ensure_ascii=False)) + +def predict(): + while True: + if task_queue.qsize() >0: + try: + logging.info("取任务队列长度{}".format(task_queue.qsize())) + raw_data = task_queue.get() + logging.info("原始数据-{}".format(raw_data)) + # raw_data = {"user_file": {"accountId": "39234393", "accountName": "hello", "nickName": "Johnson Leung", + # "fansCount": 308, "likeCount": 92707, "postCount": 14237, + # "otherInfo": "{\"\"otherInfo\"\":\"\"{\"\"bio\"\": \"\"Huge}", + # "authentication": 0}, + # "post_file": {"count": 1, "LikeCount": 12, "CommentsCount": 1, "ShareCount": 1, + # "length": 150, "tags": 0, "https": 0, "at": 0, "diffdate": 1}} + # 用户数据 + res = {"successCode": "1", "errorLog": "", "results": {}} + #获取历史数据源 + all_result = raw_data['data'] + user_data = [] + data=raw_data["metadata"]["admin"] + #{"user_file": "9_获取用户信息", "post_file": "10_获取用户发帖信息"} + user_file_result = json.loads(all_result[data['user_file']]) + post_file_result = json.loads(all_result[data['post_file']]) + if user_file_result['resultList']: + data['user_file'] = user_file_result['resultList'][0] + logging.info('用户数据:{}'.format(data['user_file'])) + else: + data['user_file'] ={} + if post_file_result['resultList']: + data['post_file'] = post_file_result['resultList'][0] + logging.info('帖子数据:{}'.format(data['post_file'])) + else: + data['post_file'] = {} + #识别结果返回值 + recognition_code = "0" + try: + user_data_otherInfo_1 = 0 if data["user_file"]["otherInfo"].strip() == "" else 1 + except: + user_data_otherInfo_1 = 0 + try: + user_data_nickName_2 = 0 if data["user_file"]["nickName"].strip() == "" else 1 + except: + user_data_nickName_2 = 0 + try: + user_data_fansCount_3 = int(data["user_file"]["fansCount"]) + except: + user_data_fansCount_3 = 0 + try: + user_data_likeCount_4 = int(data["user_file"]["likeCount"]) + except: + user_data_likeCount_4 = 0 + try: + user_data_postCount_5 = int(data["user_file"]["postCount"]) + except: + user_data_postCount_5 = 0 + try: + user_data_authentication_6 = int(data["user_file"]["authentication"]) + except: + user_data_authentication_6 = 0 + user_data.extend( + [user_data_otherInfo_1, user_data_nickName_2, user_data_fansCount_3, user_data_likeCount_4, + user_data_postCount_5, user_data_authentication_6]) + # 帖子数据 + if data["post_file"]=={}: + recognition_code = "-1" + else: + post_data = [] + try: + post_data_count_1 = int(data["post_file"]["count"]) + except: + post_data_count_1 = 0 + try: + post_data_LikeCount_2 = int(data["post_file"]["LikeCount"]) + except: + post_data_LikeCount_2 = 0 + try: + post_data_CommentsCount_3 = int(data["post_file"]["CommentsCount"]) + except: + post_data_CommentsCount_3 = 0 + try: + post_data_ShareCount_4 = int(data["post_file"]["ShareCount"]) + except: + post_data_ShareCount_4 = 0 + try: + post_data_length_5 = int(data["post_file"]["length"]) + except: + post_data_length_5 = 0 + try: + post_data_tags_6 = int(data["post_file"]["tags"]) + except: + post_data_tags_6 = 0 + try: + post_data_https_7 = int(data["post_file"]["https"]) + except: + post_data_https_7 = 0 + try: + post_data_at_8 = int(data["post_file"]["at"]) + except: + post_data_at_8 = 0 + try: + post_data_diffdate_9 = int(data["post_file"]["diffdate"]) + except: + post_data_diffdate_9 = 0 + post_data.extend( + [post_data_count_1, post_data_LikeCount_2, post_data_CommentsCount_3, post_data_ShareCount_4, + post_data_length_5, post_data_tags_6, post_data_https_7, post_data_at_8, post_data_diffdate_9]) + features = [user_data + post_data] + bot_user = joblib.load(cur_dir+"/model/bot_user.pkl") # 加载训练好的模型 + result = bot_user.predict(features) + recognition_code = str(result[0]) + # logging.info("预测模型结果为{}".format(result)) + results = {} + # 用户id + results['accountId'] = data["user_file"]["accountId"] + # 用户昵称 + results['nickName'] = data["user_file"]["nickName"] + # 用户账号 + results['accountName'] = data["user_file"]["accountName"] + if recognition_code == '0': + results['recognitionResult'] = '非机器人' + results['recognitionCode'] = recognition_code + elif recognition_code == '1': + results['recognitionResult'] = '机器人' + results['recognitionCode'] = recognition_code + else: + results['recognitionResult'] = '未知识别结果' + results['recognitionCode'] = recognition_code + res['results'] = json.dumps(results) + raw_data["result"] = res + # raw_data_json=json.dumps(raw_data) + logging.info("增加预测数据-{}".format(raw_data)) + to_kafka.send_kafka(raw_data, logging) + except: + res = {"successCode": "0", "errorLog": "", "results": {}} + raw_data["result"] = res + raw_data["result"]["error"] = traceback.format_exc() + # raw_data_json=json.dumps(raw_data) + logging.info(traceback.format_exc()) + to_kafka.send_kafka(raw_data, logging) + else: + #暂无任务,进入休眠 + time.sleep(10) + + +if __name__ == '__main__': + all_result = {"9_获取用户发帖信息":"{\"resultList\": [{\"count\": \"10\", \"LikeCount\": \"1\", \"CommentsCount\": \"0.1\", \"ShareCount\": \"0.4\", \"length\": \"241.8000\", \"tags\": \"5.80000000\", \"https\": \"1.20000000\", \"at\": \"0.40000000\", \"diffdate\": \"170269\"}]}","8_获取用户信息":"{\"resultList\": [{\"accountId\": \"1368232444323799043\", \"accountName\": \"Ujjal best Tech@UjjalKumarGho19\", \"nickName\": \"UjjalKumarGho19\", \"fansCount\": \"660\", \"likeCount\": \"2096\", \"postCount\": \"579\", \"otherInfo\": \"\", \"authentication\": 1}]}"} + data={} + #{"user_file": "9_获取用户信息", "post_file": "10_获取用户发帖信息"} + user_file_result = json.loads(all_result[data['user_file']]) + post_file_result = json.loads(all_result[data['post_file']]) + if user_file_result['resultList']: + resultList = user_file_result['resultList'] + data['user_file'] = resultList[0] + else: + data['user_file'] ={} + if post_file_result['resultList']: + data['post_file'] = post_file_result['resultList'][0] + else: + data['post_file'] = {} + + + print(data) + + + + + + + diff --git a/text_analysis/bak/views.py_0226 b/text_analysis/bak/views.py_0226 new file mode 100644 index 0000000..f006e7c --- /dev/null +++ b/text_analysis/bak/views.py_0226 @@ -0,0 +1,327 @@ +# coding:utf8 +import os, sys +import io + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8') +cur_dir = os.path.dirname(os.path.abspath(__file__)) or os.getcwd() +par_dir = os.path.abspath(os.path.join(cur_dir, os.path.pardir)) +sys.path.append(cur_dir) +sys.path.append(par_dir) +import json +from django.http import HttpResponse +from text_analysis.tools import to_kafka +from django.views.decorators.csrf import csrf_exempt +from log_util.set_logger import set_logger +from text_analysis.tools.tool import parse_data +logging = set_logger('logs/results.log') +import traceback +import queue +import requests +import time +from datetime import datetime +import os +import joblib +from text_analysis.cusException import userFile_Exception, postFile_Exception + +# 任务队列 +global task_queue +task_queue = queue.Queue() + +#mysql连接池 +from text_analysis.tools.db_pool import get_conn_pool + +@csrf_exempt +def robotIdentification(request): + if request.method == 'POST': + try: + raw_data = json.loads(request.body) + task_queue.put(raw_data) + return HttpResponse(json.dumps({"code": 1, "msg": "请求正常!"}, ensure_ascii=False)) + except: + logging.error(traceback.format_exc()) + return HttpResponse(json.dumps({"code": 0, "msg": "请求json格式不正确!"}, ensure_ascii=False)) + else: + return HttpResponse(json.dumps({"code": 0, "msg": "请求方式错误,改为post请求"}, ensure_ascii=False)) + + +def predict(user_file_result,post_file_result,task): + try: + # raw_data = {"user_file": {"accountId": "39234393", "accountName": "hello", "nickName": "Johnson Leung", + # "fansCount": 308, "likeCount": 92707, "postCount": 14237, + # "otherInfo": "{\"\"otherInfo\"\":\"\"{\"\"bio\"\": \"\"Huge}", + # "authentication": 0}, + # "post_file": {"count": 1, "LikeCount": 12, "CommentsCount": 1, "ShareCount": 1, + # "length": 150, "tags": 0, "https": 0, "at": 0, "diffdate": 1}} + # 用户数据 + res = {"successCode": "1", "errorLog": "", "results": {}} + user_data = [] + # 返回值需要的三个字段 + accountId = "" + nickName = "" + accountName = "" + data = {} + if user_file_result: + data['user_file'] = user_file_result + logging.info('用户数据:{}'.format(data['user_file'])) + accountId = data["user_file"]["accountId"] + nickName = data["user_file"]["nickName"] + accountName = data["user_file"]["accountName"] + else: + data['user_file'] = {} + raise userFile_Exception + if post_file_result: + data['post_file'] = post_file_result + logging.info('帖子数据:{}'.format(data['post_file'])) + else: + data['post_file'] = {} + raise postFile_Exception + # 识别结果返回值 + recognition_code = "0" + try: + user_data_otherInfo_1 = 0 if data["user_file"]["otherInfo"].strip() == "" else 1 + except: + user_data_otherInfo_1 = 0 + try: + user_data_nickName_2 = 0 if data["user_file"]["nickName"].strip() == "" else 1 + except: + user_data_nickName_2 = 0 + try: + user_data_fansCount_3 = int(data["user_file"]["fansCount"]) + except: + user_data_fansCount_3 = 0 + try: + user_data_likeCount_4 = int(data["user_file"]["likeCount"]) + except: + user_data_likeCount_4 = 0 + try: + user_data_postCount_5 = int(data["user_file"]["postCount"]) + except: + user_data_postCount_5 = 0 + try: + user_data_authentication_6 = int(data["user_file"]["authentication"]) + except: + user_data_authentication_6 = 0 + user_data.extend( + [user_data_otherInfo_1, user_data_nickName_2, user_data_fansCount_3, user_data_likeCount_4, + user_data_postCount_5, user_data_authentication_6]) + # 帖子数据 + if data["post_file"] == {}: + recognition_code = "-1" + else: + post_data = [] + try: + post_data_count_1 = int(data["post_file"]["count"]) + except: + post_data_count_1 = 0 + try: + post_data_LikeCount_2 = int(data["post_file"]["LikeCount"]) + except: + post_data_LikeCount_2 = 0 + try: + post_data_CommentsCount_3 = int(data["post_file"]["CommentsCount"]) + except: + post_data_CommentsCount_3 = 0 + try: + post_data_ShareCount_4 = int(data["post_file"]["ShareCount"]) + except: + post_data_ShareCount_4 = 0 + try: + post_data_length_5 = int(data["post_file"]["length"]) + except: + post_data_length_5 = 0 + try: + post_data_tags_6 = int(data["post_file"]["tags"]) + except: + post_data_tags_6 = 0 + try: + post_data_https_7 = int(data["post_file"]["https"]) + except: + post_data_https_7 = 0 + try: + post_data_at_8 = int(data["post_file"]["at"]) + except: + post_data_at_8 = 0 + try: + post_data_diffdate_9 = int(data["post_file"]["diffdate"]) + except: + post_data_diffdate_9 = 0 + post_data.extend( + [post_data_count_1, post_data_LikeCount_2, post_data_CommentsCount_3, post_data_ShareCount_4, + post_data_length_5, post_data_tags_6, post_data_https_7, post_data_at_8, post_data_diffdate_9]) + features = [user_data + post_data] + bot_user = joblib.load(cur_dir + "/model/bot_user.pkl") # 加载训练好的模型 + result = bot_user.predict(features) + recognition_code = str(result[0]) + # logging.info("预测模型结果为{}".format(result)) + results = {} + # 用户id + results['authorId'] = accountId + # 用户昵称 + results['nickName'] = nickName + # 用户账号 + results['accountName'] = accountName + #结束标识 + res['isLast'] = True + #数据类型 --目前只提供给图谱使用 + results['pageType'] = 'userAuthenPage' + if recognition_code == '0': + results['recognitionResult'] = '非机器人' + results['recognitionCode'] = recognition_code + elif recognition_code == '1': + results['recognitionResult'] = '机器人' + results['recognitionCode'] = recognition_code + else: + results['recognitionResult'] = '未知识别结果' + results['recognitionCode'] = recognition_code + res['results'] = json.dumps(results) + task["result"] = res + logging.info("增加预测数据-{}".format(task)) + to_kafka.send_kafka(task, logging) + except userFile_Exception: + res = {"successCode": "0", "errorLog": "用户数据为空!", "results": {}} + results = {} + results['authorId'] = "" + results['nickName'] = "" + results['accountName'] = "" + results['recognitionResult'] = '用户数据为空' + res['results'] = json.dumps(results) + task["result"] = res + logging.info("该条请求用户数据为空-{}".format(task)) + to_kafka.send_kafka(task, logging) + except postFile_Exception: + res = {"successCode": "0", "errorLog": "帖子数据为空!", "results": {}} + results = {} + results['authorId'] = accountId + results['nickName'] = nickName + results['accountName'] = accountName + results['recognitionResult'] = '帖子数据为空' + res['results'] = json.dumps(results) + task["result"] = res + logging.info("该条请求帖子数据为空-{}".format(task)) + to_kafka.send_kafka(task, logging) + except: + res = {"successCode": "0", "errorLog": "", "results": {}} + results = {} + results['authorId'] = accountId + results['nickName'] = nickName + results['accountName'] = accountName + results['recognitionResult'] = "" + res["results"] = json.dumps(results) + task["result"] = res + task["result"]["error"] = traceback.format_exc() + logging.info(traceback.format_exc()) + to_kafka.send_kafka(task, logging) + +def data_structure(dbConfig): + ''' + 水军识别数据构造 + 主要是写入用户表、主贴表 + ''' + #获取数据库连接 + sqlhelper = get_conn_pool(dbConfig['host'],dbConfig['port'],dbConfig['username'],dbConfig['password'],dbConfig['db']) + #用户任务作为响应体 + send_task = None + while True: + if task_queue.qsize() > 0: + try: + logging.info("队列长度:{}".format(task_queue.qsize())) + task = task_queue.get() + input = task['input'] + account = input['account'] + post = input['post'] + #判断数据类型 + data = task['data'] + page_type = None + taskId = None + for data_str in data: + try: + app_data = json.loads(data[data_str]) + taskId = app_data['taskId'] + if "pageType" in app_data: + page_type = app_data['pageType'] + break + except: + logging.error("正常判断,异常请忽略") + logging.info("数据类型:{}".format(page_type)) + if page_type == 'userInfoPage': + # 用户任务作为响应体 + send_task = task + #用户类型数据写入 + sql = "INSERT INTO `user_account`(`taskId`, `accountId`, `accountName`, `nickName`, `fansCount`, `likeCount`, `postCount`, `otherInfo`, `authentication`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" + # 构造参数元组 + values = ( + parse_data(task, account['taskId']), + parse_data(task, account['accountId']), + parse_data(task, account['accountName']), + parse_data(task, account['nickName']), + parse_data(task, account['fansCount']), + parse_data(task, account['likeCount']), + parse_data(task, account['postCount']), + parse_data(task, account['otherInfo']), + parse_data(task, account['authentication']) + ) + sqlhelper.insert(sql,values) + + elif page_type == 'storyDetailPage': + #帖子类型数据写入 + # 定义 SQL 语句 + sql = "INSERT INTO `user_post`(`taskId`, `postId`, `accountId`, `accountName`, `likeCount`, `emotionCount`, `commentsCount`, `shareCount`, `content`, `pubTime`, `crawlTime`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" + # 构造参数元组 + values = ( + parse_data(task, post['taskId']), + parse_data(task, post['postId']), + parse_data(task, post['accountId']), + parse_data(task, post['accountName']), + parse_data(task, post['likeCount']), + parse_data(task, post['emotionCount']), + parse_data(task, post['commentsCount']), + parse_data(task, post['shareCount']), + parse_data(task, post['content']), + parse_data(task, post['pubTime']), + parse_data(task, post['crawlTime']) + ) + sqlhelper.insert(sql,values) + #判断是否是此次数据流的最后一条,最后一条直接触发用户的水军识别算法 + if 'isLast'in data and data['isLast']: + #获取用户相关的数据 + sql = "select accountId,accountName,nickName,fansCount,likeCount,postCount,otherInfo,authentication from user_account where taskId ='{}'".format(taskId) + user_file_result = sqlhelper.queryOne(sql) + # 获取帖子相关的数据 + sql = "SELECT CONVERT(COUNT(postId), CHAR(255)) AS count, CONVERT(AVG(likeCount), CHAR(255)) AS LikeCount, CONVERT(AVG(commentsCount), CHAR(255)) AS CommentsCount, CONVERT(AVG(shareCount), CHAR(255)) AS ShareCount, CONVERT(AVG(LENGTH(content)), CHAR(255)) AS length, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, '#', ''))) / LENGTH('#')), CHAR(255)) AS tags, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, 'https', ''))) / LENGTH('https')), CHAR(255)) AS https, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, '@', ''))) / LENGTH('@')), CHAR(255)) AS at, CONVERT(MIN(TIMESTAMPDIFF(SECOND, pubTime, GREATEST(pubTime, crawlTime))), CHAR(255)) AS diffdate FROM user_post where taskId ='{}'".format(taskId) + post_file_result = sqlhelper.queryOne(sql) + if send_task == None: + send_task = task + predict(user_file_result,post_file_result,send_task) + #结束置空 + send_task = None + except Exception as e: + traceback.print_exc() + else: + # 暂无任务,进入休眠 + time.sleep(10) +if __name__ == '__main__': + all_result = { + "9_获取用户发帖信息": "{\"resultList\": [{\"count\": \"10\", \"LikeCount\": \"1\", \"CommentsCount\": \"0.1\", \"ShareCount\": \"0.4\", \"length\": \"241.8000\", \"tags\": \"5.80000000\", \"https\": \"1.20000000\", \"at\": \"0.40000000\", \"diffdate\": \"170269\"}]}", + "8_获取用户信息": "{\"resultList\": [{\"accountId\": \"1368232444323799043\", \"accountName\": \"Ujjal best Tech@UjjalKumarGho19\", \"nickName\": \"UjjalKumarGho19\", \"fansCount\": \"660\", \"likeCount\": \"2096\", \"postCount\": \"579\", \"otherInfo\": \"\", \"authentication\": 1}]}"} + data = {} + # {"user_file": "9_获取用户信息", "post_file": "10_获取用户发帖信息"} + user_file_result = json.loads(all_result[data['user_file']]) + post_file_result = json.loads(all_result[data['post_file']]) + if user_file_result['resultList']: + resultList = user_file_result['resultList'] + data['user_file'] = resultList[0] + else: + data['user_file'] = {} + if post_file_result['resultList']: + data['post_file'] = post_file_result['resultList'][0] + else: + data['post_file'] = {} + + print(data) + + + + + + + diff --git a/text_analysis/bak/views.py_0607 b/text_analysis/bak/views.py_0607 new file mode 100644 index 0000000..b6b0e96 --- /dev/null +++ b/text_analysis/bak/views.py_0607 @@ -0,0 +1,335 @@ +# coding:utf8 +import os, sys +import io + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8') +cur_dir = os.path.dirname(os.path.abspath(__file__)) or os.getcwd() +par_dir = os.path.abspath(os.path.join(cur_dir, os.path.pardir)) +sys.path.append(cur_dir) +sys.path.append(par_dir) +import json +from django.http import HttpResponse +from text_analysis.tools import to_kafka +from django.views.decorators.csrf import csrf_exempt +from log_util.set_logger import set_logger +from text_analysis.tools.tool import parse_data +logging = set_logger('logs/results.log') +import traceback +import queue +import requests +import time +from datetime import datetime +import os +import joblib +from text_analysis.cusException import userFile_Exception, postFile_Exception + +# 任务队列 +global task_queue +task_queue = queue.Queue() + +#mysql连接池 +from text_analysis.tools.db_pool import get_conn_pool + +@csrf_exempt +def robotIdentification(request): + if request.method == 'POST': + try: + raw_data = json.loads(request.body) + task_queue.put(raw_data) + return HttpResponse(json.dumps({"code": 1, "msg": "请求正常!"}, ensure_ascii=False)) + except: + logging.error(traceback.format_exc()) + return HttpResponse(json.dumps({"code": 0, "msg": "请求json格式不正确!"}, ensure_ascii=False)) + else: + return HttpResponse(json.dumps({"code": 0, "msg": "请求方式错误,改为post请求"}, ensure_ascii=False)) + + +def predict(user_file_result,post_file_result,task): + try: + # raw_data = {"user_file": {"accountId": "39234393", "accountName": "hello", "nickName": "Johnson Leung", + # "fansCount": 308, "likeCount": 92707, "postCount": 14237, + # "otherInfo": "{\"\"otherInfo\"\":\"\"{\"\"bio\"\": \"\"Huge}", + # "authentication": 0}, + # "post_file": {"count": 1, "LikeCount": 12, "CommentsCount": 1, "ShareCount": 1, + # "length": 150, "tags": 0, "https": 0, "at": 0, "diffdate": 1}} + # 用户数据 + res = {"successCode": "1", "errorLog": "", "results": {}} + user_data = [] + # 返回值需要的三个字段 + accountId = "" + nickName = "" + accountName = "" + data = {} + if user_file_result: + data['user_file'] = user_file_result + logging.info('用户数据:{}'.format(data['user_file'])) + accountId = data["user_file"]["accountId"] + nickName = data["user_file"]["nickName"] + accountName = data["user_file"]["accountName"] + else: + data['user_file'] = {} + raise userFile_Exception + if post_file_result: + data['post_file'] = post_file_result + logging.info('帖子数据:{}'.format(data['post_file'])) + else: + data['post_file'] = {} + raise postFile_Exception + # 识别结果返回值 + recognition_code = "0" + try: + user_data_otherInfo_1 = 0 if data["user_file"]["otherInfo"].strip() == "" else 1 + except: + user_data_otherInfo_1 = 0 + try: + user_data_nickName_2 = 0 if data["user_file"]["nickName"].strip() == "" else 1 + except: + user_data_nickName_2 = 0 + try: + user_data_fansCount_3 = int(data["user_file"]["fansCount"]) + except: + user_data_fansCount_3 = 0 + try: + user_data_likeCount_4 = int(data["user_file"]["likeCount"]) + except: + user_data_likeCount_4 = 0 + try: + user_data_postCount_5 = int(data["user_file"]["postCount"]) + except: + user_data_postCount_5 = 0 + try: + user_data_authentication_6 = int(data["user_file"]["authentication"]) + except: + user_data_authentication_6 = 0 + user_data.extend( + [user_data_otherInfo_1, user_data_nickName_2, user_data_fansCount_3, user_data_likeCount_4, + user_data_postCount_5, user_data_authentication_6]) + # 帖子数据 + if data["post_file"] == {}: + recognition_code = "-1" + else: + post_data = [] + try: + post_data_count_1 = int(data["post_file"]["count"]) + except: + post_data_count_1 = 0 + try: + post_data_LikeCount_2 = int(data["post_file"]["LikeCount"]) + except: + post_data_LikeCount_2 = 0 + try: + post_data_CommentsCount_3 = int(data["post_file"]["CommentsCount"]) + except: + post_data_CommentsCount_3 = 0 + try: + post_data_ShareCount_4 = int(data["post_file"]["ShareCount"]) + except: + post_data_ShareCount_4 = 0 + try: + post_data_length_5 = int(data["post_file"]["length"]) + except: + post_data_length_5 = 0 + try: + post_data_tags_6 = int(data["post_file"]["tags"]) + except: + post_data_tags_6 = 0 + try: + post_data_https_7 = int(data["post_file"]["https"]) + except: + post_data_https_7 = 0 + try: + post_data_at_8 = int(data["post_file"]["at"]) + except: + post_data_at_8 = 0 + try: + post_data_diffdate_9 = int(data["post_file"]["diffdate"]) + except: + post_data_diffdate_9 = 0 + post_data.extend( + [post_data_count_1, post_data_LikeCount_2, post_data_CommentsCount_3, post_data_ShareCount_4, + post_data_length_5, post_data_tags_6, post_data_https_7, post_data_at_8, post_data_diffdate_9]) + features = [user_data + post_data] + bot_user = joblib.load(cur_dir + "/model/bot_user.pkl") # 加载训练好的模型 + result = bot_user.predict(features) + recognition_code = str(result[0]) + # logging.info("预测模型结果为{}".format(result)) + results = {} + # 用户id + results['authorId'] = accountId + # 用户昵称 + results['nickName'] = nickName + # 用户账号 + results['accountName'] = accountName + #结束标识 + res['isLast'] = True + #数据类型 --目前只提供给图谱使用 + results['pageType'] = 'userAuthenPage' + if recognition_code == '0': + results['recognitionResult'] = '非机器人' + results['recognitionCode'] = recognition_code + elif recognition_code == '1': + results['recognitionResult'] = '机器人' + results['recognitionCode'] = recognition_code + else: + results['recognitionResult'] = '未知识别结果' + results['recognitionCode'] = recognition_code + res['results'] = json.dumps(results) + res["status"]=1 + res["message"]="成功" + task["result"] = res + logging.info("增加预测数据-{}".format(task)) + to_kafka.send_kafka(task, logging) + except userFile_Exception: + res = {"successCode": "0", "errorLog": "用户数据为空!", "results": {}} + results = {} + results['authorId'] = "" + results['nickName'] = "" + results['accountName'] = "" + results['recognitionResult'] = '用户数据为空' + res['results'] = json.dumps(results) + res["status"]=2 + res["message"]="用户数据为空" + task["result"] = res + logging.info("该条请求用户数据为空-{}".format(task)) + to_kafka.send_kafka(task, logging) + except postFile_Exception: + res = {"successCode": "0", "errorLog": "帖子数据为空!", "results": {}} + results = {} + results['authorId'] = accountId + results['nickName'] = nickName + results['accountName'] = accountName + results['recognitionResult'] = '帖子数据为空' + res['results'] = json.dumps(results) + res["status"]=2 + res["message"]="帖子数据为空" + task["result"] = res + logging.info("该条请求帖子数据为空-{}".format(task)) + to_kafka.send_kafka(task, logging) + except: + res = {"successCode": "0", "errorLog": "", "results": {}} + results = {} + results['authorId'] = accountId + results['nickName'] = nickName + results['accountName'] = accountName + results['recognitionResult'] = "" + res["results"] = json.dumps(results) + res["status"]=2 + res["message"]="异常" + task["result"] = res + task["result"]["error"] = traceback.format_exc() + logging.info(traceback.format_exc()) + to_kafka.send_kafka(task, logging) + +def data_structure(dbConfig): + ''' + 水军识别数据构造 + 主要是写入用户表、主贴表 + ''' + #获取数据库连接 + sqlhelper = get_conn_pool(dbConfig['host'],dbConfig['port'],dbConfig['username'],dbConfig['password'],dbConfig['db']) + #用户任务作为响应体 + send_task = None + while True: + if task_queue.qsize() > 0: + try: + logging.info("队列长度:{}".format(task_queue.qsize())) + task = task_queue.get() + input = task['input'] + account = input['account'] + post = input['post'] + #判断数据类型 + data = task['data'] + page_type = None + taskId = None + for data_str in data: + try: + app_data = json.loads(data[data_str]) + taskId = app_data['taskId'] + if "pageType" in app_data: + page_type = app_data['pageType'] + break + except: + logging.error("正常判断,异常请忽略") + logging.info("数据类型:{}".format(page_type)) + if page_type == 'userInfoPage': + # 用户任务作为响应体 + send_task = task + #用户类型数据写入 + sql = "INSERT INTO `user_account`(`taskId`, `accountId`, `accountName`, `nickName`, `fansCount`, `likeCount`, `postCount`, `otherInfo`, `authentication`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" + # 构造参数元组 + values = ( + parse_data(task, account['taskId']), + parse_data(task, account['accountId']), + parse_data(task, account['accountName']), + parse_data(task, account['nickName']), + parse_data(task, account['fansCount']), + parse_data(task, account['likeCount']), + parse_data(task, account['postCount']), + parse_data(task, account['otherInfo']), + parse_data(task, account['authentication']) + ) + sqlhelper.insert(sql,values) + + elif page_type == 'storyDetailPage': + #帖子类型数据写入 + # 定义 SQL 语句 + sql = "INSERT INTO `user_post`(`taskId`, `postId`, `accountId`, `accountName`, `likeCount`, `emotionCount`, `commentsCount`, `shareCount`, `content`, `pubTime`, `crawlTime`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" + # 构造参数元组 + values = ( + parse_data(task, post['taskId']), + parse_data(task, post['postId']), + parse_data(task, post['accountId']), + parse_data(task, post['accountName']), + parse_data(task, post['likeCount']), + parse_data(task, post['emotionCount']), + parse_data(task, post['commentsCount']), + parse_data(task, post['shareCount']), + parse_data(task, post['content']), + parse_data(task, post['pubTime']), + parse_data(task, post['crawlTime']) + ) + sqlhelper.insert(sql,values) + #判断是否是此次数据流的最后一条,最后一条直接触发用户的水军识别算法 + if 'isLast'in data and data['isLast']: + #获取用户相关的数据 + sql = "select accountId,accountName,nickName,fansCount,likeCount,postCount,otherInfo,authentication from user_account where taskId ='{}'".format(taskId) + user_file_result = sqlhelper.queryOne(sql) + # 获取帖子相关的数据 + sql = "SELECT CONVERT(COUNT(postId), CHAR(255)) AS count, CONVERT(AVG(likeCount), CHAR(255)) AS LikeCount, CONVERT(AVG(commentsCount), CHAR(255)) AS CommentsCount, CONVERT(AVG(shareCount), CHAR(255)) AS ShareCount, CONVERT(AVG(LENGTH(content)), CHAR(255)) AS length, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, '#', ''))) / LENGTH('#')), CHAR(255)) AS tags, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, 'https', ''))) / LENGTH('https')), CHAR(255)) AS https, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, '@', ''))) / LENGTH('@')), CHAR(255)) AS at, CONVERT(MIN(TIMESTAMPDIFF(SECOND, pubTime, GREATEST(pubTime, crawlTime))), CHAR(255)) AS diffdate FROM user_post where taskId ='{}'".format(taskId) + post_file_result = sqlhelper.queryOne(sql) + if send_task == None: + send_task = task + predict(user_file_result,post_file_result,send_task) + #结束置空 + send_task = None + except Exception as e: + traceback.print_exc() + else: + # 暂无任务,进入休眠 + time.sleep(10) +if __name__ == '__main__': + all_result = { + "9_获取用户发帖信息": "{\"resultList\": [{\"count\": \"10\", \"LikeCount\": \"1\", \"CommentsCount\": \"0.1\", \"ShareCount\": \"0.4\", \"length\": \"241.8000\", \"tags\": \"5.80000000\", \"https\": \"1.20000000\", \"at\": \"0.40000000\", \"diffdate\": \"170269\"}]}", + "8_获取用户信息": "{\"resultList\": [{\"accountId\": \"1368232444323799043\", \"accountName\": \"Ujjal best Tech@UjjalKumarGho19\", \"nickName\": \"UjjalKumarGho19\", \"fansCount\": \"660\", \"likeCount\": \"2096\", \"postCount\": \"579\", \"otherInfo\": \"\", \"authentication\": 1}]}"} + data = {} + # {"user_file": "9_获取用户信息", "post_file": "10_获取用户发帖信息"} + user_file_result = json.loads(all_result[data['user_file']]) + post_file_result = json.loads(all_result[data['post_file']]) + if user_file_result['resultList']: + resultList = user_file_result['resultList'] + data['user_file'] = resultList[0] + else: + data['user_file'] = {} + if post_file_result['resultList']: + data['post_file'] = post_file_result['resultList'][0] + else: + data['post_file'] = {} + + print(data) + + + + + + + diff --git a/text_analysis/cusException.py b/text_analysis/cusException.py new file mode 100644 index 0000000..f157618 --- /dev/null +++ b/text_analysis/cusException.py @@ -0,0 +1,9 @@ +# -*- coding:utf-8 -*- + +class userFile_Exception(Exception): + def __str__(self): + return '用户数据为空' + +class postFile_Exception(Exception): + def __str__(self): + return '帖子数据为空' \ No newline at end of file diff --git a/text_analysis/linshi.py b/text_analysis/linshi.py new file mode 100644 index 0000000..d4e4b90 --- /dev/null +++ b/text_analysis/linshi.py @@ -0,0 +1,101 @@ +#coding:utf8 +import joblib +import json +import os +cur_dir = os.path.dirname(os.path.abspath(__file__)) or os.getcwd() +import numpy as np +class MyEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, np.integer): + return int(obj) + elif isinstance(obj, np.floating): + return float(obj) + elif isinstance(obj, np.ndarray): + return obj.tolist() + +raw_data = {"user_file": {"accountId": "39234393", "accountName": "hello", "nickName": "Johnson Leung", + "fansCount": 308, "likeCount": 92707, "postCount": 14237, + "otherInfo": "{\"\"otherInfo\"\":\"\"{\"\"bio\"\": \"\"Huge}", + "authentication": 0}, + "post_file": {"count": 1, "LikeCount": 12, "CommentsCount": 1, "ShareCount": 1, + "length": 150, "tags": 0, "https": 0, "at": 0, "diffdate": 1}} +# 用户数据 +res = {"successCode": "1", "errorLog": "", "results": {}} +user_data = [] +try: + user_data_otherInfo_1 = 0 if raw_data["user_file"]["otherInfo"].strip() == "" else 1 +except: + user_data_otherInfo_1 = 0 +try: + user_data_nickName_2 = 0 if raw_data["user_file"]["nickName"].strip() == "" else 1 +except: + user_data_nickName_2 = 0 +try: + user_data_fansCount_3 = int(raw_data["user_file"]["fansCount"]) +except: + user_data_fansCount_3 = 0 +try: + user_data_likeCount_4 = int(raw_data["user_file"]["likeCount"]) +except: + user_data_likeCount_4 = 0 +try: + user_data_postCount_5 = int(raw_data["user_file"]["postCount"]) +except: + user_data_postCount_5 = 0 +try: + user_data_authentication_6 = int(raw_data["user_file"]["authentication"]) +except: + user_data_authentication_6 = 0 +user_data.extend( + [user_data_otherInfo_1, user_data_nickName_2, user_data_fansCount_3, user_data_likeCount_4, + user_data_postCount_5, user_data_authentication_6]) +# 帖子数据 +post_data = [] +try: + post_data_count_1 = int(raw_data["post_file"]["count"]) +except: + post_data_count_1 = 0 +try: + post_data_LikeCount_2 = int(raw_data["post_file"]["LikeCount"]) +except: + post_data_LikeCount_2 = 0 +try: + post_data_CommentsCount_3 = int(raw_data["post_file"]["CommentsCount"]) +except: + post_data_CommentsCount_3 = 0 +try: + post_data_ShareCount_4 = int(raw_data["post_file"]["ShareCount"]) +except: + post_data_ShareCount_4 = 0 +try: + post_data_length_5 = int(raw_data["post_file"]["length"]) +except: + post_data_length_5 = 0 +try: + post_data_tags_6 = int(raw_data["post_file"]["tags"]) +except: + post_data_tags_6 = 0 +try: + post_data_https_7 = int(raw_data["post_file"]["https"]) +except: + post_data_https_7 = 0 +try: + post_data_at_8 = int(raw_data["post_file"]["at"]) +except: + post_data_at_8 = 0 +try: + post_data_diffdate_9 = int(raw_data["post_file"]["diffdate"]) +except: + post_data_diffdate_9 = 0 +post_data.extend( + [post_data_count_1, post_data_LikeCount_2, post_data_CommentsCount_3, post_data_ShareCount_4, + post_data_length_5, post_data_tags_6, post_data_https_7, post_data_at_8, post_data_diffdate_9]) +features = [user_data + post_data] +print(cur_dir + "/model/bot_user.pkl") +bot_user = joblib.load(cur_dir + "/model/bot_user.pkl") # 加载训练好的模型 +result = bot_user.predict(features) +res["results"] = result[0] +# logging.info("预测模型结果为{}".format(result)) +raw_data["result"] = res +# print(raw_data) +print(raw_data) \ No newline at end of file diff --git a/text_analysis/model/bot_user.pkl b/text_analysis/model/bot_user.pkl new file mode 100644 index 0000000000000000000000000000000000000000..419f983560d597a8ddd843141406fe7b09ea4bac GIT binary patch literal 594441 zcmeFa1$*JeiUf+5K#?G&K(PYFy@4V@ic1Kt z3GNW2IOV^|eV$7)`|hvzyU_CGegAy=>60__oH=J^&YYQh_wL=W)YH4CG9>;Bw+rsw z$HybczpRgcuuoslK0amLeES9Y1cyX~=WH}EB*>#fkdIGrgFYU?!G6AeK0y)FB1(*i z7#iUep58?A>+2EHFDN2B7h4H2vCF!7CD46>Bf@iNP5h57cm?@|_yqa&^N$Em-P6zC zFCyF~IG~STh^a6lJZ+GNzjwdB5#j0kdJJ^)_6Z0vMzjjg*4NM9E!d-PKp&rAw?uM; zbINerq@||*_(nLV2)9cp9N^>E(-`9B8|2{?Vlw2GSlLAFyulEjDWPp&ACHhwQ=d&< z1P2D0dY&brG=b^n-_P4r-YPtk>Wo`(h)0NzNzRqfwqM_XP*V>EnVj^ ziEaTNK^}dBBb}Tqg>F*2!Jc9Zr z^xiZ)zvY<%{hfJyEYIezj7LLwKC@USdv%!GdvrH z-p${muW3F_V`_>SlM8+PJj?or_6->17U1V)3ebq~Y^@T+dO<-RgF2Z!4@eq`Ho>8u ziNhTco+eQ%B0QbHw?_ik6t3ZEf{h*lre0(nZTh=kkat3GrD$OK+dE{CsoYrBSjEIj z*}8hf_;F(++C?}yrwUIoB%)QTR?R<{{w4m;SqX{o4A0=vr%%5DZhiYE4qblL!$do# zsrBpW-`B@K#LaV1h$&>8Z9_f7QhFs)$|ekN*}kEDLi`fR8Qe^B(a+yB1)*Lc83GL| zD+6545SYT*Fgh@$mz$R<_`HHM`1mLMks&aZYYJ1`dIqL;O>4qF9wC1I6#~VcU|{R_<8E-;I!hly z7*ZI?=bFJ(*52q51S|Q~f$;I~8Db19;F{W08{*M3IPjaqhK(U10l|R<6Fct_5?Cm) z2i|_ZzTT!~5NPic5?I)??DQa$Qo_IREdE*^NQ^`0tl=5_-TH-w1cZhJyCvik8>BV2 z2xCb#2O7&5%Nr{=ryLz&tYoZgtYWMho-(w;$1pP1Og_8@QxF+zk2BUuh>r9L!Ik*W zkYf5#)eF-?^Jn%n*-ROpA;~H>rVr1kr2vyl-A(J?296}Gzs$xg|L--JyZOot!!spa zigvAxA6KKXu5(tSVp_f8|J6U=WXq(sv`muqFdh4c&Z!WuOy7h8W7F_l|KkcVW&dC= zk3Jp=+fBlt`Xw=H>|j2q4QvuZJmFu&7}E+4&zv-^n+7sfc$$Qr$&_8PC*P?ON=<1$ zVUshNGW9?C%%;$0wyQR8DL&BF^b83L()7Bnk;Ob!ZY;o@eOhFGWzu~rRp`8hm~x()hxyGb=6iCzaAyE+@jL>NO%Xk)@q6WW@vzp=fuoe2k+ z(B6atP32A|9AuKqkBJC%u5L;=wn>9Jb;6WmR1AM%pfakXWXK(I>0Dp$ltSDbzHND@ zQ;K`SisiqsDT3n~i$8EiF@#2zsP`uCU&8gL<3(H^omAQ+)e}<$dF{|vLYheUcQEAX z0PmXZMcs8XW_ipxsZ>v@7dKf@{6?i4s25hJR+HipO~v;`4vnez`n=K$^@$MHMI@xH zgntE8Fr)+Cno|FptA8{UtD9UMoO5-ok`v`BR2B(oJKW9_$|=+Ri@Y&hS4 zZ>3lz2kKR*B-nm#lqaO-gnu2sYmoMW>o#TN>zqCdFK@Rp~|*`@sUX_FwpMFTX_ThHgphbah$^V08JphXz&;QLVXm_ zz<5;UctumdAD>%K_A@ISVLY&YvMM8i%q>tivs%tP5)g|xNcOMjqdTJ|7c#f-oHH$|F%7OJnb+*d4Y`Y z`gwo75<0;$A2Rr$JTz^YWv^!n1*B#BCtfzN9eCc^Fh<>#MGLKA+ zD*49g>Qk{}{oFqn{(M$(L46{Gbrgjl+XI=OCbw;W|MuaPif`KfciSI4qj3LF^*ZRD z2RRQGhMg9YJ(p7f>n^@{rg&GVU20o{V@fmBCxU1v93U45GB0}MeDuBTm|v8QU2Yv{ zG3%hxB&l9hTTukEqon8bYWt4ubrvc%G5)<%I&V_A@2IqDy8FkxrRr4{MPa8Hkp2JW zL4gmGH_!a!IJ0)$%JJz0|D1tb4{4_OH_g%LnNoeyb<=;xmGY=pp{XbVxwfPia{KD$ z)P;5{B{S42w&1&HrED_2CZZ(dT0qWUiO@aH?F+;z4}#u)mudP@g>kIX>WWg}*8~!( z46U(#_Kt1Jxv~4+M7x^u1uGJOgJ3 zUHMmEzZw06T6|97{-es}1^ZhKdbHQBTwTY3J11-QxZkO?vZ5ULRVBTrjqX*==P_Q} z$K*W7d8qZccKuna$9Yx9$w7Bsveq8=4b`5lZhMS(RnK0xo}8EJs0|pJ1GyhZ z|5)w#Z4n_7i^EQut-re9Hv)3qK5wu+=JkRGg84;We+YO(L+EimTsvVmZuHEH%8kTC zxJTjnM5Q?i0e%A@<9coJqNCC+Yb%&vn%{Q5xpS-!@sg)<9e`s&V~^8D$|6Fjf0 z!%#pp#&|RXa({TWt<%bGFK<}fH@V+8g&y-{SZL~2QG>e(wfO(fFP5(3ternuuNB6> zEs$}YCUpIrk@@;-^C0J!*5J1Ra-EF`xHhX%@NJ9pt~btPKlSQan?Gf}_UP9YI6{A} zu50bJHbv2Ty?(gTAjg3i=}fQ1G0KsodhU}1uM56|9_Q&^+3kij?{d{^dSYDZ zhWCyr{gdjgogg~F-Z1Df4;FkhqWX!Hy+ohYo7N27dPE6Ls<&){aD`qd^cXLVkAzk& zvSg@;?EYa_YvU0mFsa_S38FLfT%gDGUS!=SzbOOz3db?~ey}NUMCp@M&wYaE0=@1) z&QlT3ask=a%~YCR4jr<_=a}*U?IzOP$BM4tcLOpn#pcUg|D^FZ?R=J0%|z9`|IrV% zdF$`L^nicu;Rxep{L&5~Hw_uYk#nn-4zG4hxtG+@He-bw^xC1E^ROe0SLxW1L&T+v zl{2?Jaa6gTRImD2;SN0yAm_bZ!5QBN-tQn5SITju`;SMJTS@iGkJUXcyv|5$KCGee zgq^l%kLQiTg}h#L8(&yV&J~@meWv5e_N4aij22$dD~WQhhqT=mUa8XSy5jxoxx&YD z9apv`)r%V~yrFj+$niYc?$&^}F%J~`4=vXWT69#Iom4M+l<)!n8jxYw{8^o1MYF#U z^L_jp9%`^dsgrc#ql1Mn_`rTJN*KZ!KqF8Y8!6v*+cux;U7yT3eyd-3?l z5zRL!ygo^!g*6j>!5;!-yd0Pt9#b^uK}FPPa^t&<8x>whsd`O?KluG5y@2>7*QVu} zrHIOBOjoK=X4k2D_ao+GwRu|+06X7G_AYg96LBu@0qxvshk6yNi$KVOCB2a)R!{WK z7iIB&ND%mgfIPoBP3U-J-Rm35#s+cwDmwk4Fh8oaVj>v)fk4(*b1Uuq(&4Ih{m%AO zS^*IP{s187?`XO39k=pyvUt7@1;0O#@wuRdVyy4%D%4{0`|Nt>f$LdqNB@1{q|3oz zus+Z0^^@xh!=O9w%5kRG9@mL#&q=pEYsV!QI;KJu-S(^<7oJlS?M1a0VX!{}$Z@++ zbKEx%-#r&<@t42u_zwOp2XY|LGydEpy5+_TUC(I_eW)zNZ)k`BxzKhX-pa zyq}vZjfnIfyY+tDI_3MMdcs4DhP({Oe7!cj(1PY;udC;!>Kl}>qHyXdPkickA(sko{(P zemwZ|fsFgnt2%YrStV8(cPLBynHP5|Wl*08VT}dH=|`0F{PM2NvDCwyZYyon8+M9Q zQawXMF#+-{Amex6_>I-CZwwXDStmq{Sh_-SOr}>~ghQSPq@Q>DobtR>@|0r#%f(JE zkJl^tlIhjdJ)ZJ?lu2l3CXjKK<-ndl(|XqvmiC7qz@GtRoOS*tpmNUbmiLFr;4^Ny zuVn6De|J>h6G~9x2S_Ir`k~V8#1!aF1v1WtTuCv!ri0rj-+z(w*)-UR0CJyOlsHoVf_^OpGM{CPY}zYLw~dHT z^XD1#_D{C=PwUl2KU8R?JDevp3gbbQ?ZsB`e+P2h7G$my89ip6l5lq-+BH_;`9!4^ z(7kTu{%wPuJwWE`(>Zqr4{qbE594?hNchIXB8 zf1hhToPvL+ft=s#-XC&wYuQ<-#sB;F_s=z+dgo7`_lp?+OVT_P*`H!zjZI$KJn&qq z()3@a%Kf_xJ6C|rOS>C(@3pVo5pCa;*OA`-$@XGlCl1K?+jaFTZZ@z`qg*c*cF- z^TT>pjX5g9>dn2hsO2f8d(wc34i$HyS4`5ISib7eeJc-$#mkBfy5@RH>6TP4DpcHq zUK;2z&fYX=lDTb*SIUwSWo92ucS`A;RBv*qxDP#pWbfxydwxCsJW|XFI+JtMgBYcD zQoX2P@c?>nQOWN_S2zrl!jKlSYn>Ss3tV5UZY1JuyPbZ2F-G|lyhNDqFP=f34L!zLwelJL^WXVSG(4L7akn?e6z+4X zUN7++dLtxzALgw5Wq7N6!l_S{>gNj{QF#7Kq{kTr?T0{*=ag4vOQxIEeXr8z!?=x8 zRvlE9p?wv6#0$tTft>d<_AguPp7BW8TcL!@;135B-VaQqxqIoJKlyXmSFqDn@-w$h zhT0jY4Oi?pjm(|u?h)lX@Kk&5;x*)U(zuiyF|*M0sEp#qy)18BqN9~AN%g{9#2d(s zpvQO_Q1@N4B8z<#n@70AD^yXoLcO?W++sr>j|^ZW!^#W zJ&@;C_ij~+mXDgQ1f9L{I^V35N)^;6LRfR%4K#7XR>WzQ@>f=T4xS;!5oN@oHhzjmU=Oe3Kd;Y>tN&LEKp)*Q;XsA$2 z@SIQ%ddz1_*EDT%vdK~rKQ&#dW07afKEKTce%a)X7;1Gb5i)nxV&y=>*Bc9*R^8 z?uZxj@7eIVGDqlf-R@jme{;l9cd>rYshcm-oma9ZvsYH+1E0^cas6e!6z%uNvYp!c zV_sF&^*_hL^QEe1D+<6~VIapdPw3q>6W+8HD({@xecErpFDU7~_TM;WNVRIh(&yTG zpv7g&6=TjaEQ7WW6e_T)UFR}b!}Zko=!4k+MrjNFg@aUkP!WrI{cGmMx1&*o3P@glFk(iq1wK<0^zlg=tH z^SWD{2fg+_S6u70hi+)=p*#vI0GYRx6Xo`83_SVO#|y8otDt|(pGRx>ce_;}zs2_g zSUa9oVTbnvxc*M1xmWLp=a01Ul;f-#^r}nqFfHG$T!nr)^V#p$>FwX=iqBf;S3@A@ zq0pig3x7CKUGRA~dB5fTm;r0NIb+9w*`& zw+=v_IAV6LYYx6Mkp7(6VUupNZ?whrpm)8?=eicK(-O#WseH<=-RW?im#n}3L$jEs zc%>BzS_7FU`loMtck8In|6HZsaj`Z&<^EY~uRR*-0_1%+w*lWp#^;%dcrm{Y=m0+N zhjV_H7R%PY{f~RaxP-?w3SBUJUZW%Q65nBGnjOx2hWn4hJnlZzu5&m)>IB*e7wB~Y zQg70xfUylHJo)VT)7tUWtH<$D`}gmEPlKO-^u>7c{5i(uP4t$Q?jkOA+`52nyOa`G zL5X1co*O@J=>t8+uhFw$+R7Dr3YES?u~+}V|ApuQes3VpFUQ;;r++--toB@b!DM=M zg&X+2fQ--dqc?OdCXQ;)$;sF6?%?|X8Bee62F)0fsi%m$d*)XsGrXAY=dduSGF)_G`@zx70o(lrN4+OH^3+;b>HDJ}J zKM!r~c*33kcsb&QPwr)AEs-C?V2>u`-^Yx>@ltZ4q_`L9!e@@_A_%{T|xE|?uRqWbW z`?KGV911&O(zpaX=#>7F_kD}!kYV5t2Qq&SDp0MIe+PcQBi7eV_(F4x+4q@8gC7oLyc|lACHjV;im>$g!x-=<0NIUar%UvIeeaYu@62;* zy@MDF{`Wxc|J@4inc48wQLMi!X4hlmz#k9f`pmPp$MT#x&S>kFP+SY;yWha;ve|RubHJYqPE}-dpcH$o-oKJHG%Gx$q@Y}Z$Kbgi^lWQW_u`eMC|CyMdP(v99+$9UCqMafF4>;7@u^qOT6=O{T8V~^1Gyd! z&neyG{)fG4z7C5uyN|L8{JqH?F_cMFU@_bgLN&y@a@w*PTG ztM;742Jklnx&Gp+46})!ZPenE{Z{oH#76Kp0om@XiCh0Hm-T?f{PIu78P}KUr>*!6 z{%w`~>^SIJk+?I*v~iL3BEjDRWcmygf|l$ zdr@#;7m)kk({}OST${A-ljBn!m))?l2gvn4J7$>6ncKIuIFt83Yx`%d-XHMq2#|R< zO~WbsPi6leewu&Yu@C&iK#pezze^9EPWr{-=N9|HKLF%9$~drg1>x%^)Bv&mb1r#2 z55mqNAmhm`+G*UHiU(lt>p4%z{X2?&9Ro5BC$34`Y2T(5UtRyu4K)n@gFM0gMpbkY zF=*%}ko(x94Tn>|?Chf5-<7{-dJ_B_K<;xtJ9_2tJYE>%dBp5}#;3r)F6oW1Exlot zeO8O_Gd>Oe86elg+I8&>yRvl>pL+jOj+e8ra}CJ#9{*-QOwR#l6ieT0JqP|(AlFfk zo_0mnZ0Mt%3wSo9F+x>B-lrdiy7@ z2fca-3pHH+gS;f$yN!n40GXF|_Z^$=YE?hP^*OWaoIBvZ1~N}vy%4$TZ7NUgIV<_T z@Llj<0h!O5WO~2xJHKVhsZu_9ueqL8@}g%d)DZW;e+lIJJ9laBiJot!S-f7k5B>`v zo6X$2^vE$)ZfWnWV87M+(&7R5&w$JmSr(5enl8JmmM7S6RnJj81pg6`>;3TPOJz1T zexa>fwx{ap|6Lk+{vN~5Qy~3$k;121)xMU`FY(|%k@S2gPo1}SXAdoZ%6Um|e9C_6 z)q^{jChI>Be~yO!1af{4PDt1C#viGKYQXw)oweg)ZU4Bxseb?SpCfP|R_*EkJ%-Pf z2j5|!-UI1R`^6PDxP7zO;(HzR#+e+Sf5FZNAlFfu+rQpk>)HL2*8`eWhw~HibqYA1 z8p!;avyx}njQ(*J&l4%ZPX*+8!gqD5Z>sr!y#In~`1$X@hg|Rc$>W(8ju!>8AD1up z?fvM`6488K_1qusT~fYb&l0hYNC#pDAoF#lsy`IGU-6C7=fbrN&DLHp`+gOF6f-^a zm=A1PY)hZ|mY3k~3UQxO&FX(2lC}GTJT4jGpCb@p@XWRFz}lJ%MB>jB7QAfsJ4Ts6 zECOWy`F4F|pZ6zT2ut@BGlTB{1Q;Hi^M4WAC!OduZi(qDzp-Zb6|;a?7|8Yh_{MP0 zG~M__krRa{<}EWt+c^UQ*%Xdgr{VdiwVjG^?up2ftVFx%BMN&^JKF%an&zgJyY0TD;$r z7yNucUZ)q#aq-&tLnkffPiym1e%L7hWPG~V9rJCyv%63S@awtX!#t<@{qH{)YwbMz zZ_`6Kee(J%j)t6oY}YnJ%CzHV9ntcOwe!yQ;Hd8RGsydxwewdB4zvMs{q64D{MFRD zp5jr+yYDhiyP!C5BoncoC=GrUAoF|!ry}bg+dfd1{Wi3u+xg38=YlfemjyEKj@mZ2 z)_dQB3ZH9c{#VWF|6MjYUzdZO@<7(NnHG_KSu;QFI{b5;%PYW6Wgy4XFXfm~FI#o7 z7%vsUuO#Vh9W<(qXNFEf9fz+c56bab75%Cv^>1P0vt2K*@2K@pzQ1d2TvvykmOyp< z3T#^$o#T;pzUuDw=DYP&%?PdssXD1I!Dg)ddG$StM>F? z_giaE*6V~sfme{ejtvQf6%mVY-wZ+uGK zusUD6p&?%&+wEQIWUEcDr;5b>MEzm*`H?$_9zgEL=OU3DUu9EL7 z_66S`$awkSKKhTi{FiZ_Fn_o#b9vft`N=-)T3yvOTC2ah#Bt-biJZDC)JB; zC&q$*2FQG{e$wxEXBE6D9NaV7ciwbaX_8E@tr!RXX-V&i%lOR$Gj0(4UQgqsdSPwF zc<@gF0S33?omTa$b5F#t?_cw;U6;+?hx@ahdT-UJwTp^=bd)BAKfKDyefDgW0yg(N^v@p zfME^958&?xay{7o*}M7tX3v#b!KW|Q{3TW?mQ>HsKuiXICy;)=YO>GvU6H23E^I>D zqK9IYqDl3_>WeAhuLLsh=D$$arAf6@%GTmD>kNJss}xSAC&X0nR{*(B_ot^V!LsrfrUU+;Zry?I_9PrZ5=Hb%Gj83jv#Tn}%feyMiKW{<`D z!t=rZ1<3VxyW-^D!Fg>FFXrDHTmb%JAm{zWure#`$1SuN*9*a41Y~}RYjHn+p8|YN z&isC>wd3+n>v5k_C&K#AVV7b&mIJwN$4xNa+LNZe#q;Mf@P7qz9ocvc9eYig|8bnjdYe$N1IV~8Q0Z7B zzZia=W1g2bgTEcf{XIO(fO3U1$7$<<>q~XiPW%RbB#`rPYv+NObbVh#@AK`OTVQ7! zko_BdY0iq)!5_cpE$5f5;QtO}-gWbRy|q)1rCR?`{U6W6mtMF3cAQ0Fpms^)Ievd0 z$9_iMSG0cK<@wXwzb`!xe_%ZJ0l7~bLb}e&oYLdJ=DErP@b4gyc|Mb0+`{in*BhVu z{HJ`s;1KK_mdEAQ)FQo%T`lg@*3SD8*f}cM+t;$$`0=Mbg}T7M-g9y^`gIZrFl@i} zdU=lqYlUm#4=cnf%;Rc*9mEL`V}LxjI(3OHpL11l?R`jcp4U4M);_0W?Ygx#Pgv_G z$5|au>z^+_hlVan4Q4-K?=;?M`F)4y!M_0He*0swO}1AKZvN`_F{%5y@7J;4>O2(F zt!HhV$$D{c{0WeGzUqn#cZQwf_1G1&-x;|I{tY14*_pFdcimgT=d8?s_v0G)*MZEh znQ{eO+&&>iy-&^8^g|s_{om)3$K@vciwE+2wsphQOyBf-shzLoymSlv$3XgXZ2r1b zJ?9SYFG>qgql*VZ5BNA=rQ+yno_L)mje8hK<3weRZC8)mj4ee4|1KTX7xW`F6X6Gu#*YMbu@4MtS3!+?bp^3 z%T;^!A~pCKfz0RS+zR%e`P*1+9dW!=Jv)&G{Io#!V@UmgT3hEVuy|ie?>dtEmkxGp zXjgT_u*A*gU`)9hLKV&Pgthk4!%ha;g}p-8Yppz9uDv#Ys79^z_jmRBi7p~pgS`GEwGWo`3h@lZq#xln8#tJR-q;gK-oN{c0v68W}v5K+1vGzD)9cSB6 z&&jdaXkJ1LdNP zP~|Ernx2DDPaKK(|y>32HRzYrIu=NOX7 zhMJH$PSqv3yd*nWkU6e0(jS)7Ps#@VL%Xb(ku;*EdX|&tAoy2uB#-@OE$4wU{ij?~ zsDIIa%H(l<%I#AoPnOv}(NaCvH+gb<)FYBdnJAZ2CTcvv5(!yu0sl^4t4Fhx$E)o{ z;XG@AJYSN-Alr=tznhAb!ywzB-T*m%tjY`Ps-n{<=yz7p^u7#3;y)SH(vSZ~y*>29 zpl=7+Ajwg#B2iack7y}+q*~7U1Cne5S-7aY$w4X_kQV|dBj2l$#`%wfup4gS?)Y&sa~H<4eCNbDyHj_9)X&SvE-jSWncd=|2kC zKI@&NdX}>txSVL&km`)g!sA?I+yN<$b4d za=xJvWR4^E1N0-T9_r~YuS+PGMZE$4{%-#07xg(_l!e!E~iX?G@ejvG#NxqMm>t5?@;z{MLBv~F0%CzqQK4sZ|OXFw2 zKk5y0WoN`5>{>5?P zd4w|0BlOP!d|9Ty_Nb?xrlj!+tN?io}`#Np^=E)kdu^AE07b z3l(i48z4vZQ_D@yZ5tB)MfFk9z;glpN~|>)=1cXw&NX0PvgdU!|x0Kgd&wj9dmJ{`s%RI_FUop>A7HSP; zo^R;4od3#$&wg-xDPvx>b1KJ&{UVS4&@Ss~m;Kf99Ti}o_0(fEk@c34Jfh5FyK*^Y z>JjB~%0%+y{>yeKlTTzj#7`}!zBax>Es@*T{E_QrSylh|e+%`<3tGPB{L?PShcfL` zCejdP;@_3CJ@RDP9)7c)`#sxdd{d^s*fAw;|&GMz!+Ux|Nc`H{s^y**^M$N8ho_GOvP5m_(CEA`1^e6w7O z4-jad^=wy0wnt<=+oR0!B~Nd=)F)D3mU(?mzbVs?YC_edEbo8Rqo3qaraj8^gEH$` zE|0%l&-mpyI0$G0=@08QeeytOxg`Wm1M=8ER0%Cyh+Sx%Yluw9nR$a|c=sE}py=?`U@M?e0q+)_K#Bhn6$3zF{1(UPCnNAhpMNA&=uj zSw_u&v_n}&nA3puETBx3%Pq;APu6Sxp+Ig=uCFdsqCJo@QUzSQRes& z;g)v&%5u$5_#w-h9{ylGk@b|>F3Tyip5^qHGI^BQKgwp~%?hFZq3J`G$6K?HdQDc< zKmK3RCr?Hy{9QSDoKK$9D6^lOH?~Ka`b5@qy)i#CJ}A?UEVEq)p|(g__Jew?r>xBb z^tE|}ERVY;vtBj(@&71iyX+tJC=;njnfQ0*T6~ZQq&|_=e<#a4nNR=8(@>~?X?(~Q z>rtWcAy~z`6%p!H3yG!L&)^cNot32t~O`-zf@0ItH&SoqYn6-e?DKs zdaf@`AAHtZLXD3&eoOy=hryx+k4T$Q26=Ky$~pv>#R+Td}2;By_6c^{uL+bu8YalJX9oU%P+Ee}JM z=bJLelW5>S=&@Wz(*CZTJRJkww9EA)@$4{MCMz{?4Ksn5K-_CAY|HM|1BZgC2Fmq9hS>T-rtpzry<&9 zzgW(8=qJl5v!3NdxtubQ^FTgj*0Y>4>sfATK3GpZOGqA3=CPdfMSGOVr%XPP^^`eY zl+E;nT4PC%lF#cR%G8%-J}>1U)EXxs$Aj}ieab5P7OOPWgcbP(PTDE6#PR)@`$X}Wbi4=NIsGE zvdr_4gHUTI6FFb(x2(^4_K$HQ%d}5qJ8YNbMAow%xm=Tl#!U8yrFxdrPs*|%w97`x zvxMXk$El6uEt@^c<6lkVyD)o;{kTb8o)j4gaXNtHveB1I)rxf?p zs7QdYDT00!fgY<}PgQwQ>&yr7YDkJP8Gbmav}HwtUc)H@bb|x_U_1Li^zhI4BuhQp zDYYM*oEf9kN~-r@vY=QPdTA5dGyQw8cVedg6^DsqExVunb!?1Mlf;C|JCjA41T_7# zhn|fp8k*1cKH+=1uDD~L?)~srF-pFqddA6u?YD=69GBKzjP*LSyrxXH2^n4dPK=T_ zsh;;_kq+&90;!jIOWFCA?(S4V_7vVf`M_aiAO|9W7d1i9FAwPPd-~JctXmotoI}_L zNBFySKCKv0uR<4*9&$He7GRHOJqoU=(O)bXx+VSgeW#S3C{Ki_&LRWk&OquN33_1g z-C`8u3SYa_@!<)@Ety^?kr8qWAjj!h_B?F{rFRp}@7TW^JK%&ue^gp0!EtB?J=#0A zDdodkUD}J)?ceNwk@|$fc2!z?!EtB`Jr4Ji`-8m(ZvRvC-}cSuxgOC9+fAg2c7pA5 zDO1j9xc*C;uvQ}KQVk-rs5q zekCCNyi=}--E+r%;z8o?LLD-D4{J8?D*`#bp##qiYjV&aF8wy@fwE)2QWNzmv=rGP z7Xoq~8fWibvPk;oV&L7Op2LRhRca*FGhI*SfSeP^{%s#vYgCVInMK&DdEcb0wpl5i zRL}GrU$QT`nFLGUt1FyTFHDGBkP8Co=Y{Vctawnbmaz1D?76|`?`v{hU0s}lB021ntEs}A;o?Y7aVd;ljZzt?Pxxy;s`s%fy|3{`yXku``ew`dmy<^R9XR16#Qa9=9dhj+8LL6e`s-S?fl7pTH8M- z_*V+Z^>8S%sEtp7b{60NQUd&vK+fNeR}PEMm2?qm@t6M|H1laW_{n&B+qG5ul^y=n z@{%0aWxy{BQhht=WJ|9ca1Tvx{U*8{TME;G08%M^H1 zd!GQ~Po+7ED&W@za{i|G9ywxt_*%@L`94+^{5n7z;G*V#Zg2a`J&W&etp;9gAoGEX zxHLd~H3V`U87ej|7&Y^Rw%^Km&{{tm!A@f! z&vgf{_)b4pW##|b{Mj7i;SA(?=|)I+p`d);pF9trD?VGoKUW~z-PFv`2O#s{oAWNmn&;;4eVXU% zHsH4h(q6jmO`c6!wb)|5ZVP@p$=<|mf#+)E=Kk>YgfE<_TEGzQF z1+Vz()*ts%wL8}T4r3RLM^|ZFHdZ@cKHs)!7WZ3g^PpZmt}nPHy5o-?lAjAY96Vgx zD+2Rp{dJBUFK)2o4&-@iP?v9NMfdF_)ME4ZFX`={e6G{0_qp~XFZ8P&2Acc3|A2DG z(%rTZ4@%u|^c{In;rpZ#>0#r9H}u*kce4*D9$or@noi@x)6LDTS)p&bg@l}Tu z{@z9+&1tmm`vvkkGQv&?$rmxz8QVzKyBmV!J_<<19MhvKA;p%s%JAo^nuCSr@X12ok;V5b zd6ViL2orswHw1djpLq+%PU_YCf)cm=Tv&&*e<;sTpGYr1T=+w86Oij@b;pi32j=N2 zw!Jugut@wqWolAA`$3`~_~U?_r&e8eUiK|>L>YK6-Oj9Kb|^oiJ`v))L;&QmK<=BH ze%R`Fp~))cM#uO$H81W_czuyb3u`F?!5;(Uc+MF<;KtEdA5nhh!ynyZ|1kSqs37pa z19Ckyj4gO+K|e3S-%sUrn@Vdgg25jNIW8q8RD4~n!36DkjPs+?97TWd2LL%P zyX|*gb)Q^B#N9pfZf(Ld1xrD-=i6t59EeJ}Z<=PZ7f)4+nDHW;mC=zA@_= zZQhwzRa#En_T>F240c8US^x6a9gE*~7$(%>uXp}Np^i~Y;C>L2rVFpH;e*$+2aAz%hlN_o%cwVj}p9fy~#Dx2Ko6RLNHy*wnO5`@)B` z&r?)dO)&}lpMc!o>pd?#uX(0@O4FjDDQDXpR`_|3N~W+k3hoV-2TgbGTv4!<_+I|G;LigxK3fzilxaz}2HJh^&$W;7 zTsa^1cutvArP=g#{`|e`FTam1gnx@9Kim2IwRL{BYl>R@<^9wf*K&L=LBDh$p~Fi&ZK`b03jcS-L&R7t95`d-T_$m@a32Qz9tesE}FkPwy6jNSJp%Iv-F ztHECbq@VLVQ(RBCG+yEL5zAFtN!@-j9#lOCu@-jLN%po6iJTo-;~Cb2`M#oeT;%xF zt0%{&UOj8=S*s`exf$blAISaISDD%3Q2Zffmg9_9?>8J)o}oSw-2KIGknaI`t{t<$ zcyjmriDKKZRCz+S99J48)ib>}EE4inAlL2C%lDS=@OKm8r5tzlYI9PlnpDs9ey}Z& zF93NyJ@W0aBR7Y36xAnPH~n{9DW6QQsn`nnJdpO%EIBYXW%~lcWwXcryN1(d=fU5> z-v;Ekv>06ETchhAN}E>W7j!5dt>j0&3bk~{HT_rh?8J7oa}LP3zcQ;*w9yS(}?qj9=E-L)$lVCey1dc0!H_8X6)K3`kWT}-Plxxj zwcpj^pte8If0gDW_JDs1NH}_-?n2+bkCk^*P7YZ$@3O-4iCSMw>;>^8kbaJxJipc0 zV*|C{ZQ(epG)M6V_{V^3*CQZi>-tk4fA5;}s?r?9KJbqM8J}ZHlxespBCW;eQTBs> z2+01YI^?;a+ynkDjrntA2f#lFWE{4+ezW1SCsl-6{N?w}!|?A2kn_HF^Mu!Dr+Iw! z=bq!}S2U3E(kt!T!`ZK2`Q&{}UVkTGCkDv)-RZmP`z@<_2(|dj&%56IV(tF-Z|hlm zz4CASDaXr2#K|Qf=vu{2j(lac_(ohcH)4nZ_)eDw!Oz3 zu=u;ASHO=2(ogU1j%O>CJ^sn-NIoz9)A1?WyM}(vi|TVWPCHM? z^YBm4yS)DN+RKW5s8CisfZPNLgzM;WQ{U=m>`y6?H6wpboAHpcI;o!Ny|@n{3+Qp) zH|0MSc_DLU@vdgTv2mv7K)sXdnSPhx5o85=9JlQgi*>w`;AMUD58PQ-e-9PAKh?>V@sMjsem3b`uK%Ky#l_?{rw+u;I-#^q zs%LtS{u9X6p~vyAbFj15JlnMvzZdcpdR3su@x1i9<@(bHPbzaVrMhXCCR%Y$X0M&# z_0nG`=k;&Uo#_!FGwvzg6>68-*5H`g_eq|E{~pMB2oDXbxUZ(IP>Xk%J%{us_%DFm z-#-*i6?MqDySR~ffwV`V|0>PN>g$!4u=5JY{POd#8KYVcclqSs6J{K#&D)6Au=5Vc z`Z0$GyxQG!hsAvM2K=``_CLesUXDdf-{(<_zutVNH&5{TT^PX=xqRzn-tl zg1}tbdZ+BH0~ zGEP=3UBBz?ALBtaYa>#@PDvoIyJlo)QOLLETjj>REN@(*qm?pA{WQJTA~pCWBt7T1 zTZ}{Z|E6r~FvS09;0dKvGQCD34fr-du7{qL#s&$|vtN*Ry7yk7Wek9>_dcEoG`v`A4J>*9PZY-Q?;8MZT|*3H;1N7(Cl} zK<@)x9;@p;?4nuz)Ej4L7OloBSx`_2$n|jT@s7-cCcA5SN#3Wkf?p8G{bAv`v^idT zzEoTb<-6a&>$2JXR$K710h!OL>@3zds1NhmIji$Ln$`N39R=S2>E{KP-YHvbe4(7X zcfN3d*Lk!1C^^8l19DuhG-!BX#GxMAeJPf!1|3CC@bduKzudQ`+-|qREf=hU-#w)K2<F!%d z*Mq!n_3Fvz!7>=A%0TY7O4nby{=CY;;(h3{;FkmPTo(|Lwba!o8?`u-?dkOs&1&;r z9tD+vjO)DpQ%#%H;=0B4PyzgkK<+Egn_TV~6nt3o)7tSwvznjQ_V3@;s|v@f0U5t% zE|)lV?@?u;cIfNP6E)GVI#U0#-dHd^-TE%t`AptdYJp!H$aonh!ndz;jQKwkFY>tP zjZemr8b5ZT9>%e;G@fbqHrgC|^{8U${zQH78vxmE?sJ(sWqi;I@oBzq>h)7z?+sz6 zkz{ZGt0tShwz+w%wNs`FqknxbFd0y)2~C6`<-_2Wr#sl~%o*R$_YnyU)x|HIme zX5bH&^yY60EF2v(RoIF3y=ooXWA?t1=HL$ka(}ovb?}V*X|E{u370uT4=B}>+B5w= zm^1jkK=xzRjfV@T19`p)^DBP# zS6dG;YV^G$d9v;^d!C^K_#Gv^zIAW5@7}w+$aHp5K%ETx&93|Pu6LfhRd*eP3+!|P za^9~_TvV=hz4ljp$|cHDrRhptfrBFe;N6yx^2iFPe?LE*VZ^|OHJ41O2M z&$CN!R~^#xnRf1BepL1JpFib1*cEnq0NL*E&i&_HzS&u*?VCSe&<*_VK=yA*fxGY9 zO-gNXztuaQvY&eO;Ew9H>3bSqi=HPO_X09Ln-5)FGA0M#PxSSk&-BiNypDQeJO%=p zU)n866>_PWhs8W$1b+aKalK?)R;TtoT($RS$H~g1Ajf6% z!L=)FZt^~u`S;5Eg6}WsP5nJzN1L@>we|j`*Ixkq3j}gp49^cuXt?c>#qT5NjWeEy z)cLa!L9i1HWW0!JZOYC+*!q+68Jhi%^U}XP5C673Ywy3v^Jne6>(!I*>+98%{Tzxw zSPA4gx#IY-FS=d1qLhyM^=dxHU1r~t8V3F^K<1yq0~_|fR6kCs-aoRlkMj<*_bUzu ze>M;SXsBJZ{L{JF4=D3z-LBQPW0cwF(_!HM2;}#g64m{<^{Jb1uE{BCo%(uoEu%Sz=yJkDRTm2%8xH-YK0onVrkW zfj=I|{bByX%p00z=w|Ubf4zRPJ#}~-#rLo?0myT0>+Bv4cc#98dAI)hU0z3e{e(N1 zMg8YN`TAiJ8u|gq{k{Lx+jfC>_bVG4#OYCUq8|IL6D zLhaC(KMziWe-S{gqX$_gEDSB~4nM7*cX>Tbhn*Qf#@VmREq|ptKd<`o$!D1lu*}{!ye+YbdNwH7-Ue-pl`vr5rUj$^Hf9g9sjoqZZ7Vq=T1%IAo zZ~ajF>8}DWT73Rf?|91B4?n}sd?5F+Xh%c!&{CE^N6>2z&1&Ph00j$y%#&Uj>kVvw ziRbdKCqAu>GsclRFiv6##$##n0W;Juu}WDGaYo^Lf^%aeRj8`_b2Zy!dgaA3*jWK& zo^W4V^H#@!7c5>s{0jbZAoE$|y5DPFa&0A4GhfgA$?IVi`n6gbmmck6&w2;7{jd4F zV=esK1>`z9|FUpI%}w1!-Fm6-HLiV9DVA*B8;Et_Zv(Rbjfd{qw|@I`i}wrGgTF!2 zi+|KMePpTFPd+cn``AX<*#u->I##26v$K_NSj?Y#^OC%;Y=)iRf%Iqg^xtCV|@X7Zl*dCUX?z{_kpr-$PEyw3>G;|io^KPFbJF-^wtt7@Z zI%Imq{&}}fI<;nZ|LGTX&*>25N+9M7=)dZ>jW~*a#Q+)iZpHHs zU-NdUwvISns-B%V2L5p%s z=eluI9NFV>!ry(L(mkm?(Meo|UKZ%_{8Bb-#$RL8cnjVqlD{W)4SJcO$NW+~$MQ65 zyS-KTd3c+o_6!}wb?6zO$LsLMl~$dJ-10=K3qbyOMD+$wAuaLJK(e#0!G8hdx*bt}<3>?puCVleh6mt3268;-RV_LsZSTk0 z`=DI8~2&rUo6|2dHT>$dd4m9>N2p=W-*@)Z1MK>D-l+^n`G<7)rcTo+rLKmTbx zd4G6?aeNJAe7vP-9P#Mi+o*`8g|l1_Nt`*Er0Xk zZl8Q!lIJfi>|`WjU@rX8%(!4f3X9ic>A>gjJaQf7bS!4448H%#*Bxk{(qxKY3r#t0(6{y?Szd+G6~30lEKm3UA-9)V>-P<0TvT*@0Z2 z*Ykx;33NXu)QL9V|MdDPk7o|p$q57)uH5Mz>%aGV?RuK$XVw1K^L;M8543zn|JD9EiGtu42Xedz1bQ|6{nBn>>HDdLz%K@59FAGD%x=%^UE24H zx!A5_57fUpC4QNy~tAFR|GO%nod3& zGrs0>{BF7m+IQ=Xb0hdFCd&I=XHA6Qmos#NBbrjXW7eK~~ zV_2r^ZPP4K#vRJie&)rUO6{b2hE}3F_zIA5SSs`)gjbNuSkohd4;?FrFQ(sfYHOqV=!gZV3 z`%U%Qlh1WcV5d2daW)DvZg?TA?$9Ihxellp0BDY}9`2FSQyGxWf`%^~-c#(nb!7W(;$+4pa| zfj>gh%h~U@`&Db*Q7Rv(SoF%2GfI)9_QL9k?%)Rj*}qe(hZTsP-c7r&Q81~Vp|0ow zejt$NkV;1@ba%=WZ}D8<27VtP<7M0JVj_iooMP$wsqWzS269|dpM5-LU6I=sf49X0 z{9ZuLL#@$wCoC#?(&GN$3BDJQ<8o_84`q5t2f=fewd+qlhj_z|ACTiY?fWMyj_=#1 zjVH%TosMF{2Yg@2&&&sBoSHq7-31Xa=4&*| zXw!YpvUXpQ_vwGz&%WreKag>jFYK?rL)N=mJWuHLQy!OouoD2}`Ke;APSUMus0;iK|?eZS8v$CZMf|x z&pVn`!`yU7WE2WUOZEoVIDP5&IW89GPjCNZdwTWc@f?eW=16|-+|lc;r*E7!Ji6bKC5@O_mem7kCgR$PThQw?!4LWoPQ5Ke;1eb ze2O{eUiLjde=vV;Z36WEKlZ*lK8mF4dT@u}79fNGAy{yyi(r8u!JQ30i@VF<&LY8C z+}$-m@Zjziba8?%w(y12IZaaY>yO@nXP?dczWl+-t$S|Ws#{gJs(Yq;#sj$@jVt(T zg4q`uim$&$bgJ%6yZ2;_0sl83&jrN;m&8gRd`JKN4)r`S7W{FFo%h8Kk86zOd(0gF ze9Y1PT^)Bv=Zjf8bYEW&X6@8=PC`X9fZX5xKNl`qaX^6K=NA6pPX{v3KR>n6r^nLT z`gMRhev`qU2ITyFl{;W$p`;;(`{oqzrvjO;%XdyWGt;(w|C;^J(Qz=`{!M=>p@*dE77ktK(2>=)>3b3-MeNOmsQ}e1~OllJ^rwr@9jJKI6%$O|Bqi6 ztNn8{E{@u*M~4ppIj;{lb-$nD-V@E}`@0*!-wWiv(&}XD85{m6BA#{qG&tU*D|Vj; zYy^KBkn5qvoCmv4JlSn{&e{b2Rv^c(^S#`P=>Q;F@UXb+J3po6uNHg8r>KhLwAc00fi1aka_r8@M%YfM%ldG_x= z3jlv7kk^fuj<|S~pK|x7$8#6_>;`h&vs^4YsLqO~|7+GQx-W+%^g3=I3ibn;2Zycc zTsCw6Z{w%hnVp~ibY4>LGnj3s+P@$aoCY$#oIiT&(7B0w4Zr7c82nQ}&a)OD|7^Pc zFMi+D{{HR}@Q(tyPyg1uZ=unykM!@csO!&c|I~3f20zDvTz`kh1vNW%ZSxPmk5j#l zI{`l@mHu6s{C@LOJuZ>wJb`ZL>&Ve@IE#v|C~>LL=5S5F)lapspSPcJ)9(Fs=fJ-V z?f9P|&MxO^<0RJM8^SWE^c(2knj(qQpQP+dn z@k96j_PDEg=^83}4CFXWDC#!EyIlcc^t-Fq!G8qg{T}a|&r)Ap-dexU$8ye*MGs_-vaVHIMz}%Vf^i%BHezA zZs_BF7X=T2dR+EeHhJ7?Ww`$Cf&T!=b?Y^4UdD`-+8M_4KKOqqcGp}jf3}-YML(aZ zdDrZ`{-@W2qy8eR-7}0^1`H6#DP5H!1IFd}OB5dKwzXu^>vr$wdk(wwFyOk)9DnTm zB>mfn_4&&U9<=4E-E*HIuuBI!=9d9!8#dhCF0+1L!<{oa49kcYuyckT^L&HAV=J;I z{Y%@LB2H_MGFR=M`+Nzzw5q@5GgrT998G*U^fr3prC06VH}eX1Z-G4bS@8SLD|X*^dky{@AkSwdJFiL@YXX1I^uK?e_!I3*gSfDreVtNV^x5>6{+wy1 z@Z%8rJ&$*=dk^G&+#N$Yj%eidK;w0>Yj`_LDbx2EP%W*+2Na}M+UeRSMy;fq@VsH@ z=N&Gz2ty%0!Y(H4IA1Bp3h*c|~mS;{Z7i-*uP~IR4FZ!{2i=+dp;O$U zF3Chv@KXSJPOe|!z+CS(As9dV^K~-tlLI+Fw=Lh4JDW2;pSJw>_diG1gIPOuy_>aD z*PmHCNB#Yuos6)Y_m)7Q<)0o07dj3@VLG3w=X_H{*=q7dhak5D;L=v1wPFyJ${c|)fX6+C*OzYU9 z2nvblF4cbcxdPrdlmnQ< z;r(c`2d02^h}9$8K>vRJ?$(@EPivmarK0&n@rgRz-w-&(+0!&-cVwSRljL1g28tWRS}OEfQ^lvPJ%Lr3_>};9Hy&J_u=k$fWc-?P(s zGz7AoNVO`nf7BDna}g*3GJb3q<3~R0qf8!UBcxxV%40d}qfDMEn=Lo2Pq0RbtWQO< zjLN^O7ZK}M+oRfhfX{hFnReeBAGMv7>4(U2j;C5q{rAe91sM@hw})PrLDOaEY0Z9f z-m#qRq+YjI>Z6`^MDPQL3RzNHB4tra%HGgZUOGsYhrVCa682B&Z^uC>hu#G;^ZcoS zQZK4Y^y@FtR#~DaWQz}YeW5Qeac*~sp}$jP`TB2eQ}Gon7Un(JSr{*G5vI128NYJS zBThE%2aKBw^qg;$8E>Wkq3@%U{#2Bu-~OkbC6GfuACM)~YmmufyQyb8sb{&0)Dw;L zYW+4Y}0_zC*2ggH^12OOP@hJj6{T71Eeil^ZJdoKQb$r+!>e&v;te3J8 zT9kj}abD#c%Z+4(Kex4z%#sqBxAgqOe1d#rL!PoQ zPjEhSUQ*^bvz+bW{HER${wed^Oqt_Dd&ZA?7sa0KqMrUKb3RgL{d!zbAIlkM71#o$a9BG9>;@vwZD|fC#rmw zlTTzj$XAhe-z!&nYQ5C!DCA$9zbF^YP@Z3+4d)O`4k-uX+`zmbs)3JruICfZdtd0? zfs}bY$?Hp=AJ`uD7d(Am=XhA~kK<3i9#<0JmwF>4ov89yuCGHBcnkT5t3(^~57xC^ z{!!ak8urWsUW!~)k=1rlwkZEt&i$NmRC>to-+Na<+Rt!g|wioBJ2BJxyqx={!-?+ zQs($kX1gh?^PBD0c>+uz+ev#}R`hx~h?I%6C$gMqRIch(o}DaY3GIxKc0`rOay>pM zP~*+@M0@fn>v4rW%T=U5BK0nUB@&sB(GJ0U%XU=&AF>VCb^7`*0X^pd^9N-j{nI;T z>RFEaju!SiKkBEk?1>s`niT!GYc-=WNTLYe-FvKEWJAFJhzKg&7Jv{UP4Ir-Gvm9s$b z4~e=Ris_#$)xRq1@q&S(xAFQIaSDB3r6e*=TyOBJ@BbJlU1q&yU=P{m6;TfTo}oql z0~QAA{e&z@77MS(spq+ivOfMWU^}R%%=(Dby9$;_WPL_@mJ?}BnaFbb*UJSp5?M~9 zmNJp$tdFufA6QO1UjI>6^EJnrdUgGAzEV$A{ji)!J(1;Vd));Y5}8lQ_f+(>r``x7 z*7|KdtNl~$X=hZ<`(?~4YJO7ZC*#L@)%dI9>4N^!KlPN=`dF?a{Sm2W{8&zzde*PX zQA{IwovA{QFaxwhMGVZAg`Yx2l^^{Z^#_ya*E9TfqKf! zQWS3T56g+V9tD({ zPciQTYYIu=cve#6{E*o{%Jl0Ay{yIZZQih4MH0VPP9Bi$_ktbe!iub(Kh^lMy|m~3 zI=Bga&w%`kdLz{N_(SDU&vMG{f`3UYrpV+I$)-$XIrkgNM2r`|zZ8h?C2@bW;l2g$ zFH^Sg{xSDSe2#6yeN`Lh2hXKmLVDzNlYm?R$o{!N=6G?Ps`H8Yo#VjIi`Z|Y@uQye zShnih=jhaPK2T1Ec9BoN)Kk{=_=9?`3tcbtzry|?PcMa@yFBM7WlEvKyO!RLJ7xq>pU8yHv0^iLjT z@+i|EW%{Me{t&4*l3AasrybW9WwwVh?J29sdWqB<$*hlh%Br2JSKGyS(2lZhhd-z% zQqR2ODr5=s31!wtzm$o3eXysjqOASf|J1WYmrd3~KGCio768ffME#t9?uyKL%KkF{ z*^LkESTEds1L!%gs9?RUPer{x*wc>XMo1n}<*{7%hXNy>QMulJRw(#~MB2HaoHFA` znenGJ%ZaKVb-s~DWIaT?as8`D=tMO+!{Sp~3%A7}(+1~HP zMQsoL>E(hY5?M|^lvO|M2lWwa36(^|5|w9GR(U+X6-WKtcPMi`t1{13)bn#~u6N4x zM`SN36Issd6@E@dxiH#C9^*kh&wrGehsk5RD3eE-sJ93HD66Qq1AkD@a>_)O6I}%V zl1LuQ**?w_mb0C-R_!QrzEkFWryXVLSx!{TDRZ5$9c-T}ldqy$KlLnUJ-UoPbe>Q( zQr7hfUoEG#T27fr-uK!ggwBlc2kT+Hcpbq!pvqi_j3;GQN;~Qe=Q9li{s6itGTWuL zlQR9G7Crw^uf~PtMyS_=KgeS_Wg^Ro>^Jp9>M0Y|a>_ai`Iix2y)LKxjX!x1>gv|i zn#P(o^#9m+nkb$%zBPe0p*2wztCLSuYhs@$)+FWW*qYRu%$mH4HATg4i&GS`ru?Qz zRmGb6n^e*#kyQ(|6cHa%@`*b1|Mz?ny@cNHn(PI^>TRuSZBROPRLK6r{Hyz0{d}TX zn^>ENdWrB5lus1B{ss}Bf1>&1!l=h5%J9&NzCJ#c$j8mvrgEHU*0vEV3oX)X>#Wxn zQ$Ar91=Yj{#sCh?Q`|c+)iX`p8xXL(&NR7VJ+<_@UpUC6=}* zd*HK(e{n&_5^)dNJvVFCAM2CVJBe8E!+sHcOHb{bpiV3OxnQ1pu!{rac$Dk8 zy1=9d&wu#+h8$;EeTe30|IFGs>W}kDwlj<1dm{LL6UHs~f`HjmQx6s=(v^=o^6Xj7 zJN!VnOb`hXN4~F+>KjkCyRFIjNZ5Q*24uZ)Rx3-zSAMbyA`$G)V1l!rY5BwAA74nvWMwu;cq8*^j4jAI-SYCYhK!Bx}yvSI=lE!`n3+FA~F!?|Y?P zz=D#w({8bdmup?$cRF!KOCH{?=6I0=c6=W#<1`}9h3n}nXB6Yl+&)#K*BLEFc)Mid zMN-(Q@AH0|KA`^iS0A+HFFWKcU_GNn4{zr*UL=FvA`C3!GVbl{3g!DG6{5qOeODiy z*4~9*fPue>thbhyW)oL;7y>`mKu5<8$L)x|Q zc7gpw8t~r$nK#zINa%7oc4y)Id)u+Y)*aA}MX>8D(t`g|u`79V-PLPpDvKP0OJ4aU z;DB~CyxrQqg70Ho*domw<1zVbXfntm=g{P2ZZiVX1M3*0avZAN8SGuXo~uZ8bmH(# zNw#SI(1(Gosc?l{49Im`$eLp4mN^f#Qt4TWen1PJmHp|V;_I~9;q5}d zN1qL{Cy@K+#FihfeX4y-v#v}u_RYL?TFvlwq2Dj?fSg;gTQ|@xXyCc^T5!Mj2P?gp zq4|Wj3;mvccF4JaoS!MPPaHOSa#azSZqWUTYZhqv!rO&@u95?CP9W#!x;Z1ur0jI= zhxhmJ>H6#EZ)V3Y{4)CbeI>JY?7!?zdDH%wXQf?Xkq7Z84CK6?o4t0?Q;T|vh4G7D zpON8$-TQ>|g3mZ}9i1t-r_}Q8=kdJaC5`7QNjLvqHZ`94;ja*o`(Iy=2WLtok1k}f z{d?mJfL{>EcBaUC#C2z*KYsfANz9I)x^B(dIXYh)wR5zc%nM;*4}D&wIO30qVc|R* zcWg?L^7p+A-%C>hb|rya@562v-|(b#EyMRI{-@*VXk1jgQs`G1AoEhbW%b4$pM1se zcR{_tFAZegtufKH$ekA{4B!7}HZG2?+n+Vh%AsG(|C}%H+fJ|8w_rWPyi^``6@lFU zejl_q+q!Ij>Ul}cFW%r+0P-BtF6mz1o2C6DeV(X!I<&6PG8S)yi}$@~ijnfp+ha<~gqk?6@A5=jgIyXhm1y zow-}o8L^LQy#A83BBBoXen93CTe7USq^mw?!3XoYC(m-i?mc&P!T$xweR_4K3k8E> z82@f`J@6YVb`^33c3jiwwBhd()(5{4kmJzveaFK)J~c6%pAEoosQCMExzZ7Dr{l;k z|M$ME&sdNMQy|d7`!rJaG`)`0b!&FLJ9=Hk`#Z9oc?H*hH*|#SA=fg`L+jrr*Y_jU zt_Ap=fn0xSRy|C*w*OuI{eR4ll9ofX1iuxK>%Ck#kEJm_UDx+9mP?xX_ZzD5w8Bpt zAp7@V<*W=|^B)<$zxY@1TLamTZBwmnulYn5ve^DyZg%_}&GV{VTePneko_w@rC>(M!C$r;XV^ z?QO9P$F<$ihe2>F(F^iwAm``WA#D!S8RRRLW~sGgd9M@Nrto%iTZ-P0R{^;m(wA?x zzryy6VrBidhkiYLP~-V1j3#P|KH#qeGM{Z9_UD;~`yOljJcsuWC9S6D3;qfq`#-bD zw*F7vMi*{J0^Mwt4rx3uhS5U5FWV3N`9Q|SefGEqxs%S<9u(c%`1gnVwJOkufvtw< z4|$$qcdhOC5z(to)?Cs&F5RqOkjDESl2%C!0Dmr!?JQO2bL+X;PioipJB=v4;jqU0 z3SqR+_siJ8pQPB0wZ887Zlb>yw8`7IM#du=?_)?>MKKWkK|sc{L4l~lR;4+u4H^3A zSjt2PH4o?|lr_C?@_x0nD<%e`o-shqmoa-sJD0oVDU5z^dIB9QsIYxZ-W@96jW?0;u`9QYHIxa_R_`dIqkZyKJ^xKFwLju92gr4lx$wgli(dSqU%#_l(%i&k@Mi&;&(?G(J2y}5 z0R8;Q{4Z(FVhZ?E6+4f2IT!5Bzv74Qm#cA^20t@_Y|pkV(c?aevCeSZr-MHO$oY9> z{>W4nrX7uR=Lt2x{EmLjR^rn2=%{OhUu}% z`sHEmN55~w{YF-wMJ$1zr9kfQOVfB2sX4ZSkj4M=?@#cYDEn*vb0|d3q#gmOkHU2(U8t5eyHGPg$=ks?#6YobdXHtY9ky&~B8iXD*8D0ZhlrwhD)alJNv-q$OL3z~Z0I{^HnK(5bX2eK6X zkk_V_ocZ!-^^O;{bkIvEA$CIE1!TT{)!<6&Usl!=mmXct*stmujpERqketF`7UXWzrTMk{2Tys+}pQ| z_Hx|9^M?D%KJfPg*}pFJQ&k-}`!&uJk!KxoAC}#56^GETARzNn#uztj*!7FCa2PGXkd8%)6uw`fS=QfzxcHa$4nco zk&wmq^Xw$}r+}Q-eQVF{KB(M9xuC(a=r=Yd?e9!FQWP4DwmvxWWe z_jb(X)e%95aJT#KY+}Woi==ExV2sk;g_&t>vi{c+5Il)W$^COMFPR^7s3O_rc7z)6w~&?nh?*@th&M<0f9AU$24OS1v4R zvh7g~p?{9f^(<+wruQ*N`={n5v;9-!@+bP05DMg0T=lk-iD>qOGs#YfnE0&;vCei%2Y`R2O%_uyGBX>O*+56waCA=+Q~ zD>f7yr}K|5HjGp5h8`EjOVVA%XV`rKa-OY^UUF02sF{T<4%S#MWygPa*uwS!IqutI zb-&#Eltqt=dS8RjQN)BD<2G_uoG9D6H`3b~T{aN^JBg^^^SKZDtK2xK(8rta^|&~i zmryOW{Pxa^M`un%qspAkA9gYX&yq=Nd(zQ2JzUced z|MYnNto}J6j%k5fBxqd=)RtJ)1jaWkn?PR-9M{dXnR$g>-}lQ zxe*7nsjvux;HDxy_*sFRFRneZ)g05Zp&0-2K;z&Efm)aFc7Y8=2Jo{0IZj^JJde-4 zxJUR+?6lJJ+D0vRc)QT|?Yn@V8OU}9MSoJEymmla`@VS7dj}V3xx(97%8QKPy8_wH zf_su|n~|)({(WecOLOz*37%`Dor}l>KW;$giI4Y3)M%HXx4v%KZ#388^NZQ_fabuR z`RBkKz2Bqyb4NjWAkUFCz4CniknWz=cFCO#4X5qb%Akc3s)=mi7Y1^i#>bexxP2!- z;pCFz!JV9eTCwnUp}%kC0e%4>$6-yEJw;cKiYZRTSp2d|;VpLGd&&-eejxKi*ZqmF zAAbIa7UJIUx4mzcYVP6vh5oKz4)F5<+0Ge7qg2f6-B{H1dYj>9ymfY;KjZ{IFOd6# zXOkqJ(>$XHqtAVFfu9@5yt_30I-eNVUKl>tV|KnUUb366!V`Y-0NKCeNe<7>v96(z zyvUP3)$@|sxTx1hX6-oNWt_5zf{0@wW&G029$8~g^pF3VJW&MgE2^|}W#{zSLZXLg zPr7~@9Bx5n4+#lbHNjYqVZJzo_S|lHivHa{U!>f4Xi&oA>(osn=B+_+CKnWACQkS@Hby z3EiJMKLz-ufZRVCKX1Hw^$LF>10Q+TAG(40Vtzkz)Q<6jL(}u~XZiC+MU{cf2e+qm zX@7UtJI&}h=nCLh0&+feZM6I2w$Jm0?2r9(&=tY=QS7=`4UVxR<-{NUp6WjxPxZcr z*}RMHW7tEqswij+WIu}eKU$P-z+wIS!s@xl7yN2KuJ>~n(w!=M^{)Q;Lne3%gV5i_ zHQP?+Ice@Js>4qkAkPK0Z$$IV{yd6UU-Ii0!p>;U;r&^PiyGiJ2Qt5m>w4n7|N7hd z=N+jd*cA~q!LJ46{Ol4l)2Nfr_G!UBm1j0`4${=`B{@_N_4XP5H%>7T!|T-v#by5Khfa@@=OzA9*5(00T7!u7!S19D#( zkgdeKxRv-kp8fi(5B@Jej_>R=XKuI@UTe4?H2}Xcko%)YK()^05{@_AR~mxf2*~|v z_{@aXeNVrAUrOCq%#I(b#jG)(uNh|;nqCi%`unH*=V&_}wNvBS0u{9cGA~WMQGeL6 z;79s=;e3$eVE#U|>aP|2Sbw$+gn)#J4oxDV4f@D!yFHLPZ#s7G1y} z1mr%}?aHEx?q?rp?!_uKYCmAD-S-E(fLH z=A_?eNFJe`1w?o72LQQ_>hIgO;$ECfn(x;1LmyY$swInHmtXV%zdw-eOq8vk81Ao$ z5l0f%n0j@$re3G^1iv4U^QF$29ljfL^Lzfs?B1u-3;f6X^{>&JM9 zPCNWLm%85jz)xQw_wfOnyG8=d8Wp5GWb(~oG+XHO7&!AN8T59JYS>Qza1COcWG$;eTS;Q=_r^1RFsA&~3kM2u;HSvK4gM&CD`1^(|qu7~$qVo%xM z{itU2+?m;SCcy|u$SY>U&jKLl%g9E*^xNOKfRH@uv4m02X|clFb?hjXLGG#8b#YJ7qe$>B;dgKO6Q`o*G=AStwzIuh4!cgUV_tf3 zpF1C(7UP`uloRkP&TS`Fz^)_gIInm0s<1zK-8>@8z0WP@-aDu9d)i^< zer?1`*j0latIZKo_;vE0*EI2V_b099d5zz%57WzK<1YWgI8D2I(~~;@j>c@0|YE|2)lSnJN>Vue_bJGUGeG6^=C6vpVV51x3kq3hhP^3WIHRrjy5mL zhvcI7logLkygjW|4sR!Fm|nMRzclv{hv6qK+R6PWDE)8qPj=5L!gyQHY4Q(gWwH2* zBe093*e&SR_tTfI&Z7Pp+m>c;&uLh|($H2_9EF_)cFgk|e!n&I*R40T@$20t=l|=x z-S=&d!R{g3i>5>=Sg73Ud7-R$sFFe%5jDF9GTA*9QSnN*&su4Z1kB+!o){ zcF$#<0RJM8^Q>W;Sy@&WC@FaVlle+E$6cHR{{oQuvaj|R%@X|v!eM`XdkXyXK#u#Y zF^Pt~e>T{s6K)Yg?Co zezExr!{@o~fPWvz@%^~D?}~m6JPp5haTol1K#qH_ql;Dq+;bDMU6E(qq8qZ=|G;@y z_4fz`Ux3_KCg&YAqGIav+OV+CNp9MGPVyN1&p=*xIGyc&Y*4<3hR-`a0sk)`*ZZ8B zsd^3U`PA@vr>Ee*1#(_z>UunTPm7-z*TUDMQov2S=Y*eu{|3nUTPXO`^u$kM>hp~A zPYy&X@f`dRAmh?3WJm9TStl9JYe)0M3;21hv~yejdX-DRzocLPsd?!o_^%YZWDjib zy#oI|&q14w%g@@!{zN=J0XcqiOE2D3<6V&9_`L)FBar#UW5(kI$&Y8!^NTtT@4^27 zttUq-<#77)c1G#UGub2MSaQD#n;l??0BYMX`yXPMg zfS(G;^V{bB&JW)o;Qp}7?s?{f;HOmV7Edm@?aQ1qhVP$91bzx2+xc79x`ElUbkV=Z zsm9X@{KP=&A9x)}{cEmahW8a6jb{@0NeX0Ko_f^G->ca%!+q1NKU9lZZxP8*kX-S% z)IUT21tI*NW8^u1s{L~`E@tgGAGrR~paE%t%)2pq?7r5n@g2jwYt|q4ed#ZYaE70B zKuZrNpP?K2{B%JNms9Or7^n})xqksJKt zK*qE3f_@zqpRO#7KF9L}KM#=YJX@ygpkHsdF#P_!*?fj-^#zz01x0|IpKofUy|*Fu zK7Ab6Z)xZ(@_}C%$o_rmy(VA(oh1$LpXCR?5Rl{EsOsLbH5Q4i9-eaG`v93o#$>px{W9=`;eC|y;8z4P z&#$RAC}YjWllA-h>b~L)egz=gIp*>Lk9;+b{AzR1_n_9$^&L0QI zpM2czIgOg&*8{RWFGr2NRX%@BF{FBv+kXWe)^bGfS5DLdzc!HVY(FV*(tvZDe)zf= z)zYh|gMzw1?$dK;J{}mO$qDxEt$ak5Ru2`e*+hB|q?+0NKCT&*xS-)!?F@Kh<`c?Vq}Co5D{E zAm>?OKU`lqXNbl13YkuIKG&$5G#e=pr^JX11~VOZ!t{{0C@`^W1v+1ym3 zGse4%GVTegY#tMHNoB$JQLFb0%*KW5S^D!3UE!w(knM@OrNAEB)dGgsjorZS4rIMC zU%I$P>-FtfQ4YvWA=lh)N6YZ!=h~ag3Z}0~Ic`gw5I`� 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 literal 0 HcmV?d00001 diff --git a/text_analysis/tools/__pycache__/db_pool.cpython-38.pyc b/text_analysis/tools/__pycache__/db_pool.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7209ac5ed6e234a4d03b59f8d7f306ea14730d3b GIT binary patch literal 2900 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 SFpisJR?;_cN7C|5Pya8qt=F6Y literal 0 HcmV?d00001 diff --git a/text_analysis/tools/__pycache__/process.cpython-36.pyc b/text_analysis/tools/__pycache__/process.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..543ccd3b30fbacbb487d0d12aab22b9bd48bcc02 GIT binary patch literal 1584 zcmZ`(&2Jnv6t`z*XJ$W=YJlAJt z>R)gFLf;G!`W>AaF4*sa$lpLwL@`ICoH4-+4V_`dYL`_fc!KjQ;CT~7{3&W80#}+;0db3$ElE_~w<0>CyQiyfM8Hf|tQqfNu8st+57 z$XIt!`Zh-9p)=HhXZ9F&VPl)anF%sB>~jv*p03$OsdE>lE6N?t(w5Cvqw{v28@6b> z%)957c_C_E*<1$SMtkmEkUP*-z;b6xK*^9sBuJQwfTW02BbvmicGWm%+KVm0(6&=P zy~0vSsz3vf?a`7_}7y!pa1#;O^?OtKzQH@->9llaM6*j<|0m&aKI+ekSQ&1fUYSK_1R9; zAL;sTCXz^n?4YmRINi;lVsXNBRdU91UA5_CO(%UJeQmT_qoni{U< zaPg+L{n|X_mm8oEcCqU;v4aD!T26qQV4amZ_yL~99&W+Yc8qU4VaV*hs+~;giX6k< z^GMy(K8-~RmsR`GjSQZ-1W>zh8(D;UI{!J?nmt%q`?j^$>>nk($9N7^H8AFCo$WXwnOY`EiGr%YY?P^8%ahB&fYQYAeTY4@Csgr8kSYOZ0iTM({%m; DD)Fsy literal 0 HcmV?d00001 diff --git a/text_analysis/tools/__pycache__/to_kafka.cpython-36.pyc b/text_analysis/tools/__pycache__/to_kafka.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ffee3e3e29543333906942a9f3c70a130c866867 GIT binary patch literal 1533 zcmZux&u`pB6rLG-Z0}~X%C-~|36-EqAWLbKZluyi2o*Jj11PCTq!w$D<#=W{-u17{ zj6*i;a#`ROZXCE%2`&gE{tEttxuQhyFZ9G4Z&I}aTW@Ck&9mpd?|sjki;K@fEm6f~K~8Za-gCR>2H#TQv?M8uG{W(d6S9`YCefiuyLkM+VQQGXOYOcS0fc(m0K z%V1ut;m4w2Rm_D?bbI&9oU_M~P>D*4TsL?7eaY4Sxa6_P#9R*864*m9c?`q&E<;no z@YGUhh$oO6v(CuWR%Bu+Yhp8-(K9lGTqk&FGiQb|dV=yT8!0+!iV~wK#pv{=*;UTa zogw2<`?_=A&kal9^)-Epa`F_`ke#=q-6)UJ@hSfZa%u5gR)U9-jFaS)R;qvd9>5;Y zkK&wNkYLkR>>R%NBs zt=jpLC`}K>ic4)LdB4z&M<+2aYqlCnL@_^z;*oCl3z0=ClR=w^4Y$b>Zey_m=qrV` z0jLZ802T^lHN=d}FccV1$pj4vvu9BFlhui}jlNi(+7mK_l27oAOew5wBgUiEC-aig zom2AF^t5y5z3zJV?t1s$`sT*g{f+xw9|xU-qEHeTEJMk~F&FYVUh}Ci5ol*lr>3$@ z6QymFji&vyl83${Zh%YB6kJxR+6E@YYxO%dw=y6qhW9H4;;6};56j>pS}?o`CYvxI zyo8%@w{VTe1~QikfP&RDd4*D| z_VzU`MUpG+%)hMZago6^T4?VoDD7rk%4qN(=HG>H-vX27PlA>W z?+&)HXEm{hh1u0!7-mtDhoRpV#w&2kajoZh+@@s0GB};1rcS}@mp<$BWUk^6rhs)q xwZ!WJzc?k2G9HF6X~VRjFapuu`x*QjQ~rUWN*Y;txMhLCy+pi@=X$q1@-L{4lA8bk literal 0 HcmV?d00001 diff --git a/text_analysis/tools/__pycache__/to_kafka.cpython-38.pyc b/text_analysis/tools/__pycache__/to_kafka.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ec5793412bd313d7398081770e3b790a819c24d GIT binary patch literal 1068 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 Q8joe9*8Eh*&Nz(!23LuLvj6}9 literal 0 HcmV?d00001 diff --git a/text_analysis/tools/__pycache__/tool.cpython-38.pyc b/text_analysis/tools/__pycache__/tool.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f64dd050eda6bd170923a5919d51f28442065639 GIT binary patch literal 2710 zcmb7GUys|y5#OaqiK3*7lelTGC{p4av{4&NqIB1j1;e<&>BALh8pKYM5C{k!xu>JW ze_bvepG*}+eQALJY0!t}p)b8dfg%QqB2RtEC+R-)A&s5-D;P!5nU&6Gr+H{8?CfxM zW;ioDzg@l2=~x7wf47q9-!=&O2fjT1=^m!FgKYMnlp|6Dr~wfMvvR9bwb?^(?jbHb=SgH*ghg` z?f5CyIiar*key@aLb6WWr`a>?={poW(rcvKc>wW{SG$@tZxmUY`{F*S8M(1mtf zt8|bXLI0RsGngjAf{cM%6%@g_d5gNZ0_*6!nVULBA&0H!HJhq6Vy3 z%Buy^7IkXul_#!yq4NzC);njYYi@u-w@!_2H{X8%FJlo5}Zpcy* z?MHzxqAczA`hwjOp3*C#qA#*6UeaEED6PwJREQu;@+(haG}wW4qLKOYYJ0uV7k=+@ zoCSVdTmj}(S?aj*kWL<8V*hV;%PdSx1v}&{DUMCU*MO|UcodB!T}v889!El2XMsr_ z3oVT}^TUE;MWwzUrJ<}9g3IO)Zv`yJ8px*Le!%wpU?!V6k5b{WTS2!YP42&|Qk1ol z$Fc_Xc6IQdNCVSzTuV)!`i#zQ<(#+iE0!O}9%n@v3%3ROe&Q{I>!5y-l{{b=f-+ye zO3J>R=6P_1+gZE_gixJo)T9<&gVCnvsim2~w_$E;=V3kvtItu6R!`up1p)(x!r8xo zi2xIT2)YjVg5IwIk2qPO32;S@X^1$|7Inqf72l}pQ!=aZn=4y|sHz^C>!dP|wG#rU zy$P6767bgq+Zy<3f^}_SR1IbQF`yDH^p(ZOmA;fH6rx4FvQ`#GrG@%s#6I8=_@?45 z#aoJRDZcezI&CFyD|tup9pDjvYh?^2uxxl9{Q86YAAR!0r$_(%<9qi${N?@MeWJt@ zwPALY=B2>xn%w)%A8>O|}vIafM zzXQ>zkob3ja~sjVho4uBin@ufD;S6*cXc4nmzq_!rf|v!St{Ugxd48Omw=GE4vlHT zudQZm(l#{hHxyk;aRq;T1p3nSyu^=E&ntfdr{L|4W%e5rd*d}0ANa}6>kJMl;SIJn zUb0uKyCJSSo1?+zrS0*h;mFw>I^(Uu@JuC*f?4V(3>8rd2U-Gw7FV+}6(AgLIb$VO z@uSvm!F?7-_RBmuw6B7?pN5RvxPhXu#Q{6C4?q-@`}-`khjx&adCUrEn<5IC?b`<# zlnoVA8<@}*emVog%nlLy*du0@duoFFJ%MPNOQ5^YcVZX~bF7Xu2&;agJa2&)X z>e^#_&)af|VoO^T8&H;ar`qoI8#)9xGk!+|vj*7W1_idck8=`O0fa9g|;u>HZJb z(k{0C=_RQys_wJ=`yk|B1LC&uAi=*!UOMG?&8u69e-k+QETGaWMHKhW{xETLrH=GR z@W3|qJidVo&mlpyaU03kk>CZyp9cc}!0;-245;eA0p6g}ybR|^8M7-GLxG=1km3yj TaQ&9~Z4+)At7gKzV$%NroT;{2 literal 0 HcmV?d00001 diff --git a/text_analysis/tools/__pycache__/tools.cpython-36.pyc b/text_analysis/tools/__pycache__/tools.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d09f422cc044eba5cbcdbd291558e353536439d3 GIT binary patch literal 4106 zcmai1-EUk+6`#2udp~x)cAQXS5sVvIC5B+9O{pNPqAHXsLX{Pohomc)tLvR>`>yZa zyPi9n*sHq_unx3RLxcz@?Mo4)dRrPZ07ilKbgUe;J)}%8U%QRw36(e1?LC5}^yDZg$o3GFmS%7)i++B-U<_ z%z)SHEAr$T_haUX#7hNKE@P|pX?W2_l&tyD{@wcr-@m*6y?6I-f3W}H4^KY)VA0|l zbW3X^5X=|8G;2|k2GVTuFc#7g+^+>|er-#->j`i8!V7k4(g6`PMVQ2krkw1}?cMZw z=&wbAEJVr1M!==hSkCE z{n)$OYkSv&wQB*t8PoX=RNL*h-3saT zg8K_yvSslHA<6Wf4*IM?eHQItRE2EMjn`fWz%cSH@;bRecFx0mR+qqv7gn{7({Y8J zxu{`9R@x(M;*QpFGZ$uu6>b0XI@z6qI$`Bm!X}SF&k=6DID}q_P354c1N2U;w2OWe z)e;sgi5(#+Z<{T#{-v)#FxWv1`Y_%&q!$kmY=`t*TVG{gKH%(!7UWHMUITHSmX#-j!=|NEs58?rY|=6X>4ojT+&b)FiEotohT9n7v0p?=bhaHVY_)*wC{AVtac| z;n?lrxR1&rpt5ufm4*P;9-`7>6C41;1| z%4fiAg?|R5EcDD;pMyp}D0-SPAz|~+f)$@bf%g0iig8%Cj1Ux5B0kTKkbKz;y?u|U2GK)#}Y z{PGcyf$a4j+2bk9kn$}>?H1H*Ab*`fN|EWJkXcC4T{ye@Fz(awQ(RyoX9y&UFSyIr_F^AxQyQ6&R2Zc)HZ3J-QM`1~yOe^aK!A`50lD z0us=nr)@SlLReEP?Gqf(&(pxWm2j5+FGnlBkknJo9nTwx2gMsDTo}v}S9V7dcQ=|J*qX5$;^>Bq4)N|K}Q4j){2iFLOnbyRLbQ$E~>1He3Y_%8g26NP2 z#@u8XGb1mjgw$p;Y1PB_X|(RubC!LDEboRai8pZIZp)9`=g|7NE;nkVLzZw{4OX=t z#2f9igLMrwxsiFpWm&9k_FuXkwx7dcIYn+%UaQEmh4I70lV9%bzxD2uAN*zi?oax+ zCP!Me7JdQFF;n7r%5Wqij=&gu=ovXaEP+wgVsLB091pKUJ%MMFRJj}Usq4%dXi_{Q z@ebpTJT@TGhWiZudzl+Y2rizi&L6ulEvXCBlDZUmn?Zy$j=4ZD2c3tS)RI){DWs|f zE=gLjGj(yZ{IyhRY|mQ{qrmfI0ivaLi}A}iuHeI=5Hoe38v7}5LAf2Oy{c{6l}5tg c#&!vFe#P*3daJ*7noenU(Vn$u?6N)iU%O%SZ~y=R literal 0 HcmV?d00001 diff --git a/text_analysis/tools/cusException.py b/text_analysis/tools/cusException.py new file mode 100644 index 0000000..2a87b59 --- /dev/null +++ b/text_analysis/tools/cusException.py @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- + +class pt_v_Exception(Exception): + def __str__(self): + return 'pt规则未在缓存中命中' + +class dt_v_Exception(Exception): + def __str__(self): + return 'dt规则未在缓存中命中' + +class dt_v_attr_Exception(Exception): + def __str__(self): + return 'dt_attrcode规则未在缓存中命中' + +class dt_v_codeid_Exception(Exception): + def __str__(self): + return 'dt_codeid规则未在缓存中命中' + +class dt_v_senti_Exception(Exception): + def __str__(self): + return 'dt_senti规则未在缓存中命中' + +class dt_v_res_Exception(Exception): + def __str__(self): + return 'dt_resverse规则未在缓存中命中' \ No newline at end of file diff --git a/text_analysis/tools/db_pool.py b/text_analysis/tools/db_pool.py new file mode 100644 index 0000000..81c5150 --- /dev/null +++ b/text_analysis/tools/db_pool.py @@ -0,0 +1,131 @@ +# coding=utf-8 +import time +import pymysql +from DBUtils.PooledDB import PooledDB,SharedDBConnection +import json +import datetime +import re +import traceback +class MySQLUtils(object): + def __init__(self, host, port, dbuser, password, database): + self.pool = PooledDB( + creator= pymysql, #使用连接数据库的模块 + maxconnections= 100, #连接池允许的最大连接数,0和None表示不限制连接数 + mincached= 10, #初始化时,链接池中至少创建的空闲的链接,0表示不创建 + maxcached= 100, #链接池中最多闲置的链接,0和None不限制 + maxshared=0,# 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。 + blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 + maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 + setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] + ping=0, # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always + host=host, + port=int(port), + user=dbuser, + password=password, + database=database, + charset='utf8mb4' + ) + #获取连接 + def connectdb(self): + conn = self.pool.connection() + # 验证当前连接是否断开,如果断开重新连接 + conn.ping(reconnect=True) + cursor = conn.cursor(pymysql.cursors.DictCursor) + return conn,cursor + + ''' + 查询语句 + 返回全部内容 + ''' + def queryAll(self,sql): + conn,cursor = self.connectdb() + cursor.execute(sql) + results = cursor.fetchall() + conn.close() + return results + ''' + 查询语句 + 返回单条内容 + ''' + def queryOne(self,sql): + conn,cursor = self.connectdb() + cursor.execute(sql) + results = cursor.fetchone() + conn.close() + return results + ''' + 插入数据 + ''' + def insert(self,sql,values): + conn, cursor = self.connectdb() + try: + # 执行 SQL 语句 + cursor.execute(sql, values) + # 提交事务 + conn.commit() + except: + print('插入失败') + print('错误sql语句:%s' %sql) + traceback.print_exc() + conn.rollback() + finally: + conn.close() + ''' + 修改数据 + ''' + def update(self,sql): + conn, cursor = self.connectdb() + try: + cursor.execute(sql) + conn.commit() + except: + print('修改失败') + print('错误sql语句:%s' %sql) + print(traceback.print_exc()) + conn.rollback() + finally: + conn.close() + + ''' + 删除数据 + ''' + def delete(self,sql): + conn, cursor = self.connectdb() + try: + cursor.execute(sql) + conn.commit() + except: + print('删除失败') + print('错误sql语句:%s' %sql) + conn.rollback() + finally: + conn.close() + +def get_conn_pool(host,port,username,password,db): + sqlhelper = MySQLUtils(host, port, username, password, db) + return sqlhelper + +if __name__ == '__main__': + sqlhelper = MySQLUtils("172.26.11.110", 3306, "crawl", "crawl123", "kyyzgpt") + + # conn = sqlhelper.pool.connection() + # cursor = conn.cursor(pymysql.cursors.DictCursor) + sql = 'select relation_id,start_id,end_id from relations where blueprint_id = 5' + print("sql:%s" %sql) + # cursor.execute(sql) + # results = cursor.fetchall() + results = sqlhelper.queryOne(sql) + print (json.dumps(results)) + # if results: + # print('有数据:{}'.format(len(results))) + # for item in results: + # + # if item['sign']=='user': + # p1 = r".*(?=/video)" + # pattern1 = re.compile(p1) + # matcher1 = re.search(pattern1, item['url']) + # # attr = {'brand':item['keyword'],'project_name':'208-A国'} + # attr = {'project_name':'208-A国'} + # sql = "insert into crawl_seed_task (pageTypeID,cid,task_url,attachTag,crawl_mode,crawl_cyclicity_minute,crawl_period_hour,last_crawl_time,next_crawl_time,createTime) values(61,'youtube','{}','{}',1,720,24,'2019-11-28 12:00:00','2019-11-29 00:00:00',NOW())".format(matcher1.group(),json.dumps(attr).encode('utf-8').decode('unicode_escape')) + # sqlhelper.insert(sql) + # print('sql:%s' %sql) \ No newline at end of file diff --git a/text_analysis/tools/kakfa_util.py b/text_analysis/tools/kakfa_util.py new file mode 100644 index 0000000..eaa6cf3 --- /dev/null +++ b/text_analysis/tools/kakfa_util.py @@ -0,0 +1,67 @@ +# coding=utf-8 +from kafka import KafkaProducer +from kafka import KafkaConsumer +import json +import traceback +import time +import traceback +import datetime +import queue +from logUtil import get_logger + +logger = get_logger("crawlWebsrcCode.log") +""" +写到kafka +""" +def kafkaProduce(topic,resultData,address): + producer = KafkaProducer(bootstrap_servers = '{}'.format(address),request_timeout_ms=120000) + topics = topic.split(',') + for tc in topics: + future = producer.send(tc,resultData) + result = future.get(timeout=60) + producer.flush() + print (result) + +#写入文件 +def writeTxt(filePath,result): + f = open(filePath,'a',encoding='utf-8') + f.write(result.encode('utf-8').decode('unicode_escape')+'\n') + f.close + +def KafkaConsume(topic,address,group_id,task_queue,logger): + ''' + 监控kafka,读取数据写到任务队列 + :param topic: + :param address: + :param group_id: + :param task_queue: + :return: + ''' + try: + consumer = KafkaConsumer(topic, auto_offset_reset='earliest',fetch_max_bytes=1024768000,fetch_max_wait_ms=5000, bootstrap_servers=address,group_id = group_id) + i = 1 + while True: + for msg in consumer: + print('第{}条数据'.format(i)) + data = str(msg.value, encoding = "utf-8") + print(data) + task_queue.put(data) + i = i+1 + else: + print('暂无任务------') + time.sleep(10) + except Exception as e: + print('kafka未知异常----') + traceback.print_exc() + +def writeTxt(filePath,result): + f = open(filePath,'a') + f.write(result+'\n') + f.close + +if __name__ == '__main__': + # resultData = {'id': '中文', 'url': 'https://zh.wikipedia.org/zh/%E8%94%A1%E8%8B%B1%E6%96%87'} + # kafkaProduce('test', json.dumps(resultData).encode('utf-8').decode('unicode_escape').encode(),'121.4.41.194:8008') + task_queue = queue.Queue() + KafkaConsume('fq-Taobao-eccontent','39.129.129.172:6666,39.129.129.172:6668,39.129.129.172:6669,39.129.129.172:6670,39.129.129.172:6671','news_sche_8',task_queue,logger) + # KafkaConsume('zxbnewstopic','120.133.14.71:9992','group3',task_queue,logger) diff --git a/text_analysis/tools/mysql_helper.py b/text_analysis/tools/mysql_helper.py new file mode 100644 index 0000000..6118907 --- /dev/null +++ b/text_analysis/tools/mysql_helper.py @@ -0,0 +1,338 @@ +# coding:utf8 +import os, sys +cur_dir = os.path.dirname(os.path.abspath(__file__)) or os.getcwd() +par_dir = os.path.abspath(os.path.join(cur_dir, os.path.pardir)) +sys.path.append(cur_dir) +sys.path.append(par_dir) +import json +import re +# from log_util.set_logger import set_logger +# logging = set_logger('logs/error.log') +import pymysql.cursors +import traceback + +def mysqlConn(data,logging): + res={"successCode":"1","errorLog":"","results":""} + p_host=data["Host"] + p_port=int(data["Port"]) + p_db=data["Database"] + p_user=data["User"] + p_password=data["Password"] + try: + db = pymysql.connect(host=p_host, user=p_user, passwd=p_password, db=p_db, port=p_port, + charset='utf8', cursorclass=pymysql.cursors.DictCursor) + db.ping(reconnect=True) + cursor = db.cursor() + sql = "SHOW TABLES" + cursor.execute(sql) + tables = cursor.fetchall() + if tables: + table_names = list(map(lambda x: list(x.values())[0], tables)) + res["results"] = table_names + else: + res["successCode"] = "0" + cursor.close() + db.close() + return res + except: + res["successCode"] = "0" + res["errorLog"]=traceback.format_exc() + logging.error(traceback.format_exc()) + return res + +def getTableColumnNames(data,logging): + res={"successCode":"1","errorLog":"","results":""} + p_host=data["Host"] + p_port=int(data["Port"]) + p_db=data["Database"] + p_user=data["User"] + p_password=data["Password"] + p_table=data["Table"] + try: + db = pymysql.connect(host=p_host, user=p_user, passwd=p_password, db=p_db, port=p_port, + charset='utf8', cursorclass=pymysql.cursors.DictCursor) + db.ping(reconnect=True) + cursor = db.cursor() + sql = "DESCRIBE "+p_table + cursor.execute(sql) + tables = cursor.fetchall() + if tables: + table_names = list(map(lambda x: x['Field'], tables)) + res["results"] = table_names + else: + res["successCode"] = "0" + cursor.close() + db.close() + return res + except: + res["successCode"] = "0" + res["errorLog"]=traceback.format_exc() + logging.error(traceback.format_exc()) + return res + +def mysqlInsert(input,logging): + res={"successCode":"1","errorLog":"","results":""} + data=input["metadata"]["admin"] + p_host=data["Host"] + p_port=int(data["Port"]) + p_db=data["Database"] + p_user=data["User"] + p_password=data["Password"] + p_table=data["Table"] + p_columnName=data["columnName"] + cN='('+','.join(p_columnName)+') ' + p_values=data["values"] + val=tuple(p_values) + try: + db = pymysql.connect(host=p_host, user=p_user, passwd=p_password, db=p_db, port=p_port, + charset='utf8', cursorclass=pymysql.cursors.DictCursor) + db.ping(reconnect=True) + cursor = db.cursor() + sql = "insert into " + p_table + cN + "values ("+ ','.join(['%s'] * len(val)) + ")" + cursor.execute(sql,val) + db.commit() + cursor.close() + db.close() + return res + except: + res["successCode"] = "0" + res["errorLog"]=traceback.format_exc() + logging.error(traceback.format_exc()) + return res + +def mysqlUpdate(input,logging): + res={"successCode":"1","errorLog":"","results":""} + data=input["metadata"]["admin"] + p_host=data["Host"] + p_port=int(data["Port"]) + p_db=data["Database"] + p_user=data["User"] + p_password=data["Password"] + p_table=data["Table"] + # p_set=data["Set"] + p_set=get_updateSet(input) + # where=process_where(data["Filter"]) + where=get_filter(data["Filter"]) + try: + db = pymysql.connect(host=p_host, user=p_user, passwd=p_password, db=p_db, port=p_port, + charset='utf8', cursorclass=pymysql.cursors.DictCursor) + db.ping(reconnect=True) + cursor = db.cursor() + sql = "UPDATE " + p_table + p_set + where + print(sql) + cursor.execute(sql) + db.commit() + cursor.close() + db.close() + return res + except: + res["successCode"] = "0" + res["errorLog"]=traceback.format_exc() + logging.error(traceback.format_exc()) + return res + +def mysqlExecute(input,logging): + res={"successCode":"1","errorLog":"","results":""} + data=input["metadata"]["admin"] + p_host=data["Host"] + p_port=int(data["Port"]) + p_db=data["Database"] + p_user=data["User"] + p_password=data["Password"] + execute=data["Execute"] + try: + db = pymysql.connect(host=p_host, user=p_user, passwd=p_password, db=p_db, port=p_port, + charset='utf8', cursorclass=pymysql.cursors.DictCursor) + db.ping(reconnect=True) + cursor = db.cursor() + cursor.execute(execute) + if 'select' in execute.lower(): + result = cursor.fetchall() + res["results"]=json.dumps(result,ensure_ascii=False) + else: + db.commit() + cursor.close() + db.close() + return res + except: + res["successCode"] = "0" + res["errorLog"]=traceback.format_exc() + logging.error(traceback.format_exc()) + return res + +# def process_where(data): +# ''' +# 组装where +# :param data: data["Filter"],{"key":"age","value":"20","operator":">"},{"logicalSymbol":"and"},{"key":"weight","value":"50","operator":"<"} +# :return: WHERE age>20 and weight<50 +# ''' +# if data=="" or data==[]: +# return "" +# where = " WHERE " +# for line in data: +# if "key" in line.keys(): +# val = line["value"] +# if isinstance(val, str): +# val = "\'" + val + "\'" +# tmp = str(line["key"]) + " " + line["operator"] + " " + str(val) +# where += tmp +# else: +# where += " " + line["logicalSymbol"] + " " +# return where +# +# def process_filter(data): +# ''' +# 组装key,value,operator +# :param data: data["Filter"],{"key":"age",value:"20","operator":"="} +# :return: age=20 +# ''' +# if data=="" or data==[]: +# return "" +# res=data["key"]+" "+data["operator"]+" "+data["value"] +# return res + +def get_updateSet(input): + metadata=input["metadata"] + user=metadata["user"] + sets=metadata["admin"]["Set"] + res=[] + for line in sets: + part=line.split("=") + tmp = [] + for p in part: + user_match=re.findall('##(.*?)##', p) + if user_match!=[]: + tmp.append(user[user_match[0]]) + res.append(str(tmp[0])+"="+str(tmp[1])) + result=" SET "+",".join(res) + return result + +def get_filter(data): + if "OR" not in data.keys(): + return "" + op_or=data["OR"] + res = "" + if len(op_or) == 1: + tmp = [] + line = op_or[0]["AND"] + for single_line in line: + val = single_line["value"] + if isinstance(val, str): + val = "\'" + val + "\'" + tmp.append(str(single_line["key"]) + single_line["operator"] + str(val)) + if single_line != line[-1]: + tmp.append("and") + res = " WHERE "+" ".join(tmp) + elif len(op_or) > 1: + tmp = [] + for single_and in op_or: + line = single_and["AND"] + for sigle_line in line: + val = sigle_line["value"] + if isinstance(val, str): + val = "\'" + val + "\'" + tmp.append(str(sigle_line["key"]) + sigle_line["operator"] + str(val)) + if sigle_line != line[-1]: + tmp.append("and") + if single_and != op_or[-1]: + tmp.append("or") + res = " WHERE "+" ".join(tmp) + return res + + +def mysqlQuery(input,logging): + res={"successCode":"1","errorLog":"","results":""} + data=input["metadata"]["admin"] + p_host=data["Host"] + p_port=int(data["Port"]) + p_db=data["Database"] + p_user=data["User"] + p_password=data["Password"] + p_table=data["Table"] + p_columnNames=data["columnNames"] + # p_filter=data["Filter"] + column='*' + if len(p_columnNames)==1: + column=p_columnNames[0] + elif len(p_columnNames)>1: + column=','.join(p_columnNames) + where=get_filter(data["Filter"]) + try: + db = pymysql.connect(host=p_host, user=p_user, passwd=p_password, db=p_db, port=p_port, + charset='utf8', cursorclass=pymysql.cursors.DictCursor) + db.ping(reconnect=True) + cursor = db.cursor() + sql = "SELECT " + column +" From "+ p_table + where + # print(sql) + cursor.execute(sql) + result = cursor.fetchall() + res["results"]=json.dumps(result,ensure_ascii=False) + cursor.close() + db.close() + return res + except: + res["successCode"] = "0" + res["errorLog"]=traceback.format_exc() + logging.error(traceback.format_exc()) + return res + +def mysqlDelete(input,logging): + res={"successCode":"1","errorLog":"","results":""} + data=input["metadata"]["admin"] + p_host=data["Host"] + p_port=int(data["Port"]) + p_db=data["Database"] + p_user=data["User"] + p_password=data["Password"] + p_table=data["Table"] + # where=process_where(data["Filter"]) + where=get_filter(data["Filter"]) + try: + db = pymysql.connect(host=p_host, user=p_user, passwd=p_password, db=p_db, port=p_port, + charset='utf8', cursorclass=pymysql.cursors.DictCursor) + db.ping(reconnect=True) + cursor = db.cursor() + sql = "DELETE From "+ p_table + where + cursor.execute(sql) + db.commit() + cursor.close() + db.close() + return res + except: + res["successCode"] = "0" + res["errorLog"]=traceback.format_exc() + logging.error(traceback.format_exc()) + return res + + +if __name__=="__main__": + input={"metadata":{"admin":{ + "type":"query", + "Table":"student", + "columnNames":["name","age"], + "Set":["##tag1##=##value1##","##tag2##=##value2##"], + "Filter":{ + "OR":[ + { + "AND":[{"key":"age","value":20,"operator":">"},{"key":"weight","value":50,"operator":"<"}] + }, + { + "AND":[{"key":"name","value":"ff","operator":"="}] + } + ] + }, + "Host":"172.26.28.30", + "Port":"3306", + "Database":"test", + "User":"crawl", + "Password":"crawl123" + }}, + "user": { + "tag1": "age", + "tag2": "weight", + "value1": 2, + "value2": 100 + } + } + res=mysqlUpdate(input,"") + print(res) \ No newline at end of file diff --git a/text_analysis/tools/process.py b/text_analysis/tools/process.py new file mode 100644 index 0000000..0f2ff32 --- /dev/null +++ b/text_analysis/tools/process.py @@ -0,0 +1,51 @@ +#coding:utf8 +import os, sys +cur_dir = os.path.dirname(os.path.abspath(__file__)) or os.getcwd() +par_dir = os.path.abspath(os.path.join(cur_dir, os.path.pardir)) +sys.path.append(cur_dir) +sys.path.append(par_dir) +import json +from text_analysis.tools import to_kafka +from tools.mysql_helper import mysqlConn,mysqlInsert,mysqlQuery,mysqlExecute,mysqlUpdate,mysqlDelete,getTableColumnNames +import traceback +import time +from log_util.set_logger import set_logger +logging=set_logger('results.log') + +from views import task_queue + +def process_data(): + while True: + try: + # print("task_queue:",task_queue) + if task_queue.qsize() >0: + try: + raw_data = task_queue.get() + res = "" + logging.info("启动数据处理线程——") + logging.info(raw_data) + flag = raw_data["metadata"]["admin"]["type"] + # type分为execute、query、insert、update、delete + if flag == 'insert': + res = mysqlInsert(raw_data, logging) + elif flag == 'execute': + res = mysqlExecute(raw_data, logging) + elif flag == 'update': + res = mysqlUpdate(raw_data, logging) + elif flag == 'query': + res = mysqlQuery(raw_data, logging) + elif flag == 'delete': + res = mysqlDelete(raw_data, logging) + raw_data["result"] = res + logging.info("************写入kafka***********") + to_kafka.send_kafka(raw_data) + except: + raw_data["result"] = {"successCode": "0", "errorLog": "", "results": ""} + raw_data["result"]["errorLog"] = traceback.format_exc() + to_kafka.send_kafka(raw_data) + else: + logging.info("暂无任务,进入休眠--") + print("222222222222222222222222") + time.sleep(10) + except: + logging.error(traceback.format_exc()) \ No newline at end of file diff --git a/text_analysis/tools/seleniumTest.py b/text_analysis/tools/seleniumTest.py new file mode 100644 index 0000000..dbc937a --- /dev/null +++ b/text_analysis/tools/seleniumTest.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- +import time +import threading +from selenium import webdriver +import json +from urllib.parse import urljoin +from kakfa_util import KafkaConsume +from kakfa_util import kafkaProduce +from logUtil import get_logger +from Go_fastDfs import uploadFile +import traceback +import queue +import configparser +import os, sys +import re +logger = get_logger("./logs/crawlWebsrcCode.log") +#加载配置文件 +configFile = './config.ini' +# 创建配置文件对象 +con = configparser.ConfigParser() +# 读取文件 +con.read(configFile, encoding='utf-8') +kafkaConfig = dict(con.items('kafka'))#kafka配置信息 +goFastdfsConfig = dict(con.items('goFastdfs'))#goFastdfs配置信息 +class Spider(object): + def __init__(self,url): + self.chromeOptions = self.get_profile() + self.browser = self.get_browser() + self.url = url + def get_profile(self): + chromeOptions = webdriver.ChromeOptions() + chromeOptions.add_argument('--headless') # 谷歌无头模式 + chromeOptions.add_argument('--disable-gpu') # 禁用显卡 + # chromeOptions.add_argument('window-size=1280,800') # 指定浏览器分辨率 + chromeOptions.add_argument("--no-sandbox") + return chromeOptions + + def get_browser(self): + browser = webdriver.Chrome("D:\\工作使用\\zhaoshang\\chromedriver.exe",chrome_options=self.chromeOptions) + return browser + + def _get_page(self,path): + ''' + 获取页面原格式,写入文件并返回路径 + :param path: + :return: + ''' + self.browser.get(self.url) + time.sleep(5) + logger.info("休眠结束") + # 向下偏移了10000个像素,到达底部。 + scrollTop = 10000 + for num in range(1,10): + js = "var q=document.documentElement.scrollTop={}".format(scrollTop*num) + logger.info("第{}次滚动".format(num)) + self.browser.execute_script(js) + time.sleep(5) + # 执行 Chome 开发工具命令,得到mhtml内容 + res = self.browser.execute_cdp_cmd('Page.captureSnapshot', {}) + #获取文章标题 + title = '无标题' + try: + title = self.browser.find_element_by_css_selector("title").get_attribute("textContent") + except Exception as e: + logger.error('获取标题异常----') + traceback.print_exc() + pathName = '{}{}.mhtml'.format(path,title) + with open(pathName, 'w',newline='') as f: + f.write(res['data']) + return pathName,title +if __name__ == '__main__': + #初始化任务队列 + task_queue = queue.Queue() + #跟读kafka线程 + logger.info("开启读取kafka线程---") + t = threading.Thread(target=KafkaConsume, name='LoopThread',args=(kafkaConfig['read_topic'], kafkaConfig['address'], kafkaConfig['group_id'], task_queue,logger)) + t.daemon = True + t.start() + #获取任务执行页面原格式保留 + + + + + + while True: + try: + if task_queue.qsize() >0: + taskStr = task_queue.get() + logger.info('当前任务:{}'.format(taskStr)) + task = json.loads(taskStr) + p1 = u'(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]' + pattern1 = re.compile(p1) + matcher1 = re.search(p1, task['url']) + if matcher1: + l = Spider(task['url']) + pathName,title = l._get_page(goFastdfsConfig['path']) + l.browser.quit() + #gofast 上传,写入kafka + if '404 Not Found' in title: + logger.error('页面404,无效') + resultData = { + 'code': 500, + 'id': task['id'], + 'message': '页面404' + } + kafkaProduce(kafkaConfig['data_topics'], + json.dumps(resultData).encode('utf-8').decode('unicode_escape').encode(), + kafkaConfig['address']) + time.sleep(2) + continue + try: + uploadStr = uploadFile('{}upload'.format(goFastdfsConfig['uploadaddress']),pathName,logger) + uploadJson = json.loads(uploadStr) + except Exception as e: + logger.error('文件上传异常----') + traceback.print_exc() + resultData = { + 'code': 500, + 'id': task['id'], + 'message': '文件上传失败' + } + kafkaProduce(kafkaConfig['data_topics'], + json.dumps(resultData).encode('utf-8').decode('unicode_escape').encode(), + kafkaConfig['address']) + time.sleep(2) + continue + resultData = { + 'code':200, + 'id':task['id'], + 'url':goFastdfsConfig['downloadaddress']+uploadJson['path'], + 'title':title, + 'delMd5':uploadJson['md5'], + 'uploadTime':uploadJson['mtime'], + 'message':'成功' + } + kafkaProduce(kafkaConfig['data_topics'],json.dumps(resultData).encode('utf-8').decode('unicode_escape').encode(),kafkaConfig['address']) + logger.info('数据写入成功') + #删除文件 + if (os.path.exists(pathName)): + os.remove(pathName) + logger.info('清除文件:{}'.format(pathName)) + else: + logger.info('要删除的文件不存在:{}'.format(pathName)) + else: + logger.error('非正确url:'.format(task['url'])) + resultData = { + 'code': 500, + 'id': task['id'], + 'message': '非正确url' + } + kafkaProduce(kafkaConfig['data_topics'], + json.dumps(resultData).encode('utf-8').decode('unicode_escape').encode(), + kafkaConfig['address']) + time.sleep(2) + continue + else: + logger.info("暂无任务,进入休眠--") + time.sleep(10) + except Exception as e: + logger.error('未知异常----') + traceback.print_exc() + resultData = { + 'code': 500, + 'id': task['id'], + 'message': '未知异常' + } + kafkaProduce(kafkaConfig['data_topics'], + json.dumps(resultData).encode('utf-8').decode('unicode_escape').encode(), + kafkaConfig['address']) + time.sleep(2) + diff --git a/text_analysis/tools/to_kafka.py b/text_analysis/tools/to_kafka.py new file mode 100644 index 0000000..a32238a --- /dev/null +++ b/text_analysis/tools/to_kafka.py @@ -0,0 +1,25 @@ +#coding:utf8 +import traceback +import json +from kafka import KafkaProducer +from text_analysis.read_config import load_config +config=load_config() + +def send_kafka(data,logging): + try: + producer = None + topic = config["kafka"]["topic"] + data1=json.dumps(data,ensure_ascii=False) + kafkaProduce(topic,bytes(data1, encoding='utf-8')) + logging.info("数据推入kafka!") + + except Exception as e: + logging.info(traceback.format_exc()) + logging.info('写入kafka失败') + +def kafkaProduce(topic,resultData): + producer = KafkaProducer(bootstrap_servers = '{}'.format(config["kafka"]["bootstrap_servers"]),max_request_size=52428800) + topics = topic.split(',') + for tc in topics: + future = producer.send(tc,resultData) + producer.flush() diff --git a/text_analysis/tools/tool.py b/text_analysis/tools/tool.py new file mode 100644 index 0000000..9b69f81 --- /dev/null +++ b/text_analysis/tools/tool.py @@ -0,0 +1,155 @@ +#coding:utf8 +import re +import json +from jsonpath_ng import jsonpath, parse +import traceback +from log_util.set_logger import set_logger +def parse_data(raw_data,url): + val = None + try: + if "#json#" in url: + parm = url.split("#") + data1 = parse_data(raw_data, parm[0]) + data1_json = json.loads(data1) + expr = parse(parm[2]) + match = [match.value for match in expr.find(data1_json)] + val = match[0] + else: + all_result = raw_data['data'] + param_split = str(url).split(":") + datasourcestr = all_result[param_split[0]] + datasource = json.loads(datasourcestr) + # 创建 JsonPath 表达式对象 + expr = parse(param_split[1]) + # 使用表达式来选择 JSON 元素 + match = [match.value for match in expr.find(datasource)] + val = match[0] + except Exception as e: + traceback.print_exc() + val = '' + return val + + + + +def get_content(inputdata,logging): + """ + 重新组装参数 + :param inputdata:原json数据 + :return: 组装的prompt及其他参数 + """ + res={} + admin=inputdata["metadata"]["admin"] + data=inputdata["data"] + prompt=admin["prompt"] + if_user=re.findall("{{(.*)}}",prompt) + if_data=re.findall("@@(.*)@@",prompt) + if if_user != []: + user_data=inputdata["metadata"]["user"] + if if_user[0] in user_data.keys(): + tmp=user_data[if_user[0]] + prompt=re.sub("{{(.*)}}",tmp,prompt) + if if_data!=[] and if_data[0] in data.keys(): + tmp1=data[if_data[0]] + prompt=re.sub("@@(.*)@@",tmp1,prompt) + res["prompt"]=prompt + res["authorization"]=admin["authorization"] + res["model"]=admin["model"] + res["temperature"]=admin["temperature"] + res["authorization"]=admin["authorization"] + res["top_p"]=admin["top_p"] + res["n"]=admin["n"] + return res + + + +if __name__=="__main__": + datasourcestr = '{"author": "Pelham@Resist_05", "authorId": "1430497892314218502", "authornickname": "", "commentsCount": 2518, "content": "Israeli Army Commander admits they handcuffed 2 couples inside a house then used tanks to destroy the building.15 civilians were burned to death including 8 babies… https://t.co/1V4iUsA3RM", "crawlTimeStr": "2024-01-03 17:39:25", "fansCount": "", "friendsCount": "", "otherInfoJson": "", "pageType": "storyDetailPage", "postCount": "", "postId": "1733008513163784237", "pubTimeStr": "2023-12-08 14:20:01", "subjectId": "304904", "taskId": "1111881", "userType": ""}' + datasource = json.loads(datasourcestr) + # logging.info("数据源:{}".format(datasource)) + # 创建 JsonPath 表达式对象 + expr = parse("$.crawlTimeStr") + # 使用表达式来选择 JSON 元素 + match = [match.value for match in expr.find(datasource)] + val = match[0] + print(val) +# inputdata={ +# "metadata":{ +# "output":{ +# "output_type":"table", +# "label_col":[ +# "软件著作抽取结果" +# ] +# }, +# "input":{ +# "input_type":"text", +# "label":[ +# "7_软件著作过滤器" +# ] +# }, +# "address":"http://172.18.1.181:9011/chatGpt/", +# "admin":{ +# "authorization":"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", +# "top_p":"1", +# "user_input":[ +# { +# "keyname":"tag", +# "keydesc":"" +# } +# ], +# "temperature":"0.2", +# "model":"gpt-3.5-turbo-16k", +# "prompt":"请在下面这句话中提取出:证书号、软件名称、著作权人,以json格式输出,找不到的字段赋值为空字符串,不要有多余的文字输出,只输出json结构。@@7_软件著作过滤器@@", +# "n":"1" +# }, +# "index":1 +# }, +# "data":{ +# "1_项目文件上传":"[{ \"fileUrl\":\"http://172.18.1.130:9985/group33/default/20230816/16/05/1/1-基于时间序列遥感 影像洪涝检测系统.jpg\",\"fileType\":\"jpg\", \"filePath\":\"/软件著作/1-基于时间序列遥感 影像洪涝检测系统.jpg\",\"fileId\":\"cd6592f0389bb1da25afbb44901f9cde\",\"fileName\":\"1-基于时间序列遥感 影像洪涝检测系统.jpg\" },{ \"fileUrl\":\"http://172.18.1.130:9985/group33/default/20230816/16/06/1/2-基于遥感影像的快速变化检测系统.jpg\",\"fileType\":\"jpg\", \"filePath\":\"/软件著作/2-基于遥感影像的快速变化检测系统.jpg\",\"fileId\":\"338847e34904fa96e8834cb220667db8\",\"fileName\":\"2-基于遥感影像的快速变化检测系统.jpg\" },{ \"fileUrl\":\"http://172.18.1.130:9985/group33/default/20230816/16/08/1/3-基于时空模型的遥感时间序列森林火灾检测系统.jpg\",\"fileType\":\"jpg\", \"filePath\":\"/软件著作/1/3-基于时空模型的遥感时间序列森林火灾检测系统.jpg\",\"fileId\":\"944eec1cf98f216ea953459dac4dd505\",\"fileName\":\"3-基于时空模型的遥感时间序列森林火灾检测系统.jpg\" },{ \"fileUrl\":\"http://172.18.1.130:9985/group33/default/20230816/16/09/1/4-基于隐马尔可夫模型的遥感时间序列分类系统.jpg\",\"fileType\":\"jpg\", \"filePath\":\"/软件著作/4-基于隐马尔可夫模型的遥感时间序列分类系统.jpg\",\"fileId\":\"eb378cb9ee914323f601500378dfad76\",\"fileName\":\"4-基于隐马尔可夫模型的遥感时间序列分类系统.jpg\" }]", +# "2_文件分类信息":"{\"软件著作\":4}", +# "3_OCR识别内容":"{\"content\":\" 22222222222222222222222222222222222222222222222222\\n中华人民共和国国家版权局\\n计算机软件著作权登记证书\\n证书号:软著登字第1623261号\\n软件名称:\\n基于遥感影像的快速变化检测系统\\nV1.0\\n著作权人:中国科学院遥感与数字地球研究所\\n开发完成日期:2016年08月01日\\n首次发表日期:未发表\\n权利取得方式:原始取得\\n权利范围:全部权利\\n登记号:2017SR037977\\n根据《计算机软件保护条例》和《计算机软件著作权登记办法》的\\n规定,经中国版权保护中心审核,对以上事项予以登记\\n计算机软件著作权\\n登记专用章\\n2017年02月10日\\nNo.01433672\",\"fileId\":\"338847e34904fa96e8834cb220667db8\",\"fileName\":\"2-基于遥感影像的快速变化检测系统.jpg\",\"filePath\":\"/软件著作/2-基于遥感影像的快速变化检测系统.jpg\",\"fileType\":\"jpg\",\"fileUrl\":\"http://172.18.1.130:9985/group33/default/20230816/16/06/1/2-基于遥感影像的快速变化检测系统.jpg\",\"pageNum\":1}", +# "businessKey":"185aef3b1c810799a6be8314abf6512c", +# "7_软件著作过滤器":"{\"content\":\" 22222222222222222222222222222222222222222222222222\\n中华人民共和国国家版权局\\n计算机软件著作权登记证书\\n证书号:软著登字第1623261号\\n软件名称:\\n基于遥感影像的快速变化检测系统\\nV1.0\\n著作权人:中国科学院遥感与数字地球研究所\\n开发完成日期:2016年08月01日\\n首次发表日期:未发表\\n权利取得方式:原始取得\\n权利范围:全部权利\\n登记号:2017SR037977\\n根据《计算机软件保护条例》和《计算机软件著作权登记办法》的\\n规定,经中国版权保护中心审核,对以上事项予以登记\\n计算机软件著作权\\n登记专用章\\n2017年02月10日\\nNo.01433672\",\"fileId\":\"338847e34904fa96e8834cb220667db8\",\"fileName\":\"2-基于遥感影像的快速变化检测系统.jpg\",\"filePath\":\"/软件著作/2-基于遥感影像的快速变化检测系统.jpg\",\"fileType\":\"jpg\",\"fileUrl\":\"http://172.18.1.130:9985/group33/default/20230816/16/06/1/2-基于遥感影像的快速变化检测系统.jpg\",\"pageNum\":1}" +# }, +# "created":1691004265000, +# "module":"OCR", +# "start_tag":"false", +# "last_edit":1692464331000, +# "next_app_id":[ +# { +# "start_id":86, +# "edge_id":49, +# "end_id":90 +# } +# ], +# "transfer_id":11, +# "blueprint_id":3, +# "scenes_id":3, +# "scenario":{ +# "dataloss":1, +# "autoCommitTriggerLast":1, +# "maxErrors":3, +# "autoCommit":1, +# "freshVariables":1 +# }, +# "wait_condition":[ +# +# ], +# "scheduling":{ +# "interval":-1, +# "type":"single" +# }, +# "name":"软件著作抽取", +# "businessKey":"185aef3b1c810799a6be8314abf6512c", +# "id":86, +# "describe":"软件著作抽取" +# } +# a=get_content(inputdata,"") +# print(a) + + + + + + + diff --git a/text_analysis/urls.py b/text_analysis/urls.py new file mode 100644 index 0000000..89800b2 --- /dev/null +++ b/text_analysis/urls.py @@ -0,0 +1,13 @@ +from django.conf.urls import include, url +from django.contrib import admin +from text_analysis import views + +urlpatterns = [ + + url(r'^robotIdentification',views.robotIdentification, name='robotIdentification'), + # url(r'^mysqlConnection',views.mysqlConnection, name='mysqlConnection'), + # url(r'^mysqlField', views.mysqlField, name='mysqlField') + +] + + diff --git a/text_analysis/views.py b/text_analysis/views.py new file mode 100644 index 0000000..2ffb064 --- /dev/null +++ b/text_analysis/views.py @@ -0,0 +1,383 @@ +# coding:utf8 +import os, sys +import io + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8') +cur_dir = os.path.dirname(os.path.abspath(__file__)) or os.getcwd() +par_dir = os.path.abspath(os.path.join(cur_dir, os.path.pardir)) +sys.path.append(cur_dir) +sys.path.append(par_dir) +import json +from django.http import HttpResponse +from text_analysis.tools import to_kafka +from django.views.decorators.csrf import csrf_exempt +from log_util.set_logger import set_logger +from text_analysis.tools.tool import parse_data +logging = set_logger('logs/results.log') +import traceback +import time +import joblib +from text_analysis.cusException import userFile_Exception, postFile_Exception + +from kazoo.client import KazooClient +from kazoo.protocol.states import EventType +# 任务队列 +import queue +task_queue = queue.PriorityQueue() +stop_dict={} +from text_analysis.read_config import load_config +config=load_config() + +#mysql连接池 +from text_analysis.tools.db_pool import get_conn_pool + +@csrf_exempt +def robotIdentification(request): + if request.method == 'POST': + try: + raw_data = json.loads(request.body) + if "trace" in raw_data.keys() and raw_data["trace"]==True: + task_queue.put((-1, time.time(),raw_data)) + else: + task_queue.put((1,time.time(), raw_data)) + return HttpResponse(json.dumps({"code": 1, "msg": "请求正常!"}, ensure_ascii=False)) + except: + logging.error(traceback.format_exc()) + return HttpResponse(json.dumps({"code": 0, "msg": "请求json格式不正确!"}, ensure_ascii=False)) + else: + return HttpResponse(json.dumps({"code": 0, "msg": "请求方式错误,改为post请求"}, ensure_ascii=False)) + + +def predict(user_file_result,post_file_result,task): + try: + # raw_data = {"user_file": {"accountId": "39234393", "accountName": "hello", "nickName": "Johnson Leung", + # "fansCount": 308, "likeCount": 92707, "postCount": 14237, + # "otherInfo": "{\"\"otherInfo\"\":\"\"{\"\"bio\"\": \"\"Huge}", + # "authentication": 0}, + # "post_file": {"count": 1, "LikeCount": 12, "CommentsCount": 1, "ShareCount": 1, + # "length": 150, "tags": 0, "https": 0, "at": 0, "diffdate": 1}} + # 用户数据 + res = {"successCode": "1", "errorLog": "", "results": {}} + user_data = [] + # 返回值需要的三个字段 + accountId = "" + nickName = "" + accountName = "" + data = {} + if user_file_result: + data['user_file'] = user_file_result + logging.info('用户数据:{}'.format(data['user_file'])) + accountId = data["user_file"]["accountId"] + nickName = data["user_file"]["nickName"] + accountName = data["user_file"]["accountName"] + else: + data['user_file'] = {} + raise userFile_Exception + if post_file_result: + data['post_file'] = post_file_result + logging.info('帖子数据:{}'.format(data['post_file'])) + else: + data['post_file'] = {} + raise postFile_Exception + # 识别结果返回值 + recognition_code = "0" + try: + user_data_otherInfo_1 = 0 if data["user_file"]["otherInfo"].strip() == "" else 1 + except: + user_data_otherInfo_1 = 0 + try: + user_data_nickName_2 = 0 if data["user_file"]["nickName"].strip() == "" else 1 + except: + user_data_nickName_2 = 0 + try: + user_data_fansCount_3 = int(data["user_file"]["fansCount"]) + except: + user_data_fansCount_3 = 0 + try: + user_data_likeCount_4 = int(data["user_file"]["likeCount"]) + except: + user_data_likeCount_4 = 0 + try: + user_data_postCount_5 = int(data["user_file"]["postCount"]) + except: + user_data_postCount_5 = 0 + try: + user_data_authentication_6 = int(data["user_file"]["authentication"]) + except: + user_data_authentication_6 = 0 + user_data.extend( + [user_data_otherInfo_1, user_data_nickName_2, user_data_fansCount_3, user_data_likeCount_4, + user_data_postCount_5, user_data_authentication_6]) + # 帖子数据 + if data["post_file"] == {}: + recognition_code = "-1" + else: + post_data = [] + try: + post_data_count_1 = int(data["post_file"]["count"]) + except: + post_data_count_1 = 0 + try: + post_data_LikeCount_2 = int(data["post_file"]["LikeCount"]) + except: + post_data_LikeCount_2 = 0 + try: + post_data_CommentsCount_3 = int(data["post_file"]["CommentsCount"]) + except: + post_data_CommentsCount_3 = 0 + try: + post_data_ShareCount_4 = int(data["post_file"]["ShareCount"]) + except: + post_data_ShareCount_4 = 0 + try: + post_data_length_5 = int(data["post_file"]["length"]) + except: + post_data_length_5 = 0 + try: + post_data_tags_6 = int(data["post_file"]["tags"]) + except: + post_data_tags_6 = 0 + try: + post_data_https_7 = int(data["post_file"]["https"]) + except: + post_data_https_7 = 0 + try: + post_data_at_8 = int(data["post_file"]["at"]) + except: + post_data_at_8 = 0 + try: + post_data_diffdate_9 = int(data["post_file"]["diffdate"]) + except: + post_data_diffdate_9 = 0 + post_data.extend( + [post_data_count_1, post_data_LikeCount_2, post_data_CommentsCount_3, post_data_ShareCount_4, + post_data_length_5, post_data_tags_6, post_data_https_7, post_data_at_8, post_data_diffdate_9]) + features = [user_data + post_data] + bot_user = joblib.load(cur_dir + "/model/bot_user.pkl") # 加载训练好的模型 + result = bot_user.predict(features) + recognition_code = str(result[0]) + # logging.info("预测模型结果为{}".format(result)) + results = {} + # 用户id + results['authorId'] = accountId + # 用户昵称 + results['nickName'] = nickName + # 用户账号 + results['accountName'] = accountName + #结束标识 + res['isLast'] = True + #数据类型 --目前只提供给图谱使用 + results['pageType'] = 'userAuthenPage' + if recognition_code == '0': + results['recognitionResult'] = '非机器人' + results['recognitionCode'] = recognition_code + elif recognition_code == '1': + results['recognitionResult'] = '机器人' + results['recognitionCode'] = recognition_code + else: + results['recognitionResult'] = '未知识别结果' + results['recognitionCode'] = recognition_code + results["isLast"]=1 + res['results'] = json.dumps(results) + res["status"]=1 + res["message"]="成功" + task["result"] = res + logging.info("增加预测数据-{}".format(task)) + to_kafka.send_kafka(task, logging) + except userFile_Exception: + res = {"successCode": "0", "errorLog": "用户数据为空!", "results": {}} + results = {} + results['authorId'] = "" + results['nickName'] = "" + results['accountName'] = "" + results['recognitionResult'] = '用户数据为空' + results["isLast"]=1 + res['results'] = json.dumps(results) + res["status"]=2 + res["message"]="用户数据为空" + task["result"] = res + logging.info("该条请求用户数据为空-{}".format(task)) + to_kafka.send_kafka(task, logging) + except postFile_Exception: + res = {"successCode": "0", "errorLog": "帖子数据为空!", "results": {}} + results = {} + results['authorId'] = accountId + results['nickName'] = nickName + results['accountName'] = accountName + results['recognitionResult'] = '帖子数据为空' + results["isLast"]=1 + res['results'] = json.dumps(results) + res["status"]=2 + res["message"]="帖子数据为空" + task["result"] = res + logging.info("该条请求帖子数据为空-{}".format(task)) + to_kafka.send_kafka(task, logging) + except: + res = {"successCode": "0", "errorLog": "", "results": {}} + results = {} + results['authorId'] = accountId + results['nickName'] = nickName + results['accountName'] = accountName + results['recognitionResult'] = "" + results["isLast"]=1 + res["results"] = json.dumps(results) + res["status"]=2 + res["message"]="异常" + task["result"] = res + task["result"]["error"] = traceback.format_exc() + logging.info(traceback.format_exc()) + to_kafka.send_kafka(task, logging) + +def data_structure(dbConfig): + ''' + 水军识别数据构造 + 主要是写入用户表、主贴表 + ''' + #获取数据库连接 + sqlhelper = get_conn_pool(dbConfig['host'],dbConfig['port'],dbConfig['username'],dbConfig['password'],dbConfig['db']) + #用户任务作为响应体 + send_task = None + while True: + try: + if task_queue.qsize()>0: + p,t,task = task_queue.get(timeout=1) + logging.info("当前任务队列长度{}".format(task_queue.qsize()+1)) + task_id=task["scenes_id"] + task_version=task["version"] + logging.info("当前version信息为:{}".format(stop_dict)) + if task_id in stop_dict.keys() and task_version!=stop_dict[task_id]["version"]: + logging.info("已暂停任务,数据过滤掉") + continue + + input = task['input'] + account = input['account'] + post = input['post'] + #判断数据类型 + data = task['data'] + page_type = None + taskId = None + for data_str in data: + try: + app_data = json.loads(data[data_str]) + taskId = app_data['taskId'] + if "pageType" in app_data: + page_type = app_data['pageType'] + break + except: + logging.error("正常判断,异常请忽略") + logging.info("数据类型:{}".format(page_type)) + if page_type == 'userInfoPage': + # 用户任务作为响应体 + send_task = task + #用户类型数据写入 + sql = "INSERT INTO `user_account`(`taskId`, `accountId`, `accountName`, `nickName`, `fansCount`, `likeCount`, `postCount`, `otherInfo`, `authentication`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" + # 构造参数元组 + values = ( + parse_data(task, account['taskId']), + parse_data(task, account['accountId']), + parse_data(task, account['accountName']), + parse_data(task, account['nickName']), + parse_data(task, account['fansCount']), + parse_data(task, account['likeCount']), + parse_data(task, account['postCount']), + parse_data(task, account['otherInfo']), + parse_data(task, account['authentication']) + ) + sqlhelper.insert(sql,values) + + elif page_type == 'storyDetailPage': + #帖子类型数据写入 + # 定义 SQL 语句 + sql = "INSERT INTO `user_post`(`taskId`, `postId`, `accountId`, `accountName`, `likeCount`, `emotionCount`, `commentsCount`, `shareCount`, `content`, `pubTime`, `crawlTime`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" + # 构造参数元组 + values = ( + parse_data(task, post['taskId']), + parse_data(task, post['postId']), + parse_data(task, post['accountId']), + parse_data(task, post['accountName']), + parse_data(task, post['likeCount']), + parse_data(task, post['emotionCount']), + parse_data(task, post['commentsCount']), + parse_data(task, post['shareCount']), + parse_data(task, post['content']), + parse_data(task, post['pubTime']), + parse_data(task, post['crawlTime']) + ) + sqlhelper.insert(sql,values) + #判断是否是此次数据流的最后一条,最后一条直接触发用户的水军识别算法 + if 'isLast'in data and data['isLast']: + #获取用户相关的数据 + sql = "select accountId,accountName,nickName,fansCount,likeCount,postCount,otherInfo,authentication from user_account where taskId ='{}'".format(taskId) + user_file_result = sqlhelper.queryOne(sql) + # 获取帖子相关的数据 + sql = "SELECT CONVERT(COUNT(postId), CHAR(255)) AS count, CONVERT(AVG(likeCount), CHAR(255)) AS LikeCount, CONVERT(AVG(commentsCount), CHAR(255)) AS CommentsCount, CONVERT(AVG(shareCount), CHAR(255)) AS ShareCount, CONVERT(AVG(LENGTH(content)), CHAR(255)) AS length, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, '#', ''))) / LENGTH('#')), CHAR(255)) AS tags, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, 'https', ''))) / LENGTH('https')), CHAR(255)) AS https, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, '@', ''))) / LENGTH('@')), CHAR(255)) AS at, CONVERT(MIN(TIMESTAMPDIFF(SECOND, pubTime, GREATEST(pubTime, crawlTime))), CHAR(255)) AS diffdate FROM user_post where taskId ='{}'".format(taskId) + post_file_result = sqlhelper.queryOne(sql) + if send_task == None: + send_task = task + predict(user_file_result,post_file_result,send_task) + #结束置空 + send_task = None + else: + # 暂无任务,进入休眠 + time.sleep(10) + except Exception as e: + traceback.print_exc() + + +def zk_monitoring(): + try: + #线上环境 + zk = KazooClient(hosts=config['zookeeper']['zkhost']) + #测试环境 + # zk = KazooClient(hosts='172.16.12.55:2181,172.16.12.56:2181,172.16.12.57:2181') + zk.start() + # 设置监听器 + @zk.DataWatch("/analyze") + def watch_node(data, stat, event): + if event is not None and event.type == EventType.CHANGED: + data, stat = zk.get("/analyze") + logging.info("执行删除操作:{}".format(data)) + d = json.loads(data) + id = d["scenes_id"] + stop_dict[id] = {} + stop_dict[id]["version"] = d["version"] + stop_dict[id]["operation"] = d["operation"] + # 保持程序运行以监听节点变化 + try: + while True: + time.sleep(1) + except: + logging.info("Stopping...") + # 关闭连接 + zk.stop() + zk.close() + except: + logging.error(traceback.format_exc()) + + +if __name__ == '__main__': + all_result = { + "9_获取用户发帖信息": "{\"resultList\": [{\"count\": \"10\", \"LikeCount\": \"1\", \"CommentsCount\": \"0.1\", \"ShareCount\": \"0.4\", \"length\": \"241.8000\", \"tags\": \"5.80000000\", \"https\": \"1.20000000\", \"at\": \"0.40000000\", \"diffdate\": \"170269\"}]}", + "8_获取用户信息": "{\"resultList\": [{\"accountId\": \"1368232444323799043\", \"accountName\": \"Ujjal best Tech@UjjalKumarGho19\", \"nickName\": \"UjjalKumarGho19\", \"fansCount\": \"660\", \"likeCount\": \"2096\", \"postCount\": \"579\", \"otherInfo\": \"\", \"authentication\": 1}]}"} + data = {} + # {"user_file": "9_获取用户信息", "post_file": "10_获取用户发帖信息"} + user_file_result = json.loads(all_result[data['user_file']]) + post_file_result = json.loads(all_result[data['post_file']]) + if user_file_result['resultList']: + resultList = user_file_result['resultList'] + data['user_file'] = resultList[0] + else: + data['user_file'] = {} + if post_file_result['resultList']: + data['post_file'] = post_file_result['resultList'][0] + else: + data['post_file'] = {} + + print(data) + + + + + + + diff --git a/text_analysis/views.py_20240920 b/text_analysis/views.py_20240920 new file mode 100644 index 0000000..53141af --- /dev/null +++ b/text_analysis/views.py_20240920 @@ -0,0 +1,340 @@ +# coding:utf8 +import os, sys +import io + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8') +cur_dir = os.path.dirname(os.path.abspath(__file__)) or os.getcwd() +par_dir = os.path.abspath(os.path.join(cur_dir, os.path.pardir)) +sys.path.append(cur_dir) +sys.path.append(par_dir) +import json +from django.http import HttpResponse +from text_analysis.tools import to_kafka +from django.views.decorators.csrf import csrf_exempt +from log_util.set_logger import set_logger +from text_analysis.tools.tool import parse_data +logging = set_logger('logs/results.log') +import traceback +import queue +import requests +import time +from datetime import datetime +import os +import joblib +from text_analysis.cusException import userFile_Exception, postFile_Exception + +# 任务队列 +global task_queue +task_queue = queue.Queue() + +#mysql连接池 +from text_analysis.tools.db_pool import get_conn_pool + +@csrf_exempt +def robotIdentification(request): + if request.method == 'POST': + try: + raw_data = json.loads(request.body) + task_queue.put(raw_data) + return HttpResponse(json.dumps({"code": 1, "msg": "请求正常!"}, ensure_ascii=False)) + except: + logging.error(traceback.format_exc()) + return HttpResponse(json.dumps({"code": 0, "msg": "请求json格式不正确!"}, ensure_ascii=False)) + else: + return HttpResponse(json.dumps({"code": 0, "msg": "请求方式错误,改为post请求"}, ensure_ascii=False)) + + +def predict(user_file_result,post_file_result,task): + try: + # raw_data = {"user_file": {"accountId": "39234393", "accountName": "hello", "nickName": "Johnson Leung", + # "fansCount": 308, "likeCount": 92707, "postCount": 14237, + # "otherInfo": "{\"\"otherInfo\"\":\"\"{\"\"bio\"\": \"\"Huge}", + # "authentication": 0}, + # "post_file": {"count": 1, "LikeCount": 12, "CommentsCount": 1, "ShareCount": 1, + # "length": 150, "tags": 0, "https": 0, "at": 0, "diffdate": 1}} + # 用户数据 + res = {"successCode": "1", "errorLog": "", "results": {}} + user_data = [] + # 返回值需要的三个字段 + accountId = "" + nickName = "" + accountName = "" + data = {} + if user_file_result: + data['user_file'] = user_file_result + logging.info('用户数据:{}'.format(data['user_file'])) + accountId = data["user_file"]["accountId"] + nickName = data["user_file"]["nickName"] + accountName = data["user_file"]["accountName"] + else: + data['user_file'] = {} + raise userFile_Exception + if post_file_result: + data['post_file'] = post_file_result + logging.info('帖子数据:{}'.format(data['post_file'])) + else: + data['post_file'] = {} + raise postFile_Exception + # 识别结果返回值 + recognition_code = "0" + try: + user_data_otherInfo_1 = 0 if data["user_file"]["otherInfo"].strip() == "" else 1 + except: + user_data_otherInfo_1 = 0 + try: + user_data_nickName_2 = 0 if data["user_file"]["nickName"].strip() == "" else 1 + except: + user_data_nickName_2 = 0 + try: + user_data_fansCount_3 = int(data["user_file"]["fansCount"]) + except: + user_data_fansCount_3 = 0 + try: + user_data_likeCount_4 = int(data["user_file"]["likeCount"]) + except: + user_data_likeCount_4 = 0 + try: + user_data_postCount_5 = int(data["user_file"]["postCount"]) + except: + user_data_postCount_5 = 0 + try: + user_data_authentication_6 = int(data["user_file"]["authentication"]) + except: + user_data_authentication_6 = 0 + user_data.extend( + [user_data_otherInfo_1, user_data_nickName_2, user_data_fansCount_3, user_data_likeCount_4, + user_data_postCount_5, user_data_authentication_6]) + # 帖子数据 + if data["post_file"] == {}: + recognition_code = "-1" + else: + post_data = [] + try: + post_data_count_1 = int(data["post_file"]["count"]) + except: + post_data_count_1 = 0 + try: + post_data_LikeCount_2 = int(data["post_file"]["LikeCount"]) + except: + post_data_LikeCount_2 = 0 + try: + post_data_CommentsCount_3 = int(data["post_file"]["CommentsCount"]) + except: + post_data_CommentsCount_3 = 0 + try: + post_data_ShareCount_4 = int(data["post_file"]["ShareCount"]) + except: + post_data_ShareCount_4 = 0 + try: + post_data_length_5 = int(data["post_file"]["length"]) + except: + post_data_length_5 = 0 + try: + post_data_tags_6 = int(data["post_file"]["tags"]) + except: + post_data_tags_6 = 0 + try: + post_data_https_7 = int(data["post_file"]["https"]) + except: + post_data_https_7 = 0 + try: + post_data_at_8 = int(data["post_file"]["at"]) + except: + post_data_at_8 = 0 + try: + post_data_diffdate_9 = int(data["post_file"]["diffdate"]) + except: + post_data_diffdate_9 = 0 + post_data.extend( + [post_data_count_1, post_data_LikeCount_2, post_data_CommentsCount_3, post_data_ShareCount_4, + post_data_length_5, post_data_tags_6, post_data_https_7, post_data_at_8, post_data_diffdate_9]) + features = [user_data + post_data] + bot_user = joblib.load(cur_dir + "/model/bot_user.pkl") # 加载训练好的模型 + result = bot_user.predict(features) + recognition_code = str(result[0]) + # logging.info("预测模型结果为{}".format(result)) + results = {} + # 用户id + results['authorId'] = accountId + # 用户昵称 + results['nickName'] = nickName + # 用户账号 + results['accountName'] = accountName + #结束标识 + res['isLast'] = True + #数据类型 --目前只提供给图谱使用 + results['pageType'] = 'userAuthenPage' + if recognition_code == '0': + results['recognitionResult'] = '非机器人' + results['recognitionCode'] = recognition_code + elif recognition_code == '1': + results['recognitionResult'] = '机器人' + results['recognitionCode'] = recognition_code + else: + results['recognitionResult'] = '未知识别结果' + results['recognitionCode'] = recognition_code + results["isLast"]=1 + res['results'] = json.dumps(results) + res["status"]=1 + res["message"]="成功" + task["result"] = res + logging.info("增加预测数据-{}".format(task)) + to_kafka.send_kafka(task, logging) + except userFile_Exception: + res = {"successCode": "0", "errorLog": "用户数据为空!", "results": {}} + results = {} + results['authorId'] = "" + results['nickName'] = "" + results['accountName'] = "" + results['recognitionResult'] = '用户数据为空' + results["isLast"]=1 + res['results'] = json.dumps(results) + res["status"]=2 + res["message"]="用户数据为空" + task["result"] = res + logging.info("该条请求用户数据为空-{}".format(task)) + to_kafka.send_kafka(task, logging) + except postFile_Exception: + res = {"successCode": "0", "errorLog": "帖子数据为空!", "results": {}} + results = {} + results['authorId'] = accountId + results['nickName'] = nickName + results['accountName'] = accountName + results['recognitionResult'] = '帖子数据为空' + results["isLast"]=1 + res['results'] = json.dumps(results) + res["status"]=2 + res["message"]="帖子数据为空" + task["result"] = res + logging.info("该条请求帖子数据为空-{}".format(task)) + to_kafka.send_kafka(task, logging) + except: + res = {"successCode": "0", "errorLog": "", "results": {}} + results = {} + results['authorId'] = accountId + results['nickName'] = nickName + results['accountName'] = accountName + results['recognitionResult'] = "" + results["isLast"]=1 + res["results"] = json.dumps(results) + res["status"]=2 + res["message"]="异常" + task["result"] = res + task["result"]["error"] = traceback.format_exc() + logging.info(traceback.format_exc()) + to_kafka.send_kafka(task, logging) + +def data_structure(dbConfig): + ''' + 水军识别数据构造 + 主要是写入用户表、主贴表 + ''' + #获取数据库连接 + sqlhelper = get_conn_pool(dbConfig['host'],dbConfig['port'],dbConfig['username'],dbConfig['password'],dbConfig['db']) + #用户任务作为响应体 + send_task = None + while True: + if task_queue.qsize() > 0: + try: + logging.info("队列长度:{}".format(task_queue.qsize())) + task = task_queue.get() + input = task['input'] + account = input['account'] + post = input['post'] + #判断数据类型 + data = task['data'] + page_type = None + taskId = None + app_data = None + for data_str in data: + try: + app_data = json.loads(data[data_str]) + taskId = app_data['taskId'] + if "pageType" in app_data: + page_type = app_data['pageType'] + break + except: + logging.error("正常判断,异常请忽略") + logging.info("数据类型:{}".format(page_type)) + if page_type == 'userInfoPage': + # 用户任务作为响应体 + send_task = task + #用户类型数据写入 + sql = "INSERT INTO `user_account`(`taskId`, `accountId`, `accountName`, `nickName`, `fansCount`, `likeCount`, `postCount`, `otherInfo`, `authentication`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" + # 构造参数元组 + values = ( + parse_data(task, account['taskId']), + parse_data(task, account['accountId']), + parse_data(task, account['accountName']), + parse_data(task, account['nickName']), + parse_data(task, account['fansCount']), + parse_data(task, account['likeCount']), + parse_data(task, account['postCount']), + parse_data(task, account['otherInfo']), + parse_data(task, account['authentication']) + ) + sqlhelper.insert(sql,values) + + elif page_type == 'storyDetailPage': + #帖子类型数据写入 + # 定义 SQL 语句 + sql = "INSERT INTO `user_post`(`taskId`, `postId`, `accountId`, `accountName`, `likeCount`, `emotionCount`, `commentsCount`, `shareCount`, `content`, `pubTime`, `crawlTime`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" + # 构造参数元组 + values = ( + parse_data(task, post['taskId']), + parse_data(task, post['postId']), + parse_data(task, post['accountId']), + parse_data(task, post['accountName']), + parse_data(task, post['likeCount']), + parse_data(task, post['emotionCount']), + parse_data(task, post['commentsCount']), + parse_data(task, post['shareCount']), + parse_data(task, post['content']), + parse_data(task, post['pubTime']), + parse_data(task, post['crawlTime']) + ) + sqlhelper.insert(sql,values) + #判断是否是此次数据流的最后一条,最后一条直接触发用户的水军识别算法 + if 'isLast'in app_data: + #获取用户相关的数据 + sql = "select accountId,accountName,nickName,fansCount,likeCount,postCount,otherInfo,authentication from user_account where taskId ='{}'".format(taskId) + user_file_result = sqlhelper.queryOne(sql) + # 获取帖子相关的数据 + sql = "SELECT CONVERT(COUNT(postId), CHAR(255)) AS count, CONVERT(AVG(likeCount), CHAR(255)) AS LikeCount, CONVERT(AVG(commentsCount), CHAR(255)) AS CommentsCount, CONVERT(AVG(shareCount), CHAR(255)) AS ShareCount, CONVERT(AVG(LENGTH(content)), CHAR(255)) AS length, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, '#', ''))) / LENGTH('#')), CHAR(255)) AS tags, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, 'https', ''))) / LENGTH('https')), CHAR(255)) AS https, CONVERT(AVG((LENGTH(content) - LENGTH(REPLACE(content, '@', ''))) / LENGTH('@')), CHAR(255)) AS at, CONVERT(MIN(TIMESTAMPDIFF(SECOND, pubTime, GREATEST(pubTime, crawlTime))), CHAR(255)) AS diffdate FROM user_post where taskId ='{}'".format(taskId) + post_file_result = sqlhelper.queryOne(sql) + if send_task == None: + send_task = task + predict(user_file_result,post_file_result,send_task) + #结束置空 + send_task = None + except Exception as e: + traceback.print_exc() + else: + # 暂无任务,进入休眠 + time.sleep(10) +if __name__ == '__main__': + all_result = { + "9_获取用户发帖信息": "{\"resultList\": [{\"count\": \"10\", \"LikeCount\": \"1\", \"CommentsCount\": \"0.1\", \"ShareCount\": \"0.4\", \"length\": \"241.8000\", \"tags\": \"5.80000000\", \"https\": \"1.20000000\", \"at\": \"0.40000000\", \"diffdate\": \"170269\"}]}", + "8_获取用户信息": "{\"resultList\": [{\"accountId\": \"1368232444323799043\", \"accountName\": \"Ujjal best Tech@UjjalKumarGho19\", \"nickName\": \"UjjalKumarGho19\", \"fansCount\": \"660\", \"likeCount\": \"2096\", \"postCount\": \"579\", \"otherInfo\": \"\", \"authentication\": 1}]}"} + data = {} + # {"user_file": "9_获取用户信息", "post_file": "10_获取用户发帖信息"} + user_file_result = json.loads(all_result[data['user_file']]) + post_file_result = json.loads(all_result[data['post_file']]) + if user_file_result['resultList']: + resultList = user_file_result['resultList'] + data['user_file'] = resultList[0] + else: + data['user_file'] = {} + if post_file_result['resultList']: + data['post_file'] = post_file_result['resultList'][0] + else: + data['post_file'] = {} + + print(data) + + + + + + + diff --git a/text_analysis/wsgi.py b/text_analysis/wsgi.py new file mode 100644 index 0000000..36735ac --- /dev/null +++ b/text_analysis/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for Zhijian_Project_WebService project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "text_analysis.settings") + +application = get_wsgi_application() diff --git a/txt/postData-user.txt b/txt/postData-user.txt new file mode 100644 index 0000000..e040ac4 --- /dev/null +++ b/txt/postData-user.txt @@ -0,0 +1,85 @@ +{ + "metadata":{ + "address":"http://172.24.12.127:9020/robotIdentification/", + "index":0, + "admin":{ + "user_file":{ + "accountId":"39234393", + "accountName":"hello", + "nickName":"Johnson Leung", + "fansCount":308, + "likeCount":92707, + "postCount":14237, + "otherInfo":"{\"\"otherInfo\"\":\"\"{\"\"bio\"\": \"\"Huge}", + "authentication":0 + }, + "post_file":{ + "count":1, + "LikeCount":12, + "CommentsCount":1, + "ShareCount":1, + "length":150, + "tags":0, + "https":0, + "at":0, + "diffdate":1 + } + } + }, + "output":{ + "output_type":"table", + "label_col":[ + + ] + }, + "input":{ + "input_type":"text", + "label":[ + "2_任务提取" + ] + }, + "user":{ + "tag":"" + }, + "data":{ + + }, + "created":1691004265000, + "module":"robotIdentification", + "start_tag":false, + "multi_branch":0, + "last_edit":1693417201000, + "next_app_id":[ + { + "start_id":154, + "edge_id":75, + "end_id":155 + } + ], + "transfer_id":3, + "version":1, + "blueprint_id":4, + "scenes_id":5, + "scenario":{ + "dataloss":1, + "autoCommitTriggerLast":1, + "maxErrors":3, + "autoCommit":1, + "freshVariables":1 + }, + "wait_condition":[ + + ], + "scheduling":{ + "interval":-1, + "type":"single" + }, + "name":"robotIdentification", + "businessKey":"19615b029da477fb", + "id":154, + "position":[ + 100, + 200 + ], + "describe":"" +} \ No newline at end of file diff --git a/uwsgi.ini b/uwsgi.ini new file mode 100644 index 0000000..22e8b76 --- /dev/null +++ b/uwsgi.ini @@ -0,0 +1,8 @@ +[uwsgi] +http = 0.0.0.0:9020 +chdir = ../robotIdentification +wsgi-file = ../robotIdentificationi/wsgi.py +processes = 1 +threads = 2 +listen = 1024 +http-timeout=21600 diff --git a/wsgi.log b/wsgi.log new file mode 100644 index 0000000..93c076c --- /dev/null +++ b/wsgi.log @@ -0,0 +1,86 @@ +*** Starting uWSGI 2.0.21 (64bit) on [Fri Jan 3 10:55:42 2025] *** +compiled with version: 11.2.0 on 24 October 2023 19:53:56 +os: Linux-3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 +nodename: node-04 +machine: x86_64 +clock source: unix +pcre jit disabled +detected number of CPU cores: 64 +current working directory: /opt/analyze/apps/robotIdentification +detected binary path: /opt/analyze/environment/python3.8/bin/uwsgi +uWSGI running as root, you can use --uid/--gid/--chroot options +*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** +chdir() to ../robotIdentification +*** WARNING: you are running uWSGI without its master process manager *** +your processes number limit is 1031041 +your memory page size is 4096 bytes +detected max file descriptor number: 65535 +lock engine: pthread robust mutexes +thunder lock: disabled (you can enable it with --thunder-lock) +uWSGI http bound on 0.0.0.0:9020 fd 4 +spawned uWSGI http 1 (pid: 59163) +uwsgi socket 0 bound to TCP address 127.0.0.1:33452 (port auto-assigned) fd 3 +uWSGI running as root, you can use --uid/--gid/--chroot options +*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** +Python version: 3.8.16 (default, Jun 12 2023, 18:09:05) [GCC 11.2.0] +Python main interpreter initialized at 0x2277240 +uWSGI running as root, you can use --uid/--gid/--chroot options +*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** +python threads support enabled +your server socket listen backlog is limited to 1024 connections +your mercy for graceful operations on workers is 60 seconds +mapped 83376 bytes (81 KB) for 2 cores +*** Operational MODE: threaded *** +Exception in thread dataStructureThread: +Traceback (most recent call last): + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/PooledDB.py", line 325, in connection + con = self._idle_cache.pop(0) +IndexError: pop from empty list + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/opt/analyze/environment/python3.8/lib/python3.8/threading.py", line 932, in _bootstrap_inner + self.run() + File "/opt/analyze/environment/python3.8/lib/python3.8/threading.py", line 870, in run + self._target(*self._args, **self._kwargs) + File "/opt/analyze/apps/robotIdentification/./text_analysis/views.py", line 237, in data_structure + sqlhelper = get_conn_pool(dbConfig['host'],dbConfig['port'],dbConfig['username'],dbConfig['password'],dbConfig['db']) + File "/opt/analyze/apps/robotIdentification/./text_analysis/tools/db_pool.py", line 105, in get_conn_pool + sqlhelper = MySQLUtils(host, port, username, password, db) + File "/opt/analyze/apps/robotIdentification/./text_analysis/tools/db_pool.py", line 11, in __init__ + self.pool = PooledDB( + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/PooledDB.py", line 267, in __init__ + idle = [self.dedicated_connection() for i in range(mincached)] + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/PooledDB.py", line 267, in + idle = [self.dedicated_connection() for i in range(mincached)] + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/PooledDB.py", line 338, in dedicated_connection + return self.connection(False) + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/PooledDB.py", line 327, in connection + con = self.steady_connection() + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/PooledDB.py", line 273, in steady_connection + return connect( + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/SteadyDB.py", line 137, in connect + return SteadyDBConnection( + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/SteadyDB.py", line 192, in __init__ + self._store(self._create()) + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/DBUtils/SteadyDB.py", line 211, in _create + con = self._creator(*self._args, **self._kwargs) + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/pymysql/connections.py", line 358, in __init__ + self.connect() + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/pymysql/connections.py", line 664, in connect + self._request_authentication() + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/pymysql/connections.py", line 954, in _request_authentication + auth_packet = self._read_packet() + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/pymysql/connections.py", line 772, in _read_packet + packet.raise_for_error() + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/pymysql/protocol.py", line 221, in raise_for_error + err.raise_mysql_exception(self._data) + File "/opt/analyze/environment/python3.8/lib/python3.8/site-packages/pymysql/err.py", line 143, in raise_mysql_exception + raise errorclass(errno, errval) +pymysql.err.OperationalError: (1049, "Unknown database 'analyze'") +WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x2277240 pid: 59162 (default app) +uWSGI running as root, you can use --uid/--gid/--chroot options +*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** +*** uWSGI is running in multiple interpreter mode *** +spawned uWSGI worker 1 (and the only) (pid: 59162, cores: 2) diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..ece382c --- /dev/null +++ b/wsgi.py @@ -0,0 +1,36 @@ +""" +WSGI config for Zhijian_Project_WebService project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ +""" + +import os +import configparser +import threading +from text_analysis.views import predict +from text_analysis.views import data_structure + +#加载配置文件 +configFile = './config.ini' +# 创建配置文件对象 +con = configparser.ConfigParser() +# 读取文件 +con.read(configFile, encoding='utf-8') +dbConfig = dict(con.items('database'))#数据库配置信息 + +#开启数据入库线程 +t = threading.Thread(target=data_structure, name='dataStructureThread',args=(dbConfig,)) +t.daemon = True +t.start() + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "text_analysis.settings") +application = get_wsgi_application() + + + +