IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  SOA and Web services  >

Python Web 服务开发人员: 现实世界,第一部分

Google Web API

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Scott Archer, 软件架构师, GlowingOrb, Inc.
Uche Ogbuji, 首席顾问, Fourthought, Inc.

2003 年 10 月 01 日

本专栏涵盖了可以用于 Web 服务处理的主要 Python API,通过简单的客户端和服务器的使用演示了基本的工具和方法。所有的这些都为使用“现实世界的” Web 服务打下了基础。笔者现在把这些工具和理解应用到几个现实世界的 Web 服务应用程序中。这里的着重点是 Google Web API-- 应用程序可以通过 SOAP 连接到它们,以便程序化地搜索 Web 并获取缓存的 Web 页面。

安装

对于下面的示例,我们将使用 Python version 2.2 和 SOAPpy version 0.10.2。也可以使用其他版本的 SOAPpy 和 Google API,不过,您需要修改这里列出的实例,以符合 SOAPpy 中对导入和方法签名所作的更改。SOAPpy 的安装是相当简单的:untar / unzip 软件包(在 Windows 中使用 winzip 或 cygwin),然后使用标准的 Python 包安装工具(安装一般作为 root 运行)。参见 清单1。同时参见本专栏结尾的 参考资料部分,以获得下载信息。

清单1. 使用标准的 python 包安装工具
[scott@daedalus SOAPpy-0.10.2]$ python setup.py build
running build
...
[root@daedalus SOAPpy-0.10.2]# python setup.py install
running install
...





回页首


Google API

为了使用 Google 的 API,您必须首先注册 Google,以获取一个 license-key。您将需要提供一个有效的电子邮件地址,这样就可以把您的 key 到其中。这个 key 不用花费任何任何费用,并且每天可以给您提供多达 1000 次查询。在写作本文时, Google 的 API 服务还是 beta 版本,没有商用(免费或者其他方式)的计划宣布。阅读 API 下载文档中的 license 文件或登陆 Google Web 站点,您就可以了解到关于有效使用和限制条件的细节和其他信息(参见 参考资料)。

