Python Web 服务开发者: 现实世界,第二部分
2007-03-29 12:13:08 来源:WEB开发网从 清单 5 的第一部分中您可以看到,有 26 个请求方法定义在 Amazon API 的 WSDL 中。关于参数和返回结构的详细消息可以在 Amazon 中的 WSDL 和开发者文档中找到。尽管代码无疑可以被扩展以执行更为高级的查询,但是在本例中我们仅使用 KeywordSearchRequest 方法。
完全不同之处
现在我们可以利用关于 Amazon Web 服务 API 的知识来做些有用的事情。Python 经常被很多人责备,认为它在 GUI 创建的领域中跟不上其他理解 SOAP 的语言。其实,利用 Python 可以很容易地创建出强大且真正意义上跨平台的用户界面。为了证明这一点,我们将使用 Python 和 wxPython UI 库来创建一个小 GUI 应用程序,以便执行关键字搜索来查找书籍(book)、音乐(music)和 dvd。 图 1展示了我们运行中的 GUI。
选定产品种类(在 Amazon 中也称为 模式),输入您的关键字查询(各个关键字由空格格开)并点击‘Search Amazon’按钮。您的网络集线器上的灯就会开始闪烁,几秒钟后,‘Query Results’列表框就将添满。选择一个条目来查看详细信息,如果可能的话,查看条目的图像。为了简单起见,我们只获取不超过 10 个条目的第一页。这很容易扩展。
清单 6 展示了我们的应用程序代码。基本上,它是我们的测试应用程序,嵌入到一个用户界面中,并扩展为搜索音乐(music)和 dvd,并显示所获取条目的详细信息以及图像。
清单 6. amazon_widget.py —— Amazon.com 搜索 GUI 的 Python 代码.
#!/usr/bin/python
# setup SOAP proxy
import SOAPpy
file = 'AmazonWebServices.wsdl'
amazon = SOAPpy.WSDL.Proxy(file)
# import the wxPython libraries
import wxPython.wx
from wxPython.wx import *
import urllib
# developer token for amazon api
DEV_TOKEN = 'INSERT YOUR TOKEN HERE'
# event ids
ID_SEARCH = 100
ID_SELCHG = 101
#------------------------------------------------------------------------------
# amazonWidgetFrame - the main window for our app
#------------------------------------------------------------------------------
class amazonWidgetFrame(wxFrame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, wxSize(500, 475))
# add a status bar
self.CreateStatusBar()
self.SetStatusText("")
# add other widgets to frame
frame_box = wxBoxSizer(wxVERTICAL)
# query part
query_box = wxBoxSizer(wxHORIZONTAL)
# set the mode (product line to search)
mode_box =
wxStaticBoxSizer(wxStaticBox(self, -1, "Product Line"), wxVERTICAL)
self.mode_books =
wxRadioButton(self, -1, "books",
wxDefaultPosition, wxDefaultSize, wxRB_GROUP)
self.mode_music = wxRadioButton(self, -1, "music",
wxDefaultPosition, wxDefaultSize)
self.mode_dvds = wxRadioButton(self, -1, "dvd",
wxDefaultPosition, wxDefaultSize)
mode_box.Add(self.mode_books, 0, wxLEFT|wxRIGHT, 10)
mode_box.Add(self.mode_music, 0, wxLEFT|wxRIGHT, 10)
mode_box.Add(self.mode_dvds, 0, wxLEFT|wxRIGHT, 10)
query_box.Add(mode_box, 0, wxALL, 5)
# edit and button
qtext_box =
wxStaticBoxSizer(wxStaticBox(self, -1, "Enter Query"), wxHORIZONTAL)
self.search_text =
wxTextCtrl(self, -1, "python web", wxDefaultPosition, (200, -1))
qtext_box.Add(self.search_text, 1, wxALL, 5)
qtext_box.Add(wxButton(self, ID_SEARCH, "Search Amazon"), 0, wxALL, 5)
query_box.Add(qtext_box, 0, wxALL, 5)
frame_box.Add(query_box, 0, wxBOTTOM, 5)
# results part
results_box = wxBoxSizer(wxHORIZONTAL)
# details
details_box =
wxStaticBoxSizer(wxStaticBox(self, -1, "Query Results"), wxVERTICAL)
self.results_list =
wxListBox(self, ID_SELCHG, wxDefaultPosition, (300,175),
[], wxLB_ALWAYS_SB)
details_box.Add(self.results_list, 0, wxALL, 5)
hbox = wxBoxSizer(wxHORIZONTAL)
tbox = wxBoxSizer(wxVERTICAL)
tbox.Add(wxStaticText(self, -1, "Author/Artist: "), 0, wxLEFT, 5)
tbox.Add(wxStaticText(self, -1, ""), 0, wxLEFT, 5)
hbox.Add(tbox, 0)
hbox.Add(20,0,1)
self.authors = wxListBox(self, -1, wxDefaultPosition, (200,65), [])
hbox.Add(self.authors, 0, wxALIGN_RIGHT)
details_box.Add(hbox, 0, wxBOTTOM, 5)
hbox = wxBoxSizer(wxHORIZONTAL)
hbox.Add(wxStaticText(self, -1, "Release Date: "), 0, wxLEFT, 5)
self.release_date = wxStaticText(self, -1, " ",
wxDefaultPosition, wxDefaultSize)
hbox.Add(self.release_date, 0)
details_box.Add(hbox, 0)
hbox = wxBoxSizer(wxHORIZONTAL)
hbox.Add(wxStaticText(self, -1, "List Price: "), 0, wxLEFT, 5)
self.list_price = wxStaticText(self, -1, " ",
wxDefaultPosition, wxDefaultSize)
hbox.Add(self.list_price, 0)
details_box.Add(hbox, 0)
hbox = wxBoxSizer(wxHORIZONTAL)
hbox.Add(wxStaticText(self, -1, "Amazon.com Price: "), 0, wxLEFT, 5)
self.amazon_price = wxStaticText(self, -1, " ",
wxDefaultPosition, wxDefaultSize)
hbox.Add(self.amazon_price, 0)
details_box.Add(hbox, 0, wxBOTTOM, 5)
results_box.Add(details_box, 0, wxALL, 5)
# image
image_box =
wxStaticBoxSizer(wxStaticBox(self, -1, "Product Image"), wxHORIZONTAL)
# inline class for drawing our product image
class amazonImagePanel(wxPanel):
def __init__(self, parent, id, position, size):
wxPanel.__init__(self, parent, id, position, size)
self.parent = parent
self.image = None
EVT_PAINT(self, self.OnPaint)
def OnPaint(self, evt):
dc = wxPaintDC(self)
if self.image:
bitmap = wxBitmapFromImage(self.image)
dc.DrawBitmap(bitmap, 0, 0, false)
self.image_canvas = amazonImagePanel(self, -1, wxDefaultPosition, (130,150))
image_box.Add(self.image_canvas, 1, wxALL, 5)
results_box.Add(image_box, 0, wxALL, 5)
# finally...
frame_box.Add(results_box, 0, wxTOP, 5)
# add main sizer
self.SetSizer(frame_box)
# set event handlers
EVT_BUTTON(self, ID_SEARCH, self.OnSearch)
EVT_LISTBOX(self, ID_SELCHG, self.OnSelectionChange)
#---------------------------------------------------------------------
# build and call query - if returns OK, set the GUI fields
#---------------------------------------------------------------------
def OnSearch(self, event):
# fetch mode and query text
query = self.search_text.GetValue()
self.mode = 'books'
if self.mode_music.GetValue():
self.mode = 'music'
elif self.mode_dvds.GetValue():
self.mode = 'dvd'
request = { 'keyword': query, 'page': '1', 'mode': self.mode,
'tag': '', 'type': 'lite', 'devtag': DEV_TOKEN }
# do the query
try:
tmp_results = amazon.KeywordSearchRequest(request)
except SOAPpy.faultType:
self.SetStatusText('There were no exact matches for the search')
else:
self.results = tmp_results
self.SetStatusText('total results: ' + str(self.results.TotalResults) +
' (only showing first 10)')
# load up results box
items = []
images = []
for detail in self.results.Details:
items.append(detail['ProductName'])
images.append(detail['ImageUrlMedium'])
self.results_list.Set(items)
self.results_list.SetFirstItem(0)
# clear displayed image
self.authors.Set([])
self.release_date.SetLabel('')
self.list_price.SetLabel('')
self.amazon_price.SetLabel('')
self.image_canvas.image = None
self.image_canvas.Refresh()
# cache images
self.loadImages(images)
#---------------------------------------------------------------------
# whenever the product selection changes, update other fields
#---------------------------------------------------------------------
def OnSelectionChange(self, event):
# fetch selected item from results
sel = self.results_list.GetSelections()
detail = self.results.Details[sel[0]]
# set the author/artist field
items = []
if self.mode == 'books':
if 'Authors' in detail._keys():
authors = detail['Authors']
for author in authors:
items.append(author)
self.authors.Set(items)
elif self.mode == 'music':
if 'Artists' in detail._keys():
authors = detail['Artists']
for author in authors:
items.append(author)
self.authors.Set(items)
elif self.mode == 'dvd':
# only in 'heavy' search type
if 'Directors' in detail._keys():
authors = detail['Directors']
for author in authors:
items.append(author)
self.authors.Set(items)
# set release date and pricing fields
if 'ReleaseDate' in detail._keys():
self.release_date.SetLabel(detail['ReleaseDate'])
if 'ListPrice' in detail._keys():
self.list_price.SetLabel(detail['ListPrice'])
if 'OurPrice' in detail._keys():
self.amazon_price.SetLabel(detail['OurPrice'])
# fetch image
image_name = 'image_tmp_' + str(sel[0]) + '.jpg'
self.image_canvas.image = wxImage(image_name)
self.image_canvas.Refresh()
#---------------------------------------------------------------------
# retrieve from amazon.com and temporarily save images
#---------------------------------------------------------------------
def loadImages(self, images):
i = 0
for url in images:
image_name = 'image_tmp_' + str(i) + '.jpg'
pic = urllib.urlopen(url)
img = pic.read()
pic.close()
f = open(image_name,'wb')
f.write(img)
f.close()
i = i+1
#------------------------------------------------------------------------------
# simple wxApp
#------------------------------------------------------------------------------
class amazonWidgetApp(wxApp):
def __init__(self, parent):
wxApp.__init__(self, parent)
def OnInit(self):
# start GUI
frame = amazonWidgetFrame(NULL, -1, "Amazon.com SOAP Widget")
frame.Show(true)
self.SetTopWindow(frame)
return true
#------------------------------------------------------------------------------
# run this when module gets called
#------------------------------------------------------------------------------
if __name__ == '__main__':
# must call this for wxImage to load JPEGs
wx.wxInitAllImageHandlers()
app = amazonWidgetApp(0)
app.MainLoop()
更多精彩
赞助商链接