{"id":440,"date":"2018-03-14T16:21:26","date_gmt":"2018-03-14T08:21:26","guid":{"rendered":"http:\/\/www.max-shu.com\/blog\/?p=440"},"modified":"2018-03-14T16:21:26","modified_gmt":"2018-03-14T08:21:26","slug":"%e4%bd%bf%e7%94%a8python-tornado%e5%ae%9e%e7%8e%b0%e5%be%ae%e4%bf%a1%e5%85%ac%e4%bc%97%e5%8f%b7%e5%ae%9e%e4%be%8b","status":"publish","type":"post","link":"http:\/\/www.max-shu.com\/blog\/?p=440","title":{"rendered":"\u4f7f\u7528python tornado\u5b9e\u73b0\u5fae\u4fe1\u516c\u4f17\u53f7\u5b9e\u4f8b"},"content":{"rendered":"<div>\u5b9e\u73b0\u51e0\u4e2a\u5fc5\u987b\u529f\u80fd\u7684\u4f8b\u5b50\uff0c\u79bb\u5b9e\u7528\u8fdc\u7740\u5462\uff1a<\/div>\n<div>main.py\uff1a<\/div>\n<div>\n<pre>#!\/usr\/bin\/python\r\n#-*- encoding:utf-8 -*-\r\n\r\n'''\r\n\u9700\u8981\u5b89\u88c5\uff1a\r\n$ sudo yum install python-devel\r\n$ tar -zxvf pycrypto-2.6.1.tar.gz\r\n$ cd pycrypto-2.6.1\r\n$ sudo python setup.py build\r\n$ sudo python setup.py install\r\n$ sudo yum install libxml2-devel\r\n$ sudo yum install libxml2-python\r\n$ sudo yum install libxml++-devel\r\n$ sudo yum install libxslt-devel\r\n$ sudo pip install lxml\r\n$ sudo pip install requests\r\n\u540e\u53f0\u8fd0\u884c\uff1a\r\n$ sudo bash -c 'nohup python .\/main.py &amp;'\r\n'''\r\n\r\nimport os.path\r\nimport platform\r\nimport hashlib\r\nimport time\r\nimport sys\r\nimport importlib\r\nimport urllib2\r\nimport requests\r\nimport mimetypes\r\nimport io\r\nimport json\r\n# from xml.etree import cElementTree as ETree\r\nimport lxml.etree as ETree\r\n# import torndb\r\nimport tornado.httpserver\r\nimport tornado.web\r\nimport tornado.ioloop\r\nimport tornado.options\r\nimport tornado.template\r\n\r\nfrom tornado.options import define, options\r\n\r\nimport global_define\r\nimport access_token\r\nfrom encrypt_WeiXin.WXBizMsgCrypt import WXBizMsgCrypt\r\n\r\nSYS_PLATFORM = platform.system()\r\n\r\ndefine(\"port\", default=80, help=\"run port\", type=int) # \u5fae\u4fe1\u53ea\u652f\u630180\u7aef\u53e3\r\n'''\r\ndefine(\"mysql_host\", default=\"127.0.0.1:3306\", help=\"db host\")\r\ndefine(\"mysql_database\", default=\"todo\", help=\"db name\")\r\ndefine(\"mysql_user\", default=\"root\", help=\"db user\")\r\ndefine(\"mysql_password\", default=\"\", help=\"db password\")\r\n'''\r\n\r\nTEMPLATE_PATH = os.path.join(os.path.dirname(__file__), \"templates\")\r\nSTATIC_PATH = os.path.join(os.path.dirname(__file__), \"static\")\r\n\r\nclass Application(tornado.web.Application):\r\n    def __init__(self):\r\n        handlers = [\r\n            (r\"\/\", IndexHandler),\r\n            (r\"\/todo\/new\", NewHandler),\r\n            (r\"\/todo\/(\\d+)\/edit\", EditHandler),\r\n        ]\r\n        if SYS_PLATFORM == \"Windows\":\r\n            settings = dict(\r\n                template_path = TEMPLATE_PATH,\r\n                static_path = STATIC_PATH,\r\n                debug = True # debug \u548c autoreload \u6a21\u5f0f\u4e0b\u4e0d\u80fd\u542f\u7528\u591a\u8fdb\u7a0b\u65b9\u5f0f\uff08\u542f\u52a8debug\uff0c\u81ea\u52a8autoreload\uff09\r\n            )\r\n        else:\r\n            settings = dict(\r\n                template_path = TEMPLATE_PATH,\r\n                static_path = STATIC_PATH,\r\n            )\r\n        tornado.web.Application.__init__(self, handlers, **settings)\r\n'''\r\n        self.db = torndb.Connection(\r\n            host = options.mysql_host,\r\n            database = options.mysql_database,\r\n            user = options.mysql_user,\r\n            password = options.mysql_password\r\n        )\r\n'''\r\n\r\nclass IndexHandler(tornado.web.RequestHandler):\r\n    def get(self): #  \u9a8c\u8bc1\u5f00\u53d1\u63a5\u53e3\uff0c\u53c2\u8003 http:\/\/mp.weixin.qq.com\/wiki\/17\/2d4265491f12608cd170a95559800f2d.html\r\n        self.set_header(\"Server\", \"Car Ocean\")\r\n        self.set_header(\"X-Powered-By\", \"Car Ocean\")\r\n        token = global_define.TOKEN\r\n        signatures = self.get_arguments(\"signature\")\r\n        if len(signatures) == 0:\r\n            print(\"INFO: GET operation, need 'signature' parameter\")\r\n            return\r\n        signature = self.get_arguments(\"signature\")[0]\r\n        timestamp = self.get_arguments(\"timestamp\")[0]\r\n        nonce = self.get_arguments(\"nonce\")[0]\r\n        echostr = self.get_arguments(\"echostr\")[0]\r\n        sortlist = [token, timestamp, nonce]\r\n        sortlist.sort()\r\n        shaStr = \"\".join(sortlist)\r\n        sha = hashlib.sha1(shaStr)\r\n#        sha.update(\"\".join(sortlist))\r\n        calculate_signature = sha.hexdigest()\r\n        print(\"token:     %s\" % token)\r\n        print(\"timestamp: %s\" % timestamp)\r\n        print(\"nonce:     %s\" % nonce)\r\n        print(\"echostr:   %s\" % echostr)\r\n        print(\"getted    signature: %s\" % signature)\r\n        print(\"calculate signature: %s\" % calculate_signature)\r\n        if calculate_signature == signature:\r\n            self.write(echostr)\r\n        else:\r\n            todos = ['ERROR', 'bbb']\r\n            self.render(\"index.html\", todos=todos)\r\n\r\n    def post(self):\r\n        self.set_header(\"Server\", \"Car Ocean\")\r\n        self.set_header(\"X-Powered-By\", \"Car Ocean\")\r\n        body = self.request.body\r\n        print(\"Thread(Main), Time: %s, DEBUG: body: \\n%s\" % (time.ctime(), body))\r\n        encrypt_typeList = self.get_arguments(\"encrypt_type\")\r\n        msg_signature = \"\"\r\n        timestamp = \"\"\r\n        nonce = \"\"\r\n        if len(encrypt_typeList) == 0:\r\n            print(\"Thread(Main), Time: %s, INFO: is not crypt message\" % (time.ctime()))\r\n            xmlData = ETree.fromstring(body)\r\n            encrypt_type = \"raw\"\r\n        else:\r\n            encrypt_type = self.get_arguments(\"encrypt_type\")[0]\r\n            if encrypt_type == \"raw\":\r\n                print(\"Thread(Main), Time: %s, INFO: is not crypt message\" % (time.ctime()))\r\n                xmlData = ETree.fromstring(body)\r\n            elif encrypt_type == \"aes\":\r\n                print(\"Thread(Main), Time: %s, INFO: aes crypt message\" % (time.ctime()))\r\n                msg_signature = self.get_arguments(\"msg_signature\")[0]\r\n                timestamp = self.get_arguments(\"timestamp\")[0]\r\n                nonce = self.get_arguments(\"nonce\")[0]\r\n                wxBizMsgCrypt = WXBizMsgCrypt(global_define.TOKEN, global_define.EncodingAESKey, global_define.APPID)\r\n                ret , decryptBody = wxBizMsgCrypt.DecryptMsg(body, msg_signature, timestamp, nonce)\r\n                print(\"Thread(Main), Time: %s, DEBUG: decrypt body: %s\" % (time.ctime(), decryptBody))\r\n                print(\"Thread(Main), Time: %s, DEBUG: msg_signature: %s\" % (time.ctime(), msg_signature))\r\n                print(\"Thread(Main), Time: %s, DEBUG: timestamp: %s\" % (time.ctime(), timestamp))\r\n                print(\"Thread(Main), Time: %s, DEBUG: nonce: %s\" % (time.ctime(), nonce))\r\n                xmlData = ETree.fromstring(decryptBody)\r\n            else:\r\n                print(\"Thread(Main), Time: %s, ERROR: not support encrypt_type: %s\" % (time.ctime(), encrypt_type))\r\n                xmlData = \"\"\r\n        if not xmlData == \"\":\r\n            toUserName = xmlData.find(\"ToUserName\").text\r\n            print(\"Thread(Main), Time: %s, DEBUG: ToUserName : %s\" % (time.ctime(), toUserName))\r\n            fromUserName = xmlData.find(\"FromUserName\").text\r\n            print(\"Thread(Main), Time: %s, DEBUG: FromUserName : %s\" % (time.ctime(), fromUserName))\r\n            createTime = xmlData.find(\"CreateTime\").text\r\n            print(\"Thread(Main), Time: %s, DEBUG: CreateTime : %s\" % (time.ctime(), createTime))\r\n            msgType = xmlData.find(\"MsgType\").text\r\n            print(\"Thread(Main), Time: %s, DEBUG: MsgType : %s\" % (time.ctime(), msgType))\r\n            if( msgType == \"event\" ):\r\n                event = xmlData.find(\"Event\").text\r\n                print(\"Thread(Main), Time: %s, DEBUG: Event : %s\" % (time.ctime(), event))\r\n                if event == \"subscribe\":\r\n                    self.Subscribe(encrypt_type, toUserName, fromUserName, createTime)\r\n                elif event == \"unsubscribe\":\r\n                    self.Unsubscribe()\r\n                elif event == \"CLICK\":\r\n                    eventKey = xmlData.find(\"EventKey\").text\r\n                    print(\"Thread(Main), Time: %s, DEBUG: EventKey : %s\" % (time.ctime(), eventKey))\r\n                    self.MenuClick(encrypt_type, toUserName, fromUserName, createTime,  eventKey)\r\n                else:\r\n                    self.write(\"\")\r\n            if (msgType == \"text\"):\r\n                Content = xmlData.find(\"Content\").text\r\n                print(\"Thread(Main), Time: %s, DEBUG: Content : %s\" % (time.ctime(), Content))\r\n                MsgId = xmlData.find(\"MsgId\").text\r\n                print(\"Thread(Main), Time: %s, DEBUG: MsgId : %s\" % (time.ctime(), MsgId))\r\n                if Content == \"1\":\r\n                    self.RecvTextMsg1(encrypt_type, toUserName, fromUserName, createTime, Content, MsgId)\r\n                elif Content == \"2\":\r\n                    self.RecvTextMsg2(encrypt_type, toUserName, fromUserName, createTime, Content, MsgId)\r\n                else:\r\n                    self.write(\"\")\r\n\r\n    def MenuClick(self, msgEncrypt_type, msgToUserName, msgFromUserName, msgCreateTime,  msgEventKey):\r\n        # \u751f\u6210\u672a\u52a0\u5bc6\u539f\u59cbxml\u6d88\u606f\r\n        xmlRoot = ETree.Element(\"xml\")\r\n        toUserName = ETree.SubElement(xmlRoot, 'ToUserName')\r\n        toUserName.text = ETree.CDATA(msgFromUserName)\r\n        fromUserName = ETree.SubElement(xmlRoot, 'FromUserName')\r\n        fromUserName.text = ETree.CDATA(msgToUserName)\r\n        createTime = ETree.SubElement(xmlRoot, 'CreateTime')\r\n        createTime.text = msgCreateTime\r\n        msgType = ETree.SubElement(xmlRoot, 'MsgType')\r\n        msgType.text = ETree.CDATA(\"text\")\r\n        content = ETree.SubElement(xmlRoot, 'Content')\r\n        content.text = ETree.CDATA(u\"\u70b9\u51fb\u4e86\u83dc\u5355\uff1a\"+msgEventKey)  #\u6ce8\u610f\u5728xml\u4e2d\u7684\u4e2d\u6587\u9700\u8981\u4f7f\u7528unicode\u65b9\u5f0f\r\n        xmlData = ETree.tostring(xmlRoot, encoding=\"utf-8\")\r\n        print(\"Thread(Main), Time: %s, DEBUG: Return original message : \\n%s\" % (time.ctime(), xmlData))\r\n        # \u52a0\u5bc6\u5904\u7406\r\n        if (msgEncrypt_type == \"raw\"):\r\n            self.write(xmlData)\r\n        else:\r\n            nonce = str(int(time.time()))\r\n            wxBizMsgCrypt = WXBizMsgCrypt(global_define.TOKEN, global_define.EncodingAESKey, global_define.APPID)\r\n            ret, encryptBody = wxBizMsgCrypt.EncryptMsg(xmlData, nonce)\r\n            if ret != 0:\r\n                print(\"Thread(Main), Time: %s, ERROR: EncryptMsg error : %d\" % (time.ctime(), ret))\r\n                self.write(\"\")\r\n            xmlData = encryptBody\r\n            print(\"Thread(Main), Time: %s, DEBUG: Return encrypted message : \\n%s\" % (time.ctime(), xmlData))\r\n            self.set_header('Content-Type', 'text\/xml; encoding=utf-8')\r\n            self.write(xmlData)\r\n\r\n    def RecvTextMsg1(self, msgEncrypt_type, msgToUserName, msgFromUserName, msgCreateTime, msgContent, msgMsgId):\r\n        # \u751f\u6210\u672a\u52a0\u5bc6\u539f\u59cbxml\u6d88\u606f\r\n        xmlRoot = ETree.Element(\"xml\")\r\n        toUserName = ETree.SubElement(xmlRoot, 'ToUserName')\r\n        toUserName.text = ETree.CDATA(msgFromUserName)\r\n        fromUserName = ETree.SubElement(xmlRoot, 'FromUserName')\r\n        fromUserName.text = ETree.CDATA(msgToUserName)\r\n        createTime = ETree.SubElement(xmlRoot, 'CreateTime')\r\n        createTime.text = msgCreateTime\r\n        msgType = ETree.SubElement(xmlRoot, 'MsgType')\r\n        msgType.text = ETree.CDATA(\"text\")\r\n        content = ETree.SubElement(xmlRoot, 'Content')\r\n        content.text = ETree.CDATA(u\"\u60a8\u8ba2\u9605\u6210\u529f\uff01\")\r\n        xmlData = ETree.tostring(xmlRoot, encoding=\"utf-8\")\r\n        print(\"Thread(Main), Time: %s, DEBUG: Return original message : \\n%s\" % (time.ctime(), xmlData))\r\n        # \u52a0\u5bc6\u5904\u7406\r\n        if (msgEncrypt_type == \"raw\"):\r\n            self.write(xmlData)\r\n        else:\r\n            nonce = str(int(time.time()))\r\n            wxBizMsgCrypt = WXBizMsgCrypt(global_define.TOKEN, global_define.EncodingAESKey, global_define.APPID)\r\n            ret, encryptBody = wxBizMsgCrypt.EncryptMsg(xmlData, nonce)\r\n            if ret != 0:\r\n                print(\"Thread(Main), Time: %s, ERROR: EncryptMsg error : %d\" % (time.ctime(), ret))\r\n                self.write(\"\")\r\n            xmlData = encryptBody\r\n            print(\"Thread(Main), Time: %s, DEBUG: Return encrypted message : \\n%s\" % (time.ctime(), xmlData))\r\n            self.set_header('Content-Type', 'text\/xml; encoding=utf-8')\r\n            self.write(xmlData)\r\n\r\n    def RecvTextMsg2(self, msgEncrypt_type, msgToUserName, msgFromUserName, msgCreateTime, msgContent, msgMsgId):\r\n        # \u751f\u6210\u672a\u52a0\u5bc6\u539f\u59cbxml\u6d88\u606f\r\n        xmlRoot = ETree.Element(\"xml\")\r\n        toUserName = ETree.SubElement(xmlRoot, 'ToUserName')\r\n        toUserName.text = ETree.CDATA(msgFromUserName)\r\n        fromUserName = ETree.SubElement(xmlRoot, 'FromUserName')\r\n        fromUserName.text = ETree.CDATA(msgToUserName)\r\n        createTime = ETree.SubElement(xmlRoot, 'CreateTime')\r\n        createTime.text = msgCreateTime\r\n        msgType = ETree.SubElement(xmlRoot, 'MsgType')\r\n        msgType.text = ETree.CDATA(\"news\")\r\n        articleCount = ETree.SubElement(xmlRoot, 'ArticleCount')\r\n        articleCount.text = \"1\"\r\n        articles = ETree.SubElement(xmlRoot, 'Articles')\r\n        item = ETree.SubElement(articles, 'item')\r\n        title = ETree.SubElement(item, 'Title')\r\n        title.text = ETree.CDATA(u\"\u8f66\u53ef\u8baf\")\r\n        description = ETree.SubElement(item, 'Description')\r\n        description.text = ETree.CDATA(u\"\u6b22\u8fce\u5149\u4e34\u8f66\u53ef\u8baf\")\r\n        picUrl = ETree.SubElement(item, 'PicUrl')\r\n        picUrl.text = ETree.CDATA(\"http:\/\/mmbiz.qpic.cn\/mmbiz_png\/SAydTFbl7nv4ibI88uPrLxFIoKRUiawGwN7Z3p7x1N002uBiaHsYKTksMNrSUT7icshGNia1xtAYAbCTkiaia4yLqtwWA\/0\")\r\n        url = ETree.SubElement(item, 'Url')\r\n        url.text = ETree.CDATA(\"http:\/\/cloud.car-ocean.com:8080\/\")\r\n\r\n        xmlData = ETree.tostring(xmlRoot, encoding=\"utf-8\")\r\n        print(\"Thread(Main), Time: %s, DEBUG: Return original message : \\n%s\" % (time.ctime(), xmlData))\r\n        # \u52a0\u5bc6\u5904\u7406\r\n        if (msgEncrypt_type == \"raw\"):\r\n            self.write(xmlData)\r\n        else:\r\n            nonce = str(int(time.time()))\r\n            wxBizMsgCrypt = WXBizMsgCrypt(global_define.TOKEN, global_define.EncodingAESKey, global_define.APPID)\r\n            ret, encryptBody = wxBizMsgCrypt.EncryptMsg(xmlData, nonce)\r\n            if ret != 0:\r\n                print(\"Thread(Main), Time: %s, ERROR: EncryptMsg error : %d\" % (time.ctime(), ret))\r\n                self.write(\"\")\r\n            xmlData = encryptBody\r\n            print(\"Thread(Main), Time: %s, DEBUG: Return encrypted message : \\n%s\" % (time.ctime(), xmlData))\r\n            self.set_header('Content-Type', 'text\/xml; encoding=utf-8')\r\n            self.write(xmlData)\r\n\r\n    def Subscribe(self, msgEncrypt_type, msgToUserName, msgFromUserName, msgCreateTime):\r\n        # \u751f\u6210\u672a\u52a0\u5bc6\u539f\u59cbxml\u6d88\u606f\r\n        xmlRoot = ETree.Element(\"xml\")\r\n        toUserName = ETree.SubElement(xmlRoot, 'ToUserName')\r\n        toUserName.text = ETree.CDATA(msgFromUserName)\r\n        fromUserName = ETree.SubElement(xmlRoot, 'FromUserName')\r\n        fromUserName.text = ETree.CDATA(msgToUserName)\r\n        createTime = ETree.SubElement(xmlRoot, 'CreateTime')\r\n        createTime.text = msgCreateTime\r\n        msgType = ETree.SubElement(xmlRoot, 'MsgType')\r\n        msgType.text = ETree.CDATA(\"text\")\r\n        content = ETree.SubElement(xmlRoot, 'Content')\r\n        content.text = ETree.CDATA(u\"\u60a8\u8ba2\u9605\u6210\u529f\uff01\u6b22\u8fce\u60a8\u7684\u5230\u6765\uff01\")\r\n        xmlData = ETree.tostring(xmlRoot, encoding=\"utf-8\")\r\n        print(\"Thread(Main), Time: %s, DEBUG: Return original message : \\n%s\" % (time.ctime(), xmlData))\r\n\r\n        # \u52a0\u5bc6\u5904\u7406\r\n        if( msgEncrypt_type == \"raw\" ):\r\n            self.write(xmlData)\r\n        else:\r\n            nonce = str(int(time.time()))\r\n            wxBizMsgCrypt = WXBizMsgCrypt(global_define.TOKEN, global_define.EncodingAESKey, global_define.APPID)\r\n            ret, encryptBody = wxBizMsgCrypt.EncryptMsg(xmlData, nonce)\r\n            if ret != 0:\r\n                print(\"Thread(Main), Time: %s, ERROR: EncryptMsg error : %d\" % (time.ctime(), ret))\r\n                self.write(\"\")\r\n            xmlData = encryptBody\r\n            print(\"Thread(Main), Time: %s, DEBUG: Return encrypted message : \\n%s\" % (time.ctime(), xmlData))\r\n            self.set_header('Content-Type', 'text\/xml; encoding=utf-8')\r\n            self.write(xmlData)\r\n\r\n    def Unsubscribe(self):\r\n        self.write(\"\")\r\n\r\nclass NewHandler(tornado.web.RequestHandler):\r\n    def post(self):\r\n        title = self.get_argument(\"title\")\r\n        if not title:\r\n            return None\r\n        self.redirect(\"\/\")\r\n\r\n\r\nclass EditHandler(tornado.web.RequestHandler):\r\n    def get(self, id):\r\n        todo = 1\r\n        return self.render(\"edit.html\", todo=todo)\r\n\r\n    def post(self, id):\r\n        self.redirect(\"\/\")\r\n\r\nclass JSONObject:\r\n    def __init__(self, d):\r\n        self.__dict__ = d\r\n\r\ndef main():\r\n    tornado.options.parse_command_line()\r\n    app = tornado.httpserver.HTTPServer(Application())\r\n    if SYS_PLATFORM == \"Windows\":\r\n        app.listen(options.port)\r\n    else:\r\n        app.bind(options.port)\r\n        app.start(num_processes=0) # \u542f\u7528\u591a\u8fdb\u7a0b\uff0c0\u4e3a\u542f\u52a8CPU\u4e2a\u6570\u7684\u8fdb\u7a0b\uff0c\u5fc5\u987b\u5173\u6389debug\u6a21\u5f0f\uff08settings\u7684debug=true\u8bed\u53e5\uff09\uff0cwindows\u4e0b\u4e0d\u80fd\u7528\r\n    try:\r\n        tornado.ioloop.IOLoop.instance().start()\r\n    except KeyboardInterrupt:\r\n        tornado.ioloop.IOLoop.instance().stop()\r\n\r\nif __name__ == \"__main__\":\r\n    global_define.accessToken = access_token.AccessToken(1)\r\n    if not SYS_PLATFORM == \"Windows\":\r\n        global_define.accessToken.start()\r\n    access_token = global_define.accessToken.GetAccessToken() # \u7b2c\u4e00\u6b21\u53d6\r\n    access_token = global_define.accessToken.access_token     # \u9700\u8981\u65f6\u8fd9\u6837\u53d6\r\n\r\n    # \u4e0a\u4f20\u7d20\u6750\u56fe\u7247: \u6c38\u4e45\r\n    \"\"\"\r\n    fileName = '..\/car_ocean_logo.png'\r\n    if(os.path.isfile(fileName)):\r\n        fileData = io.BytesIO(open(fileName).read())\r\n        fileType = mimetypes.guess_type(fileName) or 'application\/octet-stream'\r\n        fields = {}\r\n        files = {'media': ('car_ocean_logo.png', fileData, fileType)}\r\n        url = \"https:\/\/api.weixin.qq.com\/cgi-bin\/material\/add_material?access_token=\"+access_token+\"&amp;type=image\"\r\n        print(\"Thread(Main), Time: %s, DEBUG: REQUEST URL: %s\" % (time.ctime(), url))\r\n        request = requests.post(url, verify=False, data=fields, files=files)\r\n        print(\"Thread(Main), Time: %s, DEBUG: OUTPUT: %s\" % (time.ctime(), request.content))\r\n    else:\r\n        print(\"Thread(Main), Time: %s, ERROR: file is not exist: %s\" % (time.ctime(), fileName))\r\n    \"\"\"\r\n    '''\r\n    \u8fd4\u56de\u503c\uff1a\r\n    {\"media_id\": \"EXXGrEsCjc4xXltwe1bKnwygZ1EjuWxZxjmHANE2nGE\",\r\n     \"url\": \"http:\\\/\\\/mmbiz.qpic.cn\\\/mmbiz_png\\\/SAydTFbl7nv4ibI88uPrLxFIoKRUiawGwN7Z3p7x1N002uBiaHsYKTksMNrSUT7icshGNia1xtAYAbCTkiaia4yLqtwWA\\\/0?wx_fmt=png\"}\r\n    '''\r\n    # \u4e0a\u4f20\u7d20\u6750\u7f29\u7565\u56fe\uff1a\u6c38\u4e45\r\n    \"\"\"\r\n    fileName = '..\/car_ocean_logo.jpg'\r\n    if(os.path.isfile(fileName)):\r\n        fileData = io.BytesIO(open(fileName).read())\r\n        fileType = mimetypes.guess_type(fileName) or 'application\/octet-stream'\r\n        fields = {}\r\n        files = {'media': ('car_ocean_logo.jpg', fileData, fileType)}\r\n        url = \"https:\/\/api.weixin.qq.com\/cgi-bin\/material\/add_material?access_token=\"+access_token+\"&amp;type=thumb\"\r\n        print(\"Thread(Main), Time: %s, DEBUG: REQUEST URL: %s\" % (time.ctime(), url))\r\n        request = requests.post(url, verify=False, data=fields, files=files)\r\n        print(\"Thread(Main), Time: %s, DEBUG: OUTPUT: %s\" % (time.ctime(), request.content))\r\n    else:\r\n        print(\"Thread(Main), Time: %s, ERROR: file is not exist: %s\" % (time.ctime(), fileName))\r\n    \"\"\"\r\n    '''\r\n    \u8fd4\u56de\u503c\uff1a\r\n    {\"media_id\":\"EXXGrEsCjc4xXltwe1bKn9doo_oPZSwcCrlHVL8h2_U\",\r\n    \"url\":\"http:\\\/\\\/mmbiz.qpic.cn\\\/mmbiz_jpg\\\/SAydTFbl7nv4ibI88uPrLxFIoKRUiawGwN1300ZIOiasdJdqTerKJ3ootb3b1SzOW0yxtWnqQDDSVkicvSuScicE4og\\\/0?wx_fmt=jpeg\"}\r\n    '''\r\n    # \u4e0a\u4f20\u7d20\u6750\u56fe\u7247: \u4e34\u65f6\r\n    \"\"\"\r\n    fileName = '..\/car_ocean_logo.png'\r\n    if(os.path.isfile(fileName)):\r\n        fileData = io.BytesIO(open(fileName).read())\r\n        fileType = mimetypes.guess_type(fileName) or 'application\/octet-stream'\r\n        fields = {}\r\n        files = {'media': ('car_ocean_logo.png', fileData, fileType)}\r\n        url = \"https:\/\/api.weixin.qq.com\/cgi-bin\/media\/uploadimg?access_token=\"+access_token+\"&amp;type=image\"\r\n        print(\"Thread(Main), Time: %s, DEBUG: REQUEST URL: %s\" % (time.ctime(), url))\r\n        request = requests.post(url, verify=False, data=fields, files=files)\r\n        print(\"Thread(Main), Time: %s, DEBUG: OUTPUT: %s\" % (time.ctime(), request.content))\r\n    else:\r\n        print(\"Thread(Main), Time: %s, ERROR: file is not exist: %s\" % (time.ctime(), fileName))\r\n    \"\"\"\r\n    '''\r\n    \u8fd4\u56de\u503c\uff1a\r\n    {\"url\":\"http:\\\/\\\/mmbiz.qpic.cn\\\/mmbiz_png\\\/SAydTFbl7nv4ibI88uPrLxFIoKRUiawGwN7Z3p7x1N002uBiaHsYKTksMNrSUT7icshGNia1xtAYAbCTkiaia4yLqtwWA\\\/0\"}\r\n    '''\r\n    # \u4e0a\u4f20\u7d20\u6750\u56fe\u6587\uff1a\u6c38\u4e45\r\n    \"\"\"\r\n    content1 = \"\u6b22\u8fce\u5149\u4e34\u8f66\u53ef\u8baf\"   #\u6ce8\u610f\u5728json\u7d20\u6750\u4e2d\u7684\u4e2d\u6587\u9700\u8981\u4f7f\u7528\u9ed8\u8ba4utf-8\u65b9\u5f0f\r\n    fileName = 'templates\/test.html'\r\n    if(os.path.isfile(fileName)):\r\n        content1 = open(fileName).read()\r\n    content2 = \"\u6d4b\u8bd5\u7528\"\r\n    data ={\r\n        \"articles\":[\r\n            {\"title\": \"\u8f66\u53ef\u8baf\",\r\n             \"thumb_media_id\": \"EXXGrEsCjc4xXltwe1bKn9doo_oPZSwcCrlHVL8h2_U\",\r\n             \"author\": \"Car Ocean\",\r\n             \"digest\": \"\",\r\n             \"show_cover_pic\": 0,\r\n             \"content\": content1,\r\n             \"content_source_url\": \"http:\/\/www.car-ocean.com\/\"\r\n            },\r\n            {\"title\": \"\u6d4b\u8bd51\",\r\n             \"thumb_media_id\": \"EXXGrEsCjc4xXltwe1bKn9doo_oPZSwcCrlHVL8h2_U\",\r\n             \"author\": \"Car Ocean\",\r\n             \"digest\": \"\",\r\n             \"show_cover_pic\": 0,\r\n             \"content\": content2,\r\n             \"content_source_url\": \"https:\/\/cloud.car-ocean.com:8443\/admin\/\"\r\n            },\r\n        ]\r\n    }\r\n    json_str = json.dumps(data, ensure_ascii=False)\r\n    print(\"Thread(Main), Time: %s, DEBUG: REQUEST JSON: %s\" % (time.ctime(), json_str))\r\n    url = \"https:\/\/api.weixin.qq.com\/cgi-bin\/material\/add_news?access_token=\"+access_token\r\n    print(\"Thread(Main), Time: %s, DEBUG: REQUEST URL: %s\" % (time.ctime(), url))\r\n    request = urllib2.Request(url)\r\n    request.add_header(\"Content-Type\", \"application\/json\")\r\n    response = urllib2.urlopen(request, json.dumps(data, ensure_ascii=False)).read()  #\u6ce8\u610fensure_ascii\u5fc5\u987b\u4e3aFalse\r\n    dataRtn = json.loads(response, object_hook=JSONObject)\r\n    print(\"Thread(Main), Time: %s, DEBUG: OUTPUT: %s\" % (time.ctime(), response))\r\n    if(hasattr(dataRtn, \"media_id\")):\r\n        print(\"Thread(Main), Time: %s, DEBUG: OUTPUT JSONObject: %s\" % (time.ctime(), dataRtn.media_id))\r\n    else:\r\n        dataRtn.media_id = \"\"\r\n    \"\"\"\r\n    '''\r\n    \u8fd4\u56de\u503c\uff1a\r\n    {\"media_id\":\"EXXGrEsCjc4xXltwe1bKn8uwkLzodNgZ-zdZ3DaL6kc\"}\r\n    \u5220\u9664\uff1a\r\n    curl -d '{\"media_id\":\"EXXGrEsCjc4xXltwe1bKn8uwkLzodNgZ-zdZ3DaL6kc\"}' https:\/\/api.weixin.qq.com\/cgi-bin\/material\/del_material?access_token=hSNOuGcaMdtV-WpgnvplF1ZIOmC8shJKPbeeXUN6L1wyFcBnuzZ71fCxd85dpNYguhgp5V96kuWvOWQTFJjqnSzkp-oydPbuC7lPvSzkEWob8g9_ULpgvsx_AV3xogYfIYGdABAZPX\r\n    '''\r\n    # \u63a8\u9001\u6d88\u606f\uff1a\u6bcf\u5929\u4e0d\u8d85\u8fc7\u4e00\u6b21\uff0c\u9700\u8ba4\u8bc1\u540e\u80fd\u7528\r\n    \"\"\"\r\n    data ={\r\n        \"filter\":{\r\n            \"is_to_all\":True\r\n        },\r\n        \"mpnews\":{\r\n            \"media_id\":dataRtn.media_id\r\n        },\r\n        \"msgtype\":\"mpnews\"\r\n    }\r\n    data ={\r\n        \"touser\":\"oJ-k1wLaKRynhjPWoRaa4_vAH36o\",\r\n        \"mpnews\":{\r\n            \"media_id\":dataRtn.media_id\r\n        },\r\n        \"msgtype\":\"mpnews\"\r\n    }\r\n    json_str = json.dumps(data, ensure_ascii=False)\r\n    print(\"Thread(Main), Time: %s, DEBUG: REQUEST JSON: %s\" % (time.ctime(), json_str))\r\n    # url = \"https:\/\/api.weixin.qq.com\/cgi-bin\/message\/mass\/sendall?access_token=\"+access_token\r\n    url = \"https:\/\/api.weixin.qq.com\/cgi-bin\/message\/mass\/preview?access_token=\"+access_token  # \u4ec5\u9884\u89c8\u6d4b\u8bd5\r\n    print(\"Thread(Main), Time: %s, DEBUG: REQUEST URL: %s\" % (time.ctime(), url))\r\n    request = urllib2.Request(url)\r\n    request.add_header(\"Content-Type\", \"application\/json\")\r\n    response = urllib2.urlopen(request, json.dumps(data, ensure_ascii=False)).read()\r\n    print(\"Thread(Main), Time: %s, DEBUG: OUTPUT: %s\" % (time.ctime(), response))\r\n    dataRtn = json.loads(response, object_hook=JSONObject)\r\n    \"\"\"\r\n    '''\r\n    \u8fd4\u56de\u503c\uff1a\r\n    '''\r\n\r\n    # \u521b\u5efa\u83dc\u5355\r\n    \"\"\"\r\n    data ={\r\n        \"button\":[\r\n        {\r\n            \"type\":\"click\",\r\n            \"name\":\"\u70b9\u51fb\u83dc\u5355\",\r\n            \"key\":\"MENU_1_NONE\"\r\n        },\r\n        {\r\n            \"name\":\"\u542b\u5b50\u83dc\u5355\",\r\n            \"sub_button\":[\r\n            {\r\n                \"type\":\"view\",\r\n                \"name\":\"\u8f66\u53ef\u8baf\u5b98\u7f51\",\r\n                \"url\":\"http:\/\/www.car-ocean.com\/\"\r\n            },\r\n            {\r\n               \"type\":\"view\",\r\n               \"name\":\"\u8f66\u53ef\u8baf\u4e0b\u8f7d\",\r\n               \"url\":\"http:\/\/cloud.car-ocean.com:8080\/\"\r\n            }\r\n            ]\r\n        }\r\n        ]\r\n    }\r\n    json_str = json.dumps(data, ensure_ascii=False)\r\n    print(\"Thread(Main), Time: %s, DEBUG: REQUEST JSON: %s\" % (time.ctime(), json_str))\r\n    url = \"https:\/\/api.weixin.qq.com\/cgi-bin\/menu\/create?access_token=\"+access_token\r\n    print(\"Thread(Main), Time: %s, DEBUG: REQUEST URL: %s\" % (time.ctime(), url))\r\n    request = urllib2.Request(url)\r\n    request.add_header(\"Content-Type\", \"application\/json\")\r\n    response = urllib2.urlopen(request, json.dumps(data, ensure_ascii=False)).read()\r\n    dataRtn = json.loads(response, object_hook=JSONObject)\r\n    print(\"Thread(Main), Time: %s, DEBUG: OUTPUT: %s\" % (time.ctime(), response))\r\n    if(hasattr(dataRtn, \"errmsg\")):\r\n        print(\"Thread(Main), Time: %s, DEBUG: OUTPUT JSONObject: %s\" % (time.ctime(), dataRtn.errmsg))\r\n    \"\"\"\r\n    '''\r\n    \u8fd4\u56de\u503c\uff1a\r\n    \u5220\u9664\uff1a\r\n    '''\r\n\r\n    main()<\/pre>\n<\/div>\n<div>access_token.py\uff1a<\/div>\n<div>\n<pre>#!\/usr\/bin\/python\r\n#-*- encoding:utf-8 -*-\r\n\r\nimport time\r\nimport threading\r\nimport urllib2\r\nimport json\r\nimport traceback\r\nimport signal\r\nimport platform\r\n\r\nimport global_define\r\n\r\n# \u5904\u7406\u952e\u76d8\u4e2d\u65ad\r\ndef sigint_handler(signum, frame):\r\n    global is_sigint_up\r\n    is_sigint_up = True\r\n    print('CATCHED INTERRUPT SIGNAL!')\r\n    raise SystemExit('Ctrl+C')\r\nsignal.signal(signal.SIGINT, sigint_handler)\r\nif not platform.system() == \"Windows\":\r\n    signal.signal(signal.SIGHUP, sigint_handler)\r\nsignal.signal(signal.SIGTERM, sigint_handler)\r\nis_sigint_up = False\r\n\r\nclass AccessToken(threading.Thread):\r\n    def __init__(self, number):\r\n        #\u5728\u6211\u91cd\u5199__init__\u65b9\u6cd5\u7684\u65f6\u5019\u8981\u8bb0\u5f97\u8c03\u7528\u57fa\u7c7b\u7684__init__ \u65b9\u6cd5 \u3000\r\n        threading.Thread.__init__(self)\r\n        self.number = number\r\n        self.access_token = \"\"\r\n        self.expires_in = 7200\r\n\r\n    def run(self): #\u91cd\u5199run()\u65b9\u6cd5\uff0c\u628a\u81ea\u5df1\u7684\u7ebf\u7a0b\u51fd\u6570\u7684 \u4ee3\u7801\u653e\u5230\u8fd9\u91cc\r\n        count = 0\r\n        while True:\r\n            if(count &gt;= self.expires_in - 2):\r\n                count = 0\r\n                self.runMain()\r\n            if(is_sigint_up): # \u9000\u51fa\r\n                break\r\n            count += 1\r\n            time.sleep(1)\r\n\r\n    def runMain(self):\r\n        print(\"Thread(%d), Time: %s, DEBUG: INPUT:  %s\" % (self.number, time.ctime(), global_define.ACCESS_TOKEN_URL))\r\n        httpStream = urllib2.urlopen(global_define.ACCESS_TOKEN_URL)\r\n        httpContent = httpStream.read()\r\n        print(\"Thread(%d), Time: %s, DEBUG: OUTPUT: %s\" % (self.number, time.ctime(), httpContent))\r\n        httpHeader = httpStream.info()\r\n        print(\"Thread(%d), Time: %s, DEBUG: OUTPUT HEADER: %s\" % (self.number, time.ctime(), httpHeader))\r\n        httpHeaderContenttype = httpHeader.getheader('Content-Type')\r\n        print(\"Thread(%d), Time: %s, DEBUG: OUTPUT HEADER Content-Type: %s\" % (self.number, time.ctime(), httpHeaderContenttype))\r\n        hjson = json.loads(httpContent)\r\n        print(\"Thread(%d), Time: %s, DEBUG: JSON: %s\" % (self.number, time.ctime(), json.dumps(hjson, sort_keys=True, indent=4)))\r\n        self.access_token = hjson['access_token']\r\n        self.expires_in = hjson['expires_in']\r\n        print('Thread(%d), Time: %s, DEBUG: access_token: %s' % (self.number, time.ctime(), self.access_token))\r\n        print('Thread(%d), Time: %s, DEBUG: expires_in: %d' % (self.number, time.ctime(), self.expires_in))\r\n        url = \"https:\/\/api.weixin.qq.com\/cgi-bin\/getcallbackip?access_token=\"+self.access_token\r\n        httpStream = urllib2.urlopen(url)\r\n        httpContent = httpStream.read()\r\n        hjson = json.loads(httpContent)\r\n        self.weiXinIpList = hjson['ip_list']\r\n        print('Thread(%d), Time: %s, DEBUG: WeiXin server ip list: %s' % (self.number, time.ctime(), self.weiXinIpList))\r\n\r\n    def GetAccessToken(self):\r\n        if self.access_token == \"\":\r\n            print(\"Thread(%d), Time: %s, INFO: not yet get access_token\" % (self.number, time.ctime()))\r\n            self.runMain()\r\n        print(\"Thread(%d), Time: %s, DEBUG: access_token: %s\" % (self.number, time.ctime(), self.access_token))\r\n        return self.access_token<\/pre>\n<\/div>\n<div>global_define.py\uff08xxx\u7684\u5730\u65b9\u8981\u66ff\u6362\uff09\uff1a<\/div>\n<div>\n<pre>#!\/usr\/bin\/python\r\n#-*- encoding:utf-8 -*-\r\n\r\nglobal accessToken\r\n\r\n# \u5fae\u4fe1\u6d4b\u8bd5\u53f7\uff1a gh_589de042e9ab\r\nTOKEN = \"xxxxxxxxx\" # 3-32\u5b57\u7b26\r\nEncodingAESKey = \"xxxxxxxxxxxxxx\" # 43\u5b57\u7b26\r\n\r\nAPPID = \"xxxxxxxxxxxxxxxxx\"\r\nAPPSECRET = \"xxxxxxxxxxxxxxxxxx\"\r\nACCESS_TOKEN_URL = \"https:\/\/api.weixin.qq.com\/cgi-bin\/token?grant_type=client_credential&amp;appid=\"+APPID+u\"&amp;secret=\"+APPSECRET\r\n\r\n<\/pre>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u5b9e\u73b0\u51e0\u4e2a\u5fc5\u987b\u529f\u80fd\u7684\u4f8b\u5b50\uff0c\u79bb\u5b9e\u7528\u8fdc\u7740\u5462\uff1a main.py\uff1a #!\/usr\/bin\/python #-*- enc &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[386,108,382,383,384,385],"class_list":["post-440","post","type-post","status-publish","format-standard","hentry","category-13","tag-api","tag-python","tag-tornado","tag-383","tag-384","tag-385"],"views":2201,"_links":{"self":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/440","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=440"}],"version-history":[{"count":1,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/440\/revisions"}],"predecessor-version":[{"id":441,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/440\/revisions\/441"}],"wp:attachment":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=440"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=440"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=440"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}