下载 Google API 工具集。它不包含任何 Python,但是包括了很好的封装库和 Java 以及 .NET(使用 C# 和 Visual Basic) 的示例。在下载的工具集中包含一些我们可以立即使用的 GoogleSearch WSDL 文件和 Google API 参考手册(采用 HTML 格式)。正如您在 清单2的 WSDL 文件中看到的,Google API 提供了三种操作:

  1. doGoogleSearch( ) ,用于执行通过 Google 的 Web 查询(目前,该服务不支持搜索图形或者组)。
  2. doGetCachedPage( ) ,它将检索 Web 页面,在它的 Web-crawlers 遇到 Web 页面时,由 Google 来进行缓存。
  3. doSpellingSuggest( ) ,它将返回所提交的术语清单的正确拼写。

同时也请注意返回的 GoogleSearchResult 是复杂类型。





回页首


现在开始

对于第一次登陆 Google,我们将编写 Python 客户端程序来直接构造 XML 字符串形式的 SOAP 请求,并且使用 Python httplib 模块来发送一个 HTTP 消息(参见 清单3)。我们将搜索两个词“spotted owl”,请求不超过 10 个的结果项('maxResults')并以第一个开头('start', zero-indexed)——而且,我们将不使用任何过滤器和限制条件。将搜索限制在特定的语言('lr')并从结果中过滤掉成人内容是可能的。要获得关于这些方面的其他详细信息,请参见 Google Web API 参考文档(参见 参考资料)。这里,您可以开始看到连接到服务的简单性。

清单3. 使用 httplib 对 API 的直接 XML 访问
import sys, httplib 
 
_post = '/search/beta2'
_host = 'api.google.com'
_port = 80 
# envelope_template is a simple string template that matches the required
# Google API SOAP envelope as described in the WSDL
envelope_template = """<SOAP-ENV:Envelope 
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 
 xmlns:xsd="http://www.w3.org/1999/XMLSchema">
  <SOAP-ENV:Body>
    <ns1:doGoogleSearch xmlns:ns1="urn:GoogleSearch" 
         SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <key xsi:type="xsd:string">%s</key>
      <q xsi:type="xsd:string">%s</q>
      <start xsi:type="xsd:int">%d</start>
      <maxResults xsi:type="xsd:int">%d</maxResults>
      <filter xsi:type="xsd:boolean">%s</filter>
      <restrict xsi:type="xsd:string">%s</restrict>
      <safeSearch xsi:type="xsd:boolean">%s</safeSearch>
      <lr xsi:type="xsd:string">%s</lr>
      <ie xsi:type="xsd:string"></ie>
      <oe xsi:type="xsd:string"></oe>
    </ns1:doGoogleSearch>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>""" 
 
# Google search options - for populating the envelope-template
_license_key = 'INSERT YOUR KEY HERE' 
_query = 'spotted owl'
_start = 0
_maxResults = 10
_filter = 'false'
_restrict = ''
_safeSearch = 'false'
_lang_restrict = ''
# populate the outbound SOAP envelope
envelope = envelope_template%( _license_key, _query,
                               _start, _maxResults,
                               _filter, _restrict, 
                               _safeSearch, _lang_restrict ) 
# now, we open an HTTP connection, set required headers, and send the SOAP envelope
envlen = len(envelope) 
http_conn = httplib.HTTP(_host, _port) 
http_conn.putrequest('POST', _post) 
http_conn.putheader('Host', _host) 
http_conn.putheader('Content-Type', 'text/xml; charset="utf-8"') 
http_conn.putheader('Content-Length', str(envlen)) 
http_conn.putheader('SOAPAction', '') 
http_conn.endheaders() 
http_conn.send(envelope) 
# fetch HTTP reply headers and the response
(status_code, message, reply_headers) = http_conn.getreply() 
response = http_conn.getfile().read() 
# dump raw xml
print "----------------------------------------"
print "send headers:\\n", http_conn.headers
print "----------------------------------------"
print "send body:\\n", envelope
print "----------------------------------------"
print "   status code: ", status_code 
print "status message: ", message 
print " reply headers:\\n", reply_headers
print "----------------------------------------"
print "response body:\\n", response

清单3中的源代码注释将功能分为几个步骤。第一,在初始的导入之后,我们创建了一个字符,它包含 SOAP-Envelop 的模板,该模板与 清单2的 WSDL 中所定义的结构相匹配。下一步,为了更清楚地进行说明,我们设置了一些变量,以使用 Python 的字符串处理来填充 envelop_template 。然后,我们打开 POST 请求的 HTTP 连接来传送标准的消息头(header),然后发送请求信封(envelope)。在 清单4中我们可以看到来自 GoogleSearch 服务的 XML SOAP 响应。

清单4. 清单2的部分结果 -- 只显示10个结果的第1个(添加了缩排)。
<?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/1999/XMLSchema-instance" 
 xmlns:xsd="http://www.w3.org/1999/XMLSchema">
  <SOAP-ENV:Body>
    <ns1:doGoogleSearchResponse xmlns:ns1="urn:GoogleSearch" 
      SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <return xsi:type="ns1:GoogleSearchResult">
        <documentFiltering xsi:type="xsd:boolean">false</documentFiltering>
        <estimatedTotalResultsCount xsi:type="xsd:int">
                 117000
        </estimatedTotalResultsCount>
        <directoryCategories 
         xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" 
         xsi:type="ns2:Array" ns2:arrayType="ns1:DirectoryCategory[1]">
            <item xsi:type="ns1:DirectoryCategory">
              <specialEncoding xsi:type="xsd:string"></specialEncoding>
              <fullViewableName xsi:type="xsd:string">
              Top/Regional/North_America/United_States/Oregon/Localities/S/Sweet_Home
              </fullViewableName>
            </item>
        </directoryCategories>
        <searchTime xsi:type="xsd:double">0.074759</searchTime>
        <resultElements
         xmlns:ns3="http://schemas.xmlsoap.org/soap/encoding/" 
         xsi:type="ns3:Array" ns3:arrayType="ns1:ResultElement[10]">
            <item xsi:type="ns1:ResultElement">
              <cachedSize xsi:type="xsd:string">2k</cachedSize>
              <hostName xsi:type="xsd:string"></hostName>
              <snippet xsi:type="xsd:string">
                 A presentation of bird photographs, songs, identification tips, 
                 distribution maps, and life history information for North American 
                 birds, and a forum for <b>...</b> 
               </snippet>
               <directoryCategory xsi:type="ns1:DirectoryCategory">
                 <specialEncoding xsi:type="xsd:string"></specialEncoding>
                 <fullViewableName xsi:type="xsd:string"></fullViewableName>
               </directoryCategory>
               <relatedInformationPresent xsi:type="xsd:boolean">
                    true
               </relatedInformationPresent>
               <directoryTitle xsi:type="xsd:string"></directoryTitle>
               <summary xsi:type="xsd:string"></summary>
               <URL xsi:type="xsd:string">
               http://www.mbr-pwrc.usgs.gov/id/framlst/i3690id.html
               </URL>
               <title xsi:type="xsd:string">
                  <b>Spotted</b> <b>Owl</b>
               </title>
            </item>
                    ...
          </resultElements>
          <endIndex xsi:type="xsd:int">10</endIndex>
          <searchTips xsi:type="xsd:string"></searchTips>
          <searchComments xsi:type="xsd:string"></searchComments>
          <startIndex xsi:type="xsd:int">1</startIndex>
          <estimateIsExact xsi:type="xsd:boolean">false</estimateIsExact>
          <searchQuery xsi:type="xsd:string">spotted owl</searchQuery>
       </return>
     </ns1:doGoogleSearchResponse>
   </SOAP-ENV:Body>
  </SOAP-ENV:Envelope>





回页首


更好的方法

尽管直接使用 XML 构造 SOAP 请求,接着解析 XML SOAP 响应,是相当简单的,但是还有几个更高层次的库,它们提供了更加强大和直观的接口。在本专栏前面的讨论中已经探讨了一些这样的接口。尽管 Google Web API 是非常简单的,任何支持复杂类型的 SOAP 库或许都能够正常运行,但是我们将使用 Python 的 SOAPpy 库来与 Google Web 服务交谈。

在这个方法中,我们使用 SOAPProxy 来创建一个 Web 服务的代理(参见 清单5)。通过此 SOAP 代理,我们可以直接调用 Google Web API 上公开的方法——在本例中为 doGoogleSearch( ) 。SOAPpy 以透明的方式处理字符串和整型参数(key、q、start、maxResults、restrict、lr、ie 和 oe)的编组(marshall)。但是,我们必须显式地编组布尔型的数值(filter 和 safeSearch)。注意,根据 Google Web API 文档,最后的两个参数(ie 和 oe)不再使用,因此需要忽略。如果成功地调用了远程方法,SOAPProxy 会自动解析包含结果的 SOAP 对象来创建一个 Python 对象,这个 Python 对象与 WSDL 文档中所描述的结构相匹配。对结果对象的访问是直接通过 Python 属性进行的。

另外, SOAPpy 有一个调试模式,在 SOAPpy 安装中的 Config.py 的第 68 行,将 self.debug 更改为 1,这样就可以启用这个模式(在 *NIXes上,Config.py 文件位于:/usr/lib/Python2.2/site-packages/SOAPpy)。不幸的是,没有别的方法来启用这个特性。在启动了调试模式之后,所有在调用时交换的 HTTP Header 和原始 SOAP XML 将转处到到 stdout 中。

清单5. 使用 SOAPpy 来访问 Google API
from SOAPpy import SOAPProxy
from SOAPpy import Types
# CONSTANTS
_url = 'http://api.google.com/search/beta2'
_namespace = 'urn:GoogleSearch'
# need to marshall into SOAP types
SOAP_FALSE = Types.booleanType(0)
SOAP_TRUE = Types.booleanType(1)
# create SOAP proxy object
google = SOAPProxy(_url, _namespace)
# Google search options
_license_key = 'INSERT YOUR KEY HERE' 
_query = 'spotted owl'
_start = 0
_maxResults = 10
_filter = SOAP_FALSE
_restrict = ''
_safeSearch = SOAP_FALSE
_lang_restrict = ''
# call search method over SOAP proxy
results = google.doGoogleSearch( _license_key, _query, 
                                 _start, _maxResults, 
                                 _filter, _restrict,
                                 _safeSearch, _lang_restrict, '', '' )
           
# display results
print 'google search for  " ' + _query + ' "\\n'
print 'estimated result count: ' + str(results.estimatedTotalResultsCount)
print '           search time: ' + str(results.searchTime) + '\\n'
print 'results ' + str(_start + 1) + ' - ' + str(_start + _maxResults) +':\\n'
                                                       
numresults = len(results.resultElements)
for i in range(numresults):
    title = results.resultElements[i].title
    noh_title = title.replace('<b>', '').replace('</b>', '')
    print 'title: ' + noh_title
    print '  url: ' + results.resultElements[i].URL + '\\n'

这时,我们可以简单地使用 SOAPpy 中的 SOAPProxy 对象,而不用显式地创建 SOAP 信封(envelope)并通过 HTTP 发送它。如果为 Web 服务指定了可调用的 URL 和适当的命名空间,那么 SOAPpy 就可以用 Python 的动态绑定,来把调用参数甚至方法名称( doGoogleSearch( ) )编组为代理服务对象上的一个远程过程调用。然后,就可以访问响应,因为它作为一个聚合对象,与 WSDL 中所指定的 GoogleSearchResult 结构是相匹配的。为了显示这个结果,我们直接访问 results 对象的特性。

清单6. 清单5的结果
[scott@daedalus google_test]$ python google_test.py
google search for  " spotted owl "
estimated result count: 117000
           search time: 0.070122
results 1 - 10:
title: Spotted Owl
  url: http://www.mbr-pwrc.usgs.gov/id/framlst/i3690id.html
title: Mexican Spotted Owl - Home
  url: http://mso.fws.gov/
title: EO Study: Spotting the Spotted Owl
  url: http://earthobservatory.nasa.gov/Study/SpottedOwls/
title: Western Spotted Owl Printout- EnchantedLearning.com
  url: 
  http://www.enchantedlearning.com/subjects/birds/printouts/Spottedowlprintout.shtml
title: Northern Spotted Owl
  url: http://biology.usgs.gov/s+t/SNT/noframe/pn172.htm
title: AMNH - Expedition : Endangered  url: http://www.amnh.org/nationalcenter/Endangered/owl/owl.html
title: Northern Spotted Owl - USFS History - Forest History Society
  url: http://www.lib.duke.edu/forest/usfscoll/policy/northern_spotted_owl/
title: North American Owl Identification Guide
  url: http://www.owlinstitute.org/owls/spotted.html
title: Spotted Owls - Strix occidentalis
  url: http://www.owlpages.com/species/strix/occidentalis/Default.htm
title: The Northern Spotted Owl Debate
  url: http://www.spa3.k12.sc.us/WebQuests/endangeredanimals/endangered.htm

清单6是运行 清单5中的代码的纯文本输出。在显示了搜索中的一些状态之后,我们将遍历每个结果——这里显示了这些结果的标题和 URL。Google API 限定每次搜索取10个结果。注意作为 SOAP 响应的一部分返回的搜索时间——从33亿个 Web 页面中找到超过100,000个(估计)纪录的时间少于十分之一秒。 Google Web API 为强大的 Web 服务提供了易于使用的接口。





回页首


Google

如前所述,Google API 提供了比搜索更多的特征——通过 SOAP 接口也可以进行拼写建议和检索缓存的 Web 页面。下面继续我们前面讲过的“owl”主题,在 清单7中,我们使用 SOAPpy 中的 SOAPProxy 来获取 “www.owl.org” 的缓存版本。注意,获取缓存的 Web 页面的请求和响应笔搜索 Web 页面的请求和响应(分别为 doGetCachedPage()results )要容易得多。我们只需通过代理调用 doGetCachedPage() 来传递我们的 license key 和请求的 Web 页面就可以了。

清单7. 使用 SOAP.py 通过 Google API 获取缓存的 Web 页面
from SOAPpy import SOAPProxy
from SOAPpy import Types
# CONSTANTS
_url = 'http://api.google.com/search/beta2'
_namespace = 'urn:GoogleSearch'
# create SOAP proxy object
google = SOAPProxy(_url, _namespace)
# Google search options
_license_key = 'INSERT YOUR KEY HERE' 
_query = 'www.owls.org'
# call search method over SOAP proxy
results = google.doGetCachedPage( _license_key, _query )
           
# store results
of = open('cached_page_response.html', 'w')
of.write(results)
of.close()

Google API 返回缓存的base64 编码的页面。在接收到响应之后,SOAPpy 可以很方便地把这种格式的页面解码为 html——然后,我们把它保存到文件系统中,这样就可以通过浏览器进行查看了。这是一个简单的接口,也许是世界上最大的(也是最完整的)整个 Web 的缓存的接口。 图1显示了返回的页面,它已装载到浏览器中。注意,Google 带有一个消息头(header)来标识由 Google 缓存的页面。


请单 7 的输出


参考资料



作者简介

作者相片

Scott Archer 是一位软件架构师,也是 GlowingOrb, Inc. 的创始人,一个软件工具开发人员。他主要研究模型驱动的解决方案及其与核心业务流程的集成。Archer 从香港大学(University of Hong Kong)获得了 Computational Molecular Biology 的 M.Phil 学位。您可以通过 scott.archer at glowingorb.com 与 Mr. Archer联系。


作者相片

Uche Ogbuji 是一名顾问和 Fourthought Inc. 的创始人,一个软件供应商和顾问,专长于企业知识管理应用程序的 XML 解决方案。 Fourthought 开发了 4Suite ,XML 中间件的开放源码平台。Ogbuji 是一个计算机工程师和作者,出生于 Nigeria,生活和工作在美国科罗拉多州 Boulder。您可以通过 uche.ogbuji at fourthought.com 与 Ogbuji 联系。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款