2013-01-03 3 views
21

का उपयोग करके अधूरा पढ़ें मुझे किसी विशेष वेबसाइट से आरएसएस फ़ीड प्राप्त करने में लगातार समस्या आ रही है। मैं इस समारोह को करने के लिए एक बदसूरत प्रक्रिया लिखना घायल हो गया, लेकिन मुझे उत्सुकता है कि ऐसा क्यों होता है और क्या कोई उच्च स्तरीय इंटरफेस इस समस्या को ठीक तरह से संभालता है। यह समस्या वास्तव में एक शो स्टॉपर नहीं है, क्योंकि मुझे अक्सर फ़ीड को पुनः प्राप्त करने की आवश्यकता नहीं होती है।प्रोजेक्टप्लिब

मैंने एक समाधान पढ़ा है जो अपवाद का पता लगाता है और आंशिक सामग्री देता है, फिर भी अधूरा पढ़ता है जो वास्तव में पुनर्प्राप्त बाइट्स की मात्रा में भिन्न होता है, मुझे कोई निश्चितता नहीं है कि ऐसा समाधान वास्तव में काम करेगा।

#!/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 उम्मीद कर सकते हैं, मुझे आश्चर्य है कि इस त्रुटि मशीनीकरण और अनुरोधों में रूप में अच्छी तरह का सामना करना पड़ा रहा है । फीडपार्सर मॉड्यूल भी एक त्रुटि फेंक नहीं देता है, इसलिए त्रुटियों की जांच करना 'bozo_exception' कुंजी की उपस्थिति पर निर्भर करता है।

संपादित करें: मैं बस यह उल्लेख करना चाहता था कि दोनों wget और curl फ़ंक्शन को निष्पादित करते हैं, हर बार सही पेलोड को सही तरीके से पुनर्प्राप्त करते हैं। मुझे अभी तक मेरे बदसूरत हैक को छोड़कर काम करने के लिए एक शुद्ध पायथन विधि नहीं मिली है, और मुझे यह जानकर बहुत उत्सुकता है कि प्रेजेंटप्लिब के बैकएंड पर क्या हो रहा है। एक लार्क पर, मैंने इसे दूसरे दिन टहलने के साथ भी कोशिश करने का फैसला किया और उसी प्रॉपर्टीप्लिब त्रुटि को मिला।

पीएस एक ऐसी चीज है जो मुझे बहुत अजीब तरह से मारती है। IncompleteRead पेलोड में दो ब्रेकपॉइंट्स में से एक पर लगातार होता है। ऐसा लगता है कि 926 बाइट पढ़ने के बाद फीडपार्सर और अनुरोध विफल हो जाते हैं, फिर भी 1854 बाइट पढ़ने के बाद मशीनीकरण और urllib2 विफल हो जाते हैं। यह व्यवहार शामिल है, और मुझे स्पष्टीकरण या समझ के बिना छोड़ दिया गया है।

उत्तर

23

दिन के अंत में, अन्य मॉड्यूल (feedparser, mechanize, और urllib2) फोन httplib जो है, जहां अपवाद उत्पन्न किया जा रहा है के सभी।

अब, पहली चीजें पहले, मैंने इसे wget के साथ भी डाउनलोड किया और परिणामी फ़ाइल 1854 बाइट थी। इसके बाद, मैं urllib2 साथ करने की कोशिश की:

>>> 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 बाइट्स यह काम करता है पढ़ने के लिए:

>>> 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>' 

जाहिर है, यह केवल उपयोगी है, तो हम हमेशा समय से आगे सटीक लंबाई पता है। हम संपूर्ण सामग्री पर कब्जा करने के तथ्य आंशिक पढ़ने अपवाद पर एक विशेषता के रूप में दिया जाता है का उपयोग कर सकते हैं:

>>> 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 पता चलता है इस सर्वर की एक गलती है, और वर्णन के साथ कैसे बंदर-पैच करने के लिए httplib.HTTPResponse.read() विधि try..except ब्लॉक ऊपर पर्दे के पीछे चीजों को संभालने के लिए:

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 काम किया:

>>> 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 किनारे के मामले को गलत तरीके से संभालना है या नहीं।

+0

जबकि मैं मानता हूं कि यह चीजों को करने का एक अच्छा तरीका नहीं है, यह निश्चित रूप से बहुत अधिक है जिस विधि का मैं उपयोग कर रहा था उससे बेहतर। (मुझे वास्तव में सजावटी का उपयोग करके अभ्यास करने की ज़रूरत है)। मैं या तो HTTP प्रोटोकॉल में एक विशेषज्ञ नहीं हूं, न ही क्या प्रेजिडप्लिब ठीक से इसका इलाज कर रहा है या नहीं, इसलिए मुझे लगा कि यह पूछने का एक अच्छा सवाल हो सकता है। एफडब्ल्यूआईडब्ल्यू, इस साइट पर हर दूसरे पेज अच्छी तरह से काम करता है, और यह केवल तभी होता है जब आरएसएस यूआरएल का उपयोग होता है कि यह समस्या उनके http सर्वर पर होती है। – umeboshi

+0

@umeboshi - शायद प्रतिक्रिया के सामग्री प्रकार के साथ ऐसा कुछ करने के लिए, यानी, जिस तरह से सर्वर कॉन्फ़िगर किया गया है 'टेक्स्ट/एचटीएमएल' प्रतिक्रिया ठीक काम करती है लेकिन 'text/xml' नहीं है? यदि कोई और व्यापक उत्तर दिखाई नहीं देता है तो आप हमेशा इस प्रश्न को पायथन मेलिंग सूची में पोस्ट करने का प्रयास कर सकते हैं और देख सकते हैं कि कोई भी निदान दे सकता है या नहीं। – Blair

6

मैं मेरे मामले में यह पता लगाना, एक HTTP/1.0 अनुरोध, समस्या भेजने को ठीक, बस कोड को यह जोड़ने:

import httplib 
httplib.HTTPConnection._http_vsn = 10 
httplib.HTTPConnection._http_vsn_str = 'HTTP/1.0' 

के बाद मैं अनुरोध करना:

req = urllib2.Request(url, post, headers) 
filedescriptor = urllib2.urlopen(req) 
img = filedescriptor.read() 

के बाद मैं http 1.1 पर वापस (1.1 का समर्थन करने वाले कनेक्शन के लिए):

httplib.HTTPConnection._http_vsn = 11 
httplib.HTTPConnection._http_vsn_str = 'HTTP/1.1' 
+0

मेरे लिए भी काम किया! आपका बहुत बहुत धन्यवाद! क्या आपको कोई विचार है कि यह क्यों हो रहा है? अपूर्ण पढ़ने के लिए 1.0 में इतना खास क्या है? –

+0

आप पुराने कनेक्शन प्रकार को मजबूर करते हैं, आप भाग में पढ़ने जैसी कुछ http 1.1 क्षमता का उपयोग नहीं करते हैं, अक्सर जब आप बड़ी फ़ाइलों को डाउनलोड करने का प्रयास करते हैं तो ऐसा होना चाहिए ... –

+0

सभी सर्वर http 1.0 स्वीकार नहीं करते हैं - मुझे उनमें से एक से 404 मिल रहा है। –