DiveIntoPython(十一)
英文书地址:
http://diveintopython.org/toc/index.html
Chapter 12.SOAP Web Services
Rather than dealing with HTTP requests and XML documents directly, SOAP allows you to simulate calling functions that return native data types.
As you will see, the illusion is almost perfect; you can “call” a function through a SOAP library, with the standard Python calling syntax, and the function appears to return Python objects and values.
12.1.Diving In
example 12.1.search.py
example 12.2.Sample Usage of search.py
12.2.Installing the SOAP Libraries
Before you can dive into SOAP web services, you'll need to install three libraries: PyXML, fpconst, and SOAPpy.
12.2.1.Installing PyXML
The first library you need is PyXML, an advanced set of XML libraries that provide more functionality than the built-in XML libraries we studied in Chapter 9.
1.Go to http://sourceforge.net/projects/pyxml/files/
download the latest version for your operating system.
2.My operation system is windows and my python version is 2.6,so I will install pyxml from sources.
I follow the step of this page:
http://www.linuxfromscratch.org/blfs/view/cvs/general/python-modules.html#pyxml
my system is windows, so I get PyXML-0.8.4.tar.gz and unzip it and type this command:
>python setup.py build
I got this error message:
building '_xmlplus.parsers.pyexpat' extension
error: Unable to find vcvarsall.bat
solution:
Download and install Microsoft Visual C++ 2008 Express Edition.
>python setup.py install
example 12.3.Verifying PyXML Installation
>>> import xml
>>> xml.__version__
'0.8.4'
>>>
12.2.2.Installing fpconst
The second library you need is fpconst, a set of constants and functions for working with IEEE754 double-precision special values. This provides support for the special values Not-a-Number (NaN), Positive Infinity (Inf), and Negative Infinity (-Inf), which are part of the SOAP datatype specification.
1.download the latest version of fpconst from http://sourceforge.net/projects/rsoap/files/fpconst
2.decompress the downloaded file fpconst-0.7.3.zip
3.type
>python setup.py install
example 12.4.Verifying fpconst Installation
>>> import fpconst
>>> fpconst.__version__
'0.7.3'
12.2.3.Installing SOAPpy
1.Go to http://pywebsvcs.sourceforge.net/ and select Latest Official Release
2.decompress downloaded file SOAPpy-0.12.0.zip
3.type
>python setup.py install
we get the error messages below:
Traceback (most recent call last):
File "setup.py", line 8, in <module>
from SOAPpy.version import __version__
File "E:\tools\python\soappy\SOAPpy-0.12.0\SOAPpy\__init__.py", line 5, in <module>
from Client import *
File "E:\tools\python\soappy\SOAPpy-0.12.0\SOAPpy\Client.py", line 46
from __future__ import nested_scopes
SyntaxError: from __future__ imports must occur at the beginning of the file
solution-google from the net:
modify three files from this directory E:\tools\python\soappy\SOAPpy-0.12.0\SOAPpy:
Client.py
Types.py
Server.py
move the code of "from __future__ import nested_scopes" to the top of the files
example 12.5.Verifying SOAPpy Installation
>>> import SOAPpy
>>> SOAPpy.__version__
'0.12.0'
>>>
12.3.First Steps with SOAP
The most popular public access SOAP server is http://www.xmethods.net/. This example uses a demonstration function that takes a United States zip code and returns the current temperature in that region.
example 12.6.Getting the Current Temperature(the service of temperature may be removed,so I only type the code here to study,you can't demonstrate)
>>> from SOAPpy import SOAPProxy
>>> url = 'http://services.xmethods.net:80/soap/servlet/rpcrouter'
>>> namespace = 'urn:xmethods-Temperature'
>>> server = SOAPProxy(url, namespace)
>>> server.getTemp('27502')
80.0
You're creating the SOAPProxy with the service URL and the service namespace. This doesn't make any connection to the SOAP server; it simply creates a local Python object.
12.4.Debugging SOAP Web Services
Turning on debugging is a simple matter of setting two flags in the SOAPProxy's configuration.
example 12.7.Debugging SOAP Web Services
>>> from SOAPpy import SOAPProxy
>>> url = 'http://services.xmethods.net:80/soap/servlet/rpcrouter'
>>> n = 'urn:xmethods-Temperature'
>>> server = SOAPProxy(url, namespace=n)
>>> server.config.dumpSOAPOut = 1
>>> server.config.dumpSOAPIn = 1
>>> temperature = server.getTemp('27502')
*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTemp xmlns:ns1="urn:xmethods-Temperature" SOAP-ENC:root="1">
<v1 xsi:type="xsd:string">27502</v1>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
************************************************************************
*** Incoming SOAP ******************************************************
<?xml version='1.0' encoding='UTF-8'?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:float">80.0</return>
</ns1:getTempResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
************************************************************************
>>> temperature
80.0
Second, turn on debugging by setting server.config.dumpSOAPIn and server.config.dumpSOAPOut.
The heart of the “function call” is this fragment within the <Body> element:
<ns1:getTemp
xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENC:root="1">
<v1 xsi:type="xsd:string">27502</v1>
</ns1:getTemp>
The XML return document is equally easy to understand, once you know what to ignore. Focus on this fragment within the <Body>:
<ns1:getTempResponse
xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:float">80.0</return>
</ns1:getTempResponse>
12.5.Introducing WSDL
The SOAPProxy class proxies local method calls and transparently turns then into invocations of remote SOAP methods.
A WSDL file is just that: a file. More specifically, it's an XML file. It usually lives on the same server you use to access the SOAP web services it describes, although there's nothing special about it. Later in this chapter, we'll download the WSDL file for the Google API and use it locally. That doesn't mean we're calling Google locally; the WSDL file still describes the remote functions sitting on Google's server.
A WSDL file contains a description of everything involved in calling a SOAP web service:
1. The service URL and namespace
2. The type of web service (probably function calls using SOAP, although as I mentioned, WSDL is flexible enough to describe a wide variety of web services)
3. The list of available functions
4. The arguments for each function
5. The datatype of each argument
6. The return values of each function, and the datatype of each return value
12.6.Introspecting SOAP Web Services with WSDL
The most fundamental thing that WSDL allows you to do is discover the available methods offered by a SOAP server.
example 12.8.Discovering The Available Methods
>>> from SOAPpy import WSDL
>>> wsdlfile = 'http://labs.safelayer.com/demo/wsdl/DigitalSignature.wsdl'
>>> server = WSDL.Proxy(wsdlfile)
C:\Python26\lib\site-packages\SOAPpy\wstools\XMLSchema.py:2871: DeprecationWarning: object.__init__() takes no parameters
tuple.__init__(self, args)
>>> server.methods.keys()
[u'Sign']
example 12.9.Discovering A Method's Arguments
>>> callInfo = server.methods['Sign']
>>> callInfo.inparams
[<SOAPpy.wstools.WSDLTools.ParameterInfo instance at 0x01E2ECD8>]
>>> callInfo.inparams[0].name
u'SignRequest'
>>> callInfo.inparams[0].type
(u'http://www.docs.oasis-open.org/dss/2004/06/oasis-dss-1.0-core-schema-wd-27.xsd', u'SignRequest')
The function arguments are stored in callInfo.inparams, which is a Python list of ParameterInfo objects that hold information about each parameter.
Each ParameterInfo object contains a name attribute, which is the argument name. You are not required to know the argument name to call the function through SOAP, but SOAP does support calling functions with named arguments (just like Python), and WSDL.Proxy will correctly handle mapping named arguments to the remote function if you choose to use them.
example 12.10.Discovering A Method's Reture Values
>>> callInfo.outparams
[<SOAPpy.wstools.WSDLTools.ParameterInfo instance at 0x01E2ED00>]
>>> callInfo.outparams[0].name
u'SignResponse'
>>> callInfo.outparams[0].type
(u'http://www.docs.oasis-open.org/dss/2004/06/oasis-dss-1.0-core-schema-wd-27.xsd', u'SignResponse')
example 12.11.Calling A Web Service Through A WSDL Proxy
>>> from SOAPpy import WSDL
>>> wsdlFile = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl')
>>> server = WSDL.Proxy(wsdlFile)
>>> server.getTemp('90210')
66.0
>>> server.soapproxy.config.dumpSOAPOut = 1
>>> server.soapproxy.config.dumpSOAPIn = 1
>>> temperature = server.getTemp('90210')
*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTemp xmlns:ns1="urn:xmethods-Temperature" SOAP-ENC:root="1">
<v1 xsi:type="xsd:string">90210</v1>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
************************************************************************
*** Incoming SOAP ******************************************************
<?xml version='1.0' encoding='UTF-8'?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:float">66.0</return>
</ns1:getTempResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
************************************************************************
>>> temperature
66.0
12.7.Searching Google
Signing Up for Google Web Services
1.Go to http://www.google.com/apis ,get the wsdl file here:
http://soapclient.com/xml/googleSearch.wsdl
2.save the file googleSearch.wsdl
example 12.12.Introspecting Google Web Services
>>> from SOAPpy import WSDL
>>> server = WSDL.Proxy("D:/data/googleSearch.wsdl")
>>> server.methods.keys()
[u'doGoogleSearch', u'doGetCachedPage', u'doSpellingSuggestion']
>>> callInfo = server.methods['doGoogleSearch']
>>> for arg in callInfo.inparams:
... print arg.name.ljust(15),arg.type
...
key (u'http://www.w3.org/2001/XMLSchema', u'string')
q (u'http://www.w3.org/2001/XMLSchema', u'string')
start (u'http://www.w3.org/2001/XMLSchema', u'int')
maxResults (u'http://www.w3.org/2001/XMLSchema', u'int')
filter (u'http://www.w3.org/2001/XMLSchema', u'boolean')
restrict (u'http://www.w3.org/2001/XMLSchema', u'string')
safeSearch (u'http://www.w3.org/2001/XMLSchema', u'boolean')
lr (u'http://www.w3.org/2001/XMLSchema', u'string')
ie (u'http://www.w3.org/2001/XMLSchema', u'string')
oe (u'http://www.w3.org/2001/XMLSchema', u'string')
example 12.13.Searching Google(the url page changed)
>>> from SOAPpy import WSDL
>>> server = WSDL.Proxy('/path/to/your/GoogleSearch.wsdl')
>>> key = 'YOUR_GOOGLE_API_KEY'
>>> results = server.doGoogleSearch(key, 'mark', 0, 10, False, "",
... False, "", "utf-8", "utf-8")
>>> len(results.resultElements)
10
>>> results.resultElements[0].URL
'http://diveintomark.org/'
>>> results.resultElements[0].title
'dive into <b>mark</b>'
example 12.14.Accessing Secondary Information From Google
>>> results.searchTime
0.224919
>>> results.estimatedTotalResultsCount
29800000
>>> results.directoryCategories
[<SOAPpy.Types.structType item at 14367400>:
{'fullViewableName':
'Top/Arts/Literature/World_Literature/American/19th_Century/Twain,_Mark',
'specialEncoding': ''}]
>>> results.directoryCategories[0].fullViewableName
'Top/Arts/Literature/World_Literature/American/19th_Century/Twain,_Mark'
12.8.Troubleshooting SOAP Web Services