您当前位置:首页 > 深入 Python > HTTP Web 服务 | << >> | ||||
深入 Python从 Python 新手到专家 |
您已经了解了HTML 处理和XML 处理,并且在此过程中您看到了如何下载网页以及如何解析来自 URL 的 XML,但让我们深入探讨更通用的主题:HTTP Web 服务。
简单地说,HTTP Web 服务是使用 HTTP 操作直接从远程服务器发送和接收数据的编程方法。如果要从服务器获取数据,请使用直接的 HTTP GET;如果要将新数据发送到服务器,请使用 HTTP POST。(一些更高级的 HTTP Web 服务 API 还定义了使用 HTTP PUT 和 HTTP DELETE 修改现有数据和删除数据的方法。)换句话说,内置于 HTTP 协议中的“动词”(GET、POST、PUT 和 DELETE)直接映射到用于接收、发送、修改和删除数据的应用程序级操作。
这种方法的主要优点是简单性,其简单性已在许多不同站点中得到证明。数据(通常是 XML 数据)可以静态构建和存储,也可以由服务器端脚本动态生成,并且所有主要语言都包含用于下载数据的 HTTP 库。调试也更容易,因为您可以在任何 Web 浏览器中加载 Web 服务并查看原始数据。现代浏览器甚至会为您很好地格式化和美化 XML 数据,以便您快速浏览它。
纯 XML over HTTP Web 服务示例
在后面的章节中,您将探索使用 HTTP 作为传输层来发送和接收数据的 API,但不会将应用程序语义映射到底层 HTTP 语义。(它们通过 HTTP POST 隧道传输所有内容。)但本章将集中讨论使用 HTTP GET 从远程服务器获取数据,并且您将探索可以使用的一些 HTTP 功能,以充分利用纯 HTTP Web 服务。
以下是您在上一章中看到的 openanything 模块的更高级版本
如果您还没有这样做,则可以下载本书中使用的此示例和其他示例。
import urllib2, urlparse, gzip from StringIO import StringIO USER_AGENT = 'OpenAnything/1.0 +https://diveintopythonbook.pythonlang.cn/http_web_services/' class SmartRedirectHandler(urllib2.HTTPRedirectHandler): def http_error_301(self, req, fp, code, msg, headers): result = urllib2.HTTPRedirectHandler.http_error_301( self, req, fp, code, msg, headers) result.status = code return result def http_error_302(self, req, fp, code, msg, headers): result = urllib2.HTTPRedirectHandler.http_error_302( self, req, fp, code, msg, headers) result.status = code return result class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler): def http_error_default(self, req, fp, code, msg, headers): result = urllib2.HTTPError( req.get_full_url(), code, msg, headers, fp) result.status = code return result def openAnything(source, etag=None, lastmodified=None, agent=USER_AGENT): '''URL, filename, or string --> stream This function lets you define parsers that take any input source (URL, pathname to local or network file, or actual data as a string) and deal with it in a uniform manner. Returned object is guaranteed to have all the basic stdio read methods (read, readline, readlines). Just .close() the object when you're done with it. If the etag argument is supplied, it will be used as the value of an If-None-Match request header. If the lastmodified argument is supplied, it must be a formatted date/time string in GMT (as returned in the Last-Modified header of a previous request). The formatted date/time will be used as the value of an If-Modified-Since request header. If the agent argument is supplied, it will be used as the value of a User-Agent request header. ''' if hasattr(source, 'read'): return source if source == '-': return sys.stdin if urlparse.urlparse(source)[0] == 'http': # open URL with urllib2 request = urllib2.Request(source) request.add_header('User-Agent', agent) if etag: request.add_header('If-None-Match', etag) if lastmodified: request.add_header('If-Modified-Since', lastmodified) request.add_header('Accept-encoding', 'gzip') opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler()) return opener.open(request) # try to open with native open function (if source is a filename) try: return open(source) except (IOError, OSError): pass # treat source as string return StringIO(str(source)) def fetch(source, etag=None, last_modified=None, agent=USER_AGENT): '''Fetch data and metadata from a URL, file, stream, or string''' result = {} f = openAnything(source, etag, last_modified, agent) result['data'] = f.read() if hasattr(f, 'headers'): # save ETag, if the server sent one result['etag'] = f.headers.get('ETag') # save Last-Modified header, if the server sent one result['lastmodified'] = f.headers.get('Last-Modified') if f.headers.get('content-encoding', '') == 'gzip': # data came back gzip-compressed, decompress it result['data'] = gzip.GzipFile(fileobj=StringIO(result['data']])).read() if hasattr(f, 'url'): result['url'] = f.url result['status'] = 200 if hasattr(f, 'status'): result['status'] = f.status f.close() return result
<< 总结 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
如何不通过 HTTP 获取数据 >> |