語言:Python
工具:MySQL,Tkinter,圖靈機器人
功能:圖形聊天工具,可以選擇自動回復或者人工回復。
注意:如果運行需要自建mysql數據庫表、還有安裝各種模塊、還有到“圖靈機器人”申請賬戶(免費),否則看看就行了。
(部分借鑒自某個博客,忘記哪里看的了,tkinter部分和tcp連接都是從那里學來的)
1、服務器
#filename:Server+SwitchButton.py
#-*-coding:utf-8-*-
import Tkinter
import tkFont
import socket
import thread
import time
import urllib
import urllib2
import traceback
import MySQLdb
import random
import sys
reload(sys)
sys.setdefaultencoding('utf8')
class Server():
title = 'Python自動客服-服務器'
Ip = '127.0.0.1'#還不知怎么用私網連接,目前只能用公網ip設置serverIp
Port = 8808#端口必須在1024以上
global serverSock
global receiveMsg
global message
flag = False
#初始化類的相關屬性,類似於構造方法
def __init__(self):
from Tkinter import *
self.root = Tkinter.Tk()
self.root.title(self.title)
#窗口面板,用6個frame面板布局,ip和port設置框架最后因為連接方式的選取問題取消
self.frame = [Tkinter.Frame(), Tkinter.Frame(), Tkinter.Frame(), Tkinter.Frame(), Tkinter.Frame(), Tkinter.Frame()]
#frame0
#切換功能的checkButton
self.CheckVar1 = IntVar()
self.CheckVar2 = IntVar()
self.CheckVar3 = IntVar()
self.CheckButton1 = Checkbutton(self.frame[0], text = "手動", variable = self.CheckVar1, onvalue = 1, offvalue = 0, height=2, width = 5)
self.CheckButton2 = Checkbutton(self.frame[0], text = "數據庫", variable = self.CheckVar2, onvalue = 1, offvalue = 0, height=2, width = 5)
self.CheckButton3 = Checkbutton(self.frame[0], text = "圖靈", variable = self.CheckVar3, onvalue = 1, offvalue = 0, height=2, width = 5)
self.CheckButton1.pack(expand=1, side=Tkinter.TOP and Tkinter.LEFT)
self.CheckButton2.pack(expand=1, side=Tkinter.TOP and Tkinter.LEFT)
self.CheckButton3.pack(expand=1, side=Tkinter.TOP and Tkinter.RIGHT)
self.frame[0].pack(fill=Tkinter.BOTH)#expand=1,
'''
#frame1
#ip地址和端口選擇,暫時取消
ft1 = tkFont.Font(family='Fixdsys', size=8)
self.inputTextIp = Tkinter.Text(self.frame[1], width=20, height=2, font=ft1)
self.inputTextPort = Tkinter.Text(self.frame[1], width=7, height=2, font=ft1)
self.ipConfirmButton = Tkinter.Button(self.frame[1], text='確認', width=5, height=2, command=self.setIpPort)
self.inputTextIp.pack(expand=1, fill=Tkinter.BOTH)
self.inputTextPort.pack(expand=1, fill=Tkinter.BOTH)
self.frame[1].pack(expand=1, fill=Tkinter.BOTH)
'''
#frame2
#顯示消息Text右邊的滾動條
self.chatTextScrollBar = Tkinter.Scrollbar(self.frame[2])
self.chatTextScrollBar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)
#顯示消息Text,並綁定上面的滾動條
#本來應該相互綁定,但實際運行時,滑動條沒有綁定列表框
self.chatText = Tkinter.Listbox(self.frame[2], width=80, height=18)
self.chatText['yscrollcommand'] = self.chatTextScrollBar.set
self.chatText.pack(expand=1, side=Tkinter.LEFT, fill=Tkinter.BOTH)
#self.chatTextScrollBar['command'] = self.chatText.yview()
self.frame[2].pack(fill=Tkinter.BOTH)
#frame3
#標簽,創建高度為2的空白區區分ListBox和Text
label = Tkinter.Label(self.frame[3], height=2)
label.pack(fill=Tkinter.BOTH)
self.frame[3].pack(fill=Tkinter.BOTH)
#frame4
#輸入消息Text的滾動條
self.inputTextScrollBar = Tkinter.Scrollbar(self.frame[4])
self.inputTextScrollBar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)
#輸入消息Text,並與滾動條綁定
#常用字體元組('Arial',('Courier New',),('Comic Sans MS',),'Fixdsys',('MS Sans Serif',),('MS Serif',),'Symbol','System',('Times New Roman',),'Verdana')
ft4 = tkFont.Font(family='Fixdays', size=11)
self.inputText = Tkinter.Text(self.frame[4], width=80, height=8, font=ft4)
self.inputText['yscrollcommand'] = self.inputTextScrollBar.set
self.inputText.pack(expand=1, fill=Tkinter.BOTH)
#self.inputTextScrollBar['command'] = self.chatText.yview()
self.frame[4].pack(fill=Tkinter.BOTH)
#frame5
#發送消息按鈕
self.sendButton = Tkinter.Button(self.frame[5], text=' 發 送 ', width=10, command=self.ManualMessage)#setReplyStatus)#發送按鈕的事件調用設置回復方式函數
self.sendButton.pack(expand=1, side=Tkinter.BOTTOM and Tkinter.RIGHT, padx=25, pady=5)
#關閉按鈕
self.closeButton = Tkinter.Button(self.frame[5], text=' 關 閉 ', width=10, command=self.close)
self.closeButton.pack(expand=1, side=Tkinter.RIGHT, padx=25, pady=5)
self.frame[5].pack(expand=1, fill=Tkinter.BOTH)
'''
def showCheckButton1Varialbe(self):
return self.CheckButton1.variable.get()
def showCheckButton2Varialbe(self):
return self.CheckButton2.variable.get()
'''
#接收消息並顯示
def receiveMessage(self):
global receiveMsg
#建立Socket連接
try:
self.serverSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#建立socket,參數為ipv4,TCP,另一個參數默認為1.
self.serverSock.bind((self.Ip, self.Port))
self.serverSock.listen(15)
self.buffer = 1024
self.chatText.insert(Tkinter.END, '服務器已經就緒......')
except:
self.flag = False
self.chatText.insert(Tkinter.END,'服務器端建立連接錯誤,請檢查端口和ip是否可用......')
try:
while True:
#循環接受客戶端的連接請求
self.connection, self.address = self.serverSock.accept()
self.flag = True
while True:
#循環接收客戶端發送的消息
self.clientMsg = self.connection.recv(self.buffer)
if not self.clientMsg:
#當接受到的clientMsg為空就跳出循環,出現過卡死狀態
continue
#可以講下三次握手:客-》服;服-》客;客-》服
elif self.clientMsg == 'Y':
self.chatText.insert(Tkinter.END, '服務器端已經與客戶端建立連接......')
self.connection.send('Y')
elif self.clientMsg == 'N':
self.chatText.insert(Tkinter.END, '服務器端與客戶端建立連接失敗......')
self.connection.send('N')
else:
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '客戶端 ' + theTime + ' 說:\n')
self.chatText.insert(Tkinter.END, ' ' + self.clientMsg)
#self.chatText.insert(Tkinter.END, type(self.clientMsg))
try:
receiveMsg = self.clientMsg
except:
print "Error"
try:
self.setReplyStatus()
except:
self.chatText.insert(Tkinter.END, '回復方式函數錯誤......')
except:
self.chatText.insert(Tkinter.END, '連接錯誤......')
#判斷回復方式
def setReplyStatus(self):
global replyStatus
global receiveMsg
#regard the num as 4,2,1,and add it to replyStatus
if self.CheckVar1.get()==1 and self.CheckVar2.get()==0 and self.CheckVar3.get()==0:
self.replyStatus=7
#此處刪除函數的原因是,已經設計“發送”按鈕的command調用了ManualMessage,所以在此處定義則調用了兩次函數,而這里的這個返回空
#self.ManualMessage()
#數據庫回復
elif self.CheckVar1.get()==0 and self.CheckVar2.get()==1 and self.CheckVar3.get()==0:
self.replyStatus=2
try:
dataInfo=self.DatabaseInformation()
print "dataInfo:",dataInfo
#輸入hi時,下面的語句訪問錯誤
try:
self.DatabaseQuestion()
except:
print "hahe181"
print "dataQues:",dataQues
if dataInfo==None and dataQues is not None:
self.DatabaseQuestion()
elif dataInfo==None and dataQues==None:
self.chatText.insert(Tkinter.END, '無法匹配數據庫信息,請手動回復')
self.ManualMessage()
elif dataInfo is not None and dataQues is None:
self.DatabaseInformation()
#默認兩表不存在交集,所以這部分為空
else:
pass
except:
pass#self.chatText.insert(Tkinter.END, '數據庫回復錯誤')
elif self.CheckVar1.get()==0 and self.CheckVar2.get()==0 and self.CheckVar3.get()==1:
self.replyStatus=1
self.TuringMessage()
#數據庫+圖靈回復
elif self.CheckVar2.get()==1 and self.CheckVar3.get()==1:
self.reply=3
try:
self.DatabaseInformation()
if self.DatabaseInformation()==None:
self.DatabaseQuestion()
if self.DatabaseQuestion()==None:
self.TuringMessage()
if self.TuringMessage()==None:
self.chatText.insert(Tkinter.END, '無法匹配數據庫信息,請手動回復')
self.ManualMessage()
else:
self.DatabaseQuestion()
else:
self.DatabaseInformation()
except:
self.chatText.insert(Tkinter.END, '數據庫+圖靈回復錯誤')
elif self.CheckVar1.get()==1 and self.CheckVar2.get()==0 and self.CheckVar3.get()==1:
self.replyStatus=1
self.TuringMessage()
elif self.CheckVar1.get()==1 and self.CheckVar2.get()==1 and self.CheckVar3.get()==0:
self.replyStatus=2
self.DatabaseInformation()
self.DatabaseQuestion()
else:
#格式化當前的時間
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END,' ' + '請選擇一種回復方式,選擇兩種以上都變為數據庫和圖靈自動回復(目前狀態)' + '\n')
#自動切換為011或者111狀態
'''
#為什么這個也錯?暫時放棄
self.CheckVar2.get()==1
self.CheckVar3.get()==1
self.setReplyStatus()
'''
'''
#為什么提示database()訪問有誤,global receiveMsg沒有定義?
self.reply=3
if self.DatabaseMessage()==None:
if self.TuringMessage()==None:
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END,' ' + '未能成功匹配,請手動輸入回復信息' + '\n')
self.ManualMessage()
else:
self.TuringMessage()
else:
self.DatabaseMessage()
'''
'''
#通過判斷回復方式得到將要執行的回復語句,並由此改變replyStatus的值,再由此函數充當此button的commond函數。暫時放棄。
def setSendButtonStyle(self):
if self.replyStatus==7:
self.ManualMessage()
elif self.replyStatus==:
self.ManualMessage()
'''
#獲取圖靈消息
def TuringMessage(self):
#try:
#抓取turing的回復
global receiveMsg
global string
#self.chatText.insert(Tkinter.END, "Hello, I'm Turing. Enter bye to quit.")
TuringQuestion = receiveMsg.encode('utf-8')#.decode('gb18030')
try:
TuringQ = "http://www.tuling123.com/openapi/api?key=dcc40d6323b576076c3005043aaba756&info=%s" %(TuringQuestion)
except:
self.chatText.insert(Tkinter.END, "無法訪問圖靈數據庫1,暫時將調用手動回復,請輸入......")
self.manualMessage()
#print 11111
try:
TuringRequest = urllib2.Request(TuringQ)
print 11111
except:
self.chatText.insert(Tkinter.END, "圖靈數據庫提交數據出錯2,暫時將調用手動回復,請輸入......")
self.manualMessage()
#print 22222
try:
TuringResponse = urllib2.urlopen(TuringRequest)
print 22222
except:
self.chatText.insert(Tkinter.END, "獲取圖靈數據庫數據錯誤3,暫時將調用手動回復,請輸入......")
self.manualMessage()
TuringAnswer= TuringResponse.read().decode('utf-8')#.encode('gb18030')
#print 33333
try:
#從圖靈獲取的數據是字符串(字典格式的),轉化成字典,並提取text對應的字符串
string = eval(TuringAnswer)["text"]
print 33333
except:
self.chatText.insert(Tkinter.END, "圖靈數據庫數據轉換錯誤4,無法輸出,暫時將調用手動回復,請輸入......")
self.manualMessage()
#print 44444
#if self.flag == True:
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END,' ' + string + '\n')
if self.flag == True:
self.connection.send(string)
else:
self.chatText.insert(Tkinter.END,'您還未與客戶端建立連接,客戶端無法收到您的消息\n')
#except:
#return None
#獲取手動輸入信息
def ManualMessage(self):
message = self.inputText.get('1.0',Tkinter.END)
#格式化當前的時間
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END,' ' + message + '\n')
if self.flag == True:
#將消息發送到客戶端
self.connection.send(message)
else:
#Socket連接沒有建立,提示用戶
self.chatText.insert(Tkinter.END,'您還未與客戶端建立連接,客戶端無法收到您的消息\n')
#清空用戶在Text中輸入的消息
self.inputText.delete(0.0,message.__len__()-1.0)
'''
#手動回復信息,得到用戶在Text中輸入的消息
#這個1.0使得get兩次,第一次是未輸入的情況,get了空,第二次get了輸入的字符串
string = self.inputText.get('1.0',Tkinter.END)
print "string:",string
if string is None:
pass
elif self.flag == True and string is not None:
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
print 112
self.chatText.insert(Tkinter.END,string)
print 123
self.connection.send(string)
print 124
else:
self.chatText.insert(Tkinter.END,'您還未與客戶端建立連接,客戶端無法收到您的消息\n')
#清空用戶在Text中輸入的消息
self.inputText.delete(0.0,message.__len__()-1.0)
'''
#--------------------------------------------------------------
#數據庫回復對話信息
def DatabaseQuestion(self):
global string
try:
#問題出在receiveMsg上!!!
print 1
global receiveMsg
print receiveMsg.strip()
try:
conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='n5252n59',db='python',charset='utf8')
except:
self.chatText.insert(Tkinter.END, "數據庫連接錯誤,請檢查數據庫配置")
with conn:
cur = conn.cursor()
sql = "SELECT * from QuestionAnswerInformation WHERE Question LIKE %s"
#最痛苦的原來是receiveMsg左右各有一個空格,使用strip()消去,就成了正常字符串
cur.execute(sql,(receiveMsg.strip(),))
try:
pass
#cur.execute(sql,(receiveMsg,))
#self.chatText.insert(Tkinter.END, "ha311")
except:
self.chatText.insert(Tkinter.END, "數據庫語句載入錯誤,請檢查數據庫配置")
try:
results=cur.fetchall()
#!!!這里返回為空!!!???
#print 'results:',results
except:
self.chatText.insert(Tkinter.END, "fetch Error 317")
try:
question=results[0][1]
except:
#!!!這句在輸入信息查詢時會輸出,報錯???
#self.chatText.insert(Tkinter.END, "fetch Error 362")
pass
#self.chatText.insert(Tkinter.END, question)
#print question
answer=results[0][2]
#self.chatText.insert(Tkinter.END, answer)
#print "answer:",answer
LinkToNum=results[0][3]
#print "LinkToNum:",LinkToNum
LinkToString=results[0][4]
#print "LinkToString:",LinkToString
cur.close()
'''
#載入隨機數,判斷通過本詞條回復,還是相似詞條(可鏈接到的)回復
randomReply=random.randrange(0,2)
#print randomReply
if randomReply is not 0 and answer is not None:
string = "%s:%s。" %(question,answer)
print string
else:
'''
#!!!3個數據8種回復方式
#(任,空,空)當首次查詢的結果為空時,創建另一個游標,獲取linkToNum,並通過Num查找鏈接向的詞條
if LinkToNum is None and LinkToString is None:
#!!!這里需要對確切信息和相似信息坐下處理(LIKE和=的區別)
#string = "%s:%s。" %(question,answer)
#print "您想問的是這個嗎?"
if answer is not None:
string = "%s。" %(answer)
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END, string)
else:
self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
#(任,非,非)
elif LinkToNum is not None and LinkToString is not None:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,不建議鏈接到字符串和鏈接到編號同時存在,請檢查數據庫")
#(任,非,空)
elif LinkToNum is not None and LinkToString is None:
if answer is None:
#直接查找鏈接到的詞條,和下面else后的代碼一樣,但是寫函數就不方便了,所以寫兩個
try:
curNum = conn.cursor()
sqlLinkToNum = "SELECT * from QuestionAnswerInformation WHERE Num = %s"
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫1")
try:
curNum.execute(sqlLinkToNum,(LinkToNum,))
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫2")
try:
resultsNum=curNum.fetchall()
string = "%s:%s。" %(resultsNum[0][1],resultsNum[0][2])
if resultsNum[0][2] is not None:
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END, "您想問的是這個嗎?")
self.chatText.insert(Tkinter.END, string)
else:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫3")
except:
self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
curNum.close()
elif answer is not None:
#(非,非,空)(用例是輸入hi)載入隨機數,判斷通過本詞條回復,還是相似詞條(可鏈接到的)回復
randomReply=random.randrange(0,2)
#曾經隨機數出過問題,通過print檢驗沒有問題啊
#print randomReply
if randomReply is not 0:
#string = "%s:%s。" %(question,answer)
string = "%s。" %(answer)
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END, string)
else:
#執行LinkToNum鏈接到的詞條
try:
curNum = conn.cursor()
sqlLinkToNum = "SELECT * from QuestionAnswerInformation WHERE Num = %s"
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫1")
try:
curNum.execute(sqlLinkToNum,(LinkToNum,))
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫2")
try:
resultsNum=curNum.fetchall()
string = "%s。" %(resultsNum[0][2])
#string = "%s:%s。" %(resultsNum[0][1],resultsNum[0][2])
if resultsNum[0][2] is not None:
#print "您想問的是這個嗎?"
self.chatText.insert(Tkinter.END, string)
else:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫3")
except:
self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
curNum.close()
#(任,空,非)鏈接到字符串
elif LinkToNum is None and LinkToString is not None:
if answer is None:
try:
curString = conn.cursor()
sqlLinkToString = "SELECT * from QuestionAnswerInformation WHERE Question = %s"
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫1")
curString.execute(sqlLinkToString,(LinkToString,))
try:
resultsString=curString.fetchall()
string = "%s:%s。" %(resultsString[0][1],resultsString[0][2])
if resultsString[0][2] is not None:
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END, "您想問的是這個嗎?")
self.chatText.insert(Tkinter.END, string)
else:
self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫2")
curString.close()
elif answer is not None:
randomReply=random.randrange(0,2)
#print randomReply
if randomReply is not 0:
#string = "%s:%s。" %(question,answer)
string = "%s。" %(answer)
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END, string)
else:
try:
curString = conn.cursor()
sqlLinkToString = "SELECT * from QuestionAnswerInformation WHERE Question = %s"
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫1")
try:
curString.execute(sqlLinkToString,(LinkToString,))
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫2")
try:
resultsString=curString.fetchall()
string = "%s:%s。" %(resultsString[0][1],resultsString[0][2])
except:
self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫3")
if answer is not None:
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END, "您想問的是這個嗎?")
self.chatText.insert(Tkinter.END, string)
curString.close()
else:
self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
curString.close()
#默認linkToString和LinkToNum不能同時不為空,可以同時為空,或者一個為空
#if self.flag == True and string is not None:
if string is not None:
self.connection.send(string)
#return string
else:
self.chatText.insert(Tkinter.END,'您還未與客戶端建立連接,客戶端無法收到您的消息\n')
except:
return None
#--------------------------------------------------------------
#數據庫回復商品信息
def DatabaseInformation(self):
'''
global receiveMsg
print receiveMsg.strip()
try:
conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='n5252n59',db='python',charset='utf8')
except:
self.chatText.insert(Tkinter.END, "數據庫連接錯誤,請檢查數據庫配置")
with conn:
cur = conn.cursor()
sql = "SELECT * from QuestionAnswerInformation WHERE Question LIKE %s"
#最痛苦的原來是receiveMsg左右各有一個空格,使用strip()消去,就成了正常字符串
cur.execute(sql,(receiveMsg.strip(),))
try:
pass
#cur.execute(sql,(receiveMsg,))
#self.chatText.insert(Tkinter.END, "ha311")
except:
self.chatText.insert(Tkinter.END, "數據庫語句載入錯誤,請檢查數據庫配置")
try:
results=cur.fetchall()
#!!!這里返回為空!!!???
print 'results:',results
'''
#import MySQLdb
try:
global receiveMsg
#print "receiveMsg:",receiveMsg
#print "receiveMsg.strip():",receiveMsg.strip()
#global message
#theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
#self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
try:
conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='n5252n59',db='python',charset='utf8')
except:
self.chatText.insert(Tkinter.END, "數據庫連接錯誤,請檢查數據庫配置")
with conn:
cur = conn.cursor()
sql="SELECT * from LeatherShoesInformation WHERE ShoesName LIKE %s"
cur.execute(sql,(receiveMsg.strip(),))
try:
results=cur.fetchall()
print results
except:
print "error"
#cur.execute(sql,(receiveMsg,))
#lineNum = int(cur.rowcount)
#databaseReturn = cur.fetchone()[lineNum-1]
#print databaseReturn
string1 = "我猜,您正考慮的就是這款皮鞋吧:"
string2 = "%s,原價:%s,打折后只有:%s。" %(results[0][2],results[0][3],results[0][4])
string3 = "這款鞋是(%s),(%s)的。" %(results[0][7],results[0][8])
string4 = "另外,這款鞋是賣家評價%s,%s的優質皮鞋。" %(results[0][12],results[0][10])
string5 = "如果您想購買這雙皮鞋,我們還將贈送您%s。我們建議您,%s。" %(results[0][11],results[0][13])
string = string1+string2+string3+string4+string5
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END,string1)
self.chatText.insert(Tkinter.END,string2)
self.chatText.insert(Tkinter.END,string3)
self.chatText.insert(Tkinter.END,string4)
self.chatText.insert(Tkinter.END,string5)
cur.close()
#if self.flag == True:
#self.sendMessage()
#這一行如果調用sendMessage(),將只輸出一行
if self.flag == True:
self.connection.send(string)
else:
self.chatText.insert(Tkinter.END,'您還未與客戶端建立連接,客戶端無法收到您的消息\n')
#self.connection.send(string2)
#self.connection.send(string3)
#self.connection.send(string4)
#self.connection.send(string5)
except:
return
#6月7日決定注銷這段代碼,將輸出放在函數中進行
#發送消息,只供manual和turing調用,database的發送方式還沒定
'''
def sendMessage(self):
global message
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END,' ' + message + '\n')
if self.flag == True:
self.connection.send(message)
else:
self.chatText.insert(Tkinter.END,'您還未與客戶端建立連接,客戶端無法收到您的消息\n')
'''
#關閉消息窗口並退出
def close(self):
sys.exit()
#啟動線程接收客戶端的消息
def startNewThread(self):
#啟動一個新線程來接收客戶端的消息
#thread.start_new_thread(function,args[,kwargs])函數原型,
#其中function參數是將要調用的線程函數,args是傳遞給線程函數的參數,它必須是個元組類型,而kwargs是可選的參數
#receiveMessage函數不需要參數,就傳一個空元組
thread.start_new_thread(self.receiveMessage, ())
#thread.start_new_thread(self.setReplyStatus, ())
def main():
server = Server()
server.startNewThread()
server.setReplyStatus()
server.root.mainloop()
if __name__ == '__main__':
main()
2、客戶端
#filename:TuringTkClient.py
#-*-coding:utf-8-*-
# Python在線聊天客戶端
import Tkinter
import tkFont
import socket
import thread
import time
import sys
reload(sys);
sys.setdefaultencoding('utf8');
class ClientUI():
title = 'Python自動客服-客戶端'
local = '127.0.0.1'
port = 8808
global clientSock;
flag = False
#初始化類的相關屬性,類似於構造方法
def __init__(self):
self.root = Tkinter.Tk()
self.root.title(self.title)
#窗口面板,用4個面板布局
self.frame = [Tkinter.Frame(),Tkinter.Frame(),Tkinter.Frame(),Tkinter.Frame()]
#顯示消息Text右邊的滾動條
self.chatTextScrollBar = Tkinter.Scrollbar(self.frame[0])
self.chatTextScrollBar.pack(side=Tkinter.RIGHT,fill=Tkinter.Y)
#顯示消息Text,並綁定上面的滾動條
self.chatText = Tkinter.Listbox(self.frame[0],width=80,height=18)
self.chatText['yscrollcommand'] = self.chatTextScrollBar.set
self.chatText.pack(expand=1,fill=Tkinter.BOTH)
self.chatTextScrollBar['command'] = self.chatText.yview()
self.frame[0].pack(expand=1,fill=Tkinter.BOTH)
#標簽,分開消息顯示Text和消息輸入Text
label = Tkinter.Label(self.frame[1],height=2)
label.pack(fill=Tkinter.BOTH)
self.frame[1].pack(expand=1,fill=Tkinter.BOTH)
#輸入消息Text的滾動條
self.inputTextScrollBar = Tkinter.Scrollbar(self.frame[2])
self.inputTextScrollBar.pack(side=Tkinter.RIGHT,fill=Tkinter.Y)
#輸入消息Text,並與滾動條綁定
ft = tkFont.Font(family='Fixdsys',size=11)
self.inputText = Tkinter.Text(self.frame[2],width=80,height=8,font=ft)
self.inputText['yscrollcommand'] = self.inputTextScrollBar.set
self.inputText.pack(expand=1,fill=Tkinter.BOTH)
self.inputTextScrollBar['command'] = self.chatText.yview()
self.frame[2].pack(expand=1,fill=Tkinter.BOTH)
#發送消息按鈕
self.sendButton=Tkinter.Button(self.frame[3],text=' 發 送 ',width=10,command=self.sendMessage)
self.sendButton.pack(expand=1,side=Tkinter.BOTTOM and Tkinter.RIGHT,padx=15,pady=8)
#關閉按鈕
self.closeButton=Tkinter.Button(self.frame[3],text=' 關 閉 ',width=10,command=self.close)
self.closeButton.pack(expand=1,side=Tkinter.RIGHT,padx=15,pady=8)
self.frame[3].pack(expand=1,fill=Tkinter.BOTH)
#接收消息
def receiveMessage(self):
try:
#建立Socket連接
self.clientSock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.clientSock.connect((self.local, self.port))
self.flag = True
except:
self.flag = False
self.chatText.insert(Tkinter.END,'您還未與服務器端建立連接,請檢查服務器端是否已經啟動')
return
self.buffer = 1024
self.clientSock.send('Y')
while True:
try:
if self.flag == True:
#連接建立,接收服務器端消息
self.serverMsg = self.clientSock.recv(self.buffer)
if self.serverMsg == 'Y':
self.chatText.insert(Tkinter.END,'客戶端已經與服務器端建立連接......')
elif self.serverMsg == 'N':
self.chatText.insert(Tkinter.END,'客戶端與服務器端建立連接失敗......')
elif not self.serverMsg:
continue
else:
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END, ' ' + self.serverMsg)
else:
break
except :
self.chatText.insert(Tkinter.END,'出現錯誤......')
self.clientSock.close()
self.close()
#發送消息
def sendMessage(self):
#情況1:從text_input獲取用戶輸入
#得到用戶在Text中輸入的消息
message = self.inputText.get('1.0',Tkinter.END)
#格式化當前的時間
theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.chatText.insert(Tkinter.END, '客戶端 ' + theTime +' 說:\n')
self.chatText.insert(Tkinter.END,' ' + message + '\n')
if self.flag == True:
#將消息發送到服務器端
self.clientSock.send(message);
else:
#Socket連接沒有建立,提示用戶
self.chatText.insert(Tkinter.END,'您還未與服務器端建立連接,服務器端無法收到您的消息\n')
#清空用戶在Text中輸入的消息
self.inputText.delete(0.0,message.__len__()-1.0)
#連接數據庫並操作
#def connectDatabaseRequest(self):
#點擊小提示請求server連接數據庫
#正常打字請求server回復
#關閉消息窗口並退出
def close(self):
sys.exit()
#啟動線程接收服務器端的消息
def startNewThread(self):
#啟動一個新線程來接收服務器端的消息
#thread.start_new_thread(function,args[,kwargs])函數原型,
#其中function參數是將要調用的線程函數,args是傳遞給線程函數的參數,它必須是個元組類型,而kwargs是可選的參數
#receiveMessage函數不需要參數,就傳一個空元組
thread.start_new_thread(self.receiveMessage,())
def main():
client = ClientUI()
client.startNewThread()
client.root.mainloop()
if __name__=='__main__':
main()
3、效果圖(好大!!!)


4、缺陷:
很多,比如tkinter界面太糟糕,交互過程太簡潔而且不合理,沒有認證過程,沒有加入多線程並發等等一大堆問題。
甚至有些代碼注釋還沒改,算了,正學django,以后弄一個完整的過程吧。
