首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用httplib的IncompleteRead

使用httplib的IncompleteRead
EN

Stack Overflow用户
提问于 2013-01-04 07:43:57
回答 3查看 28.1K关注 0票数 26

从特定网站获取rss提要时,我一直有一个持续的问题。我最终写了一个相当难看的过程来执行这个函数,但我很好奇为什么会发生这种情况,以及是否有更高级别的接口正确地处理了这个问题。这个问题并不是真正的阻碍,因为我不需要经常检索提要。

我已经阅读了一个捕获异常并返回部分内容的解决方案,然而,由于未完成的读取在实际检索的字节数量上有所不同,我不确定这种解决方案是否真的有效。

代码语言:javascript
复制
#!/usr/bin/env python
import os
import sys
import feedparser
from mechanize import Browser
import requests
import urllib2
from httplib import IncompleteRead

url = 'http://hattiesburg.legistar.com/Feed.ashx?M=Calendar&ID=543375&GUID=83d4a09c-6b40-4300-a04b-f88884048d49&Mode=2013&Title=City+of+Hattiesburg%2c+MS+-+Calendar+(2013)'

content = feedparser.parse(url)
if 'bozo_exception' in content:
    print content['bozo_exception']
else:
    print "Success!!"
    sys.exit(0)

print "If you see this, please tell me what happened."

# try using mechanize
b = Browser()
r = b.open(url)
try:
    r.read()
except IncompleteRead, e:
    print "IncompleteRead using mechanize", e

# try using urllib2
r = urllib2.urlopen(url)
try:
    r.read()
except IncompleteRead, e:
    print "IncompleteRead using urllib2", e


# try using requests
try:
    r = requests.request('GET', url)
except IncompleteRead, e:
    print "IncompleteRead using requests", e

# this function is old and I categorized it as ...
# "at least it works darnnit!", but I would really like to 
# learn what's happening.  Please help me put this function into
# eternal rest.
def get_rss_feed(url):
    response = urllib2.urlopen(url)
    read_it = True
    content = ''
    while read_it:
        try:
            content += response.read(1)
        except IncompleteRead:
            read_it = False
    return content, response.info()


content, info = get_rss_feed(url)

feed = feedparser.parse(content)

如前所述,这不是一个任务关键型问题,但我很好奇,因为尽管我可以预期urllib2会有这个问题,但我很惊讶在机械化和请求中也会遇到这个错误。feedparser模块甚至不会抛出错误,因此检查错误依赖于“bozo_exception”键的存在。

编辑:我只想提一下,wget和curl都完美地执行了函数,每次都能正确地检索完整的有效负载。我还没有找到一个纯粹的python方法来工作,除了我丑陋的hack,我非常好奇地想知道httplib的后端发生了什么。开个玩笑,我决定前几天也用twill尝试一下,得到了同样的httplib错误。

另外,还有一件事让我觉得很奇怪。IncompleteRead始终在有效负载中的两个断点之一发生。似乎feedparser和请求在读取926字节后失败,而mechanize和urllib2在读取1854字节后失败。这种行为是一致的,我没有得到任何解释或理解。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-08 07:41:46

最后,所有其他模块(feedparsermechanizeurllib2)都会调用httplib,这就是抛出异常的地方。

现在,首先,我还用wget下载了这个文件,结果文件是1854字节。接下来,我尝试使用urllib2

代码语言:javascript
复制
>>> import urllib2
>>> url = 'http://hattiesburg.legistar.com/Feed.ashx?M=Calendar&ID=543375&GUID=83d4a09c-6b40-4300-a04b-f88884048d49&Mode=2013&Title=City+of+Hattiesburg%2c+MS+-+Calendar+(2013)'
>>> f = urllib2.urlopen(url)
>>> f.headers.headers
['Cache-Control: private\r\n',
 'Content-Type: text/xml; charset=utf-8\r\n',
 'Server: Microsoft-IIS/7.5\r\n',
 'X-AspNet-Version: 4.0.30319\r\n',
 'X-Powered-By: ASP.NET\r\n',
 'Date: Mon, 07 Jan 2013 23:21:51 GMT\r\n',
 'Via: 1.1 BC1-ACLD\r\n',
 'Transfer-Encoding: chunked\r\n',
 'Connection: close\r\n']
>>> f.read()
< Full traceback cut >
IncompleteRead: IncompleteRead(1854 bytes read)

因此,它正在读取所有1854个字节,但随后认为还会有更多字节。如果我们显式地告诉它只读取1854个字节,它就可以工作:

代码语言:javascript
复制
>>> f = urllib2.urlopen(url)
>>> f.read(1854)
'\xef\xbb\xbf<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">...snip...</rss>'

显然,只有当我们总是提前知道确切的长度时,这才是有用的。我们可以使用部分读取作为异常的属性返回的事实来捕获全部内容:

代码语言:javascript
复制
>>> try:
...     contents = f.read()
... except httplib.IncompleteRead as e:
...     contents = e.partial
...
>>> print contents
'\xef\xbb\xbf<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">...snip...</rss>'

This blog post认为这是服务器的故障,并描述了如何使用上面的try..except块修补httplib.HTTPResponse.read()方法来处理幕后的事情:

代码语言:javascript
复制
import httplib

def patch_http_response_read(func):
    def inner(*args):
        try:
            return func(*args)
        except httplib.IncompleteRead, e:
            return e.partial

    return inner

httplib.HTTPResponse.read = patch_http_response_read(httplib.HTTPResponse.read)

我应用了补丁,然后feedparser工作了:

代码语言:javascript
复制
>>> import feedparser
>>> url = 'http://hattiesburg.legistar.com/Feed.ashx?M=Calendar&ID=543375&GUID=83d4a09c-6b40-4300-a04b-f88884048d49&Mode=2013&Title=City+of+Hattiesburg%2c+MS+-+Calendar+(2013)'
>>> feedparser.parse(url)
{'bozo': 0,
 'encoding': 'utf-8',
 'entries': ...
 'status': 200,
 'version': 'rss20'}

这不是最好的方式,但它似乎是有效的。我不是HTTP协议的专家,无法确定服务器是否做错了事情,或者httplib是否错误地处理了边缘情况。

票数 26
EN

Stack Overflow用户

发布于 2013-12-18 06:14:40

在我的例子中,我发现了,发送一个HTTP/1.0请求,修复问题,只需将以下代码添加到代码中:

代码语言:javascript
复制
import httplib
httplib.HTTPConnection._http_vsn = 10
httplib.HTTPConnection._http_vsn_str = 'HTTP/1.0'

在我完成请求之后:

代码语言:javascript
复制
req = urllib2.Request(url, post, headers)
filedescriptor = urllib2.urlopen(req)
img = filedescriptor.read()

在我使用返回http 1.1之后(对于支持1.1的连接):

代码语言:javascript
复制
httplib.HTTPConnection._http_vsn = 11
httplib.HTTPConnection._http_vsn_str = 'HTTP/1.1'
票数 7
EN

Stack Overflow用户

发布于 2019-03-04 03:55:14

我已经修复了这个问题,使用HTTPS而不是HTTP,它工作得很好。不需要更改代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14149100

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档