Soru Https kullanarak https kullanarak


Belirli bir web sitesinden rss feed'i almakta sürekli bir sorun yaşıyorum. Bu işlevi yerine getirmek için oldukça çirkin bir prosedür yazıyordum, ama bunun neden olduğunu ve daha yüksek seviyeli arayüzlerin bu sorunu doğru şekilde yerine getirip getirmediğini merak ediyorum. Bu problem gerçekten bir gösteri durdurucu değil, çünkü sıklıkla beslemeyi almam gerekmiyor.

İstisnai yakalayan ve kısmi içeriği döndüren bir çözüm okudum, ancak tamamlanmamış okumalar aslında alınmakta olan baytların miktarında farklılık gösterdiğinden, böyle bir çözümün gerçekten işe yarayacağına dair bir kesinlik yok.

#!/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)

Daha önce de belirttiğimiz gibi, bu kritik bir problem değil, yine de bir merak, urllib2'nin bu soruna sahip olmasını bekleyebildiğim gibi, bu hatanın mekanizasyonda ve isteklerde de karşılaşıldığına şaşıyorum. Feedparser modülü bir hata bile atmaz, bu yüzden hataların kontrol edilmesi bir 'bozo_exception' anahtarının varlığına bağlıdır.

Düzenleme: Sadece wget ve curl fonksiyonunu kusursuz bir şekilde gerçekleştirdiğinden ve her zaman tam yükü doğru bir şekilde aldığından bahsetmek istedim. Çirkin hacklerim dışında çalışmak için saf bir python yöntemi bulamadım ve httplib'nin arka ucunda ne olduğunu bilmek beni çok merak ediyor. Bir kurtçukta, bunu diğer güne kadar twill ile denemeye ve aynı httplib hatası aldım.

Not; Bana da tuhaf gelen bir şey var. IncompleteRead, sürekli olarak, yükteki iki kesme noktasından birinde gerçekleşir. Feedparser ve istekler 926 bayt okuduktan sonra başarısız olur, ancak 1854 bayt okuduktan sonra mekanize ve urllib2 başarısız olur. Bu davranış tutarlı ve ben açıklama ya da anlayış olmadan bıraktım.


21
2018-01-03 23:43


Menşei




Cevaplar:


Günün sonunda, diğer tüm modüller (feedparser, mechanize, ve urllib2) aramak httplib istisnanın atıldığı yer burasıdır.

Şimdi, önce ilk şeyler, bunu da wget ile indirdim ve ortaya çıkan dosya 1854 bayt oldu. Sonra, denedim 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)

Yani, 1854 baytlık bir okumayı okuyor ama sonra gelecek daha çok şey olduğunu düşünüyor. Açıkça sadece 1854 bayt okuduğunu söylersek işe yarar:

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

Açıkçası, bu sadece zamanın tam uzunluğunu bildiğimiz zaman işe yarar. Tüm içeriği yakalamak için kısmi okunmanın istisnadaki bir özellik olarak döndürülmesi gerçeğini kullanabiliriz:

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

Bu blog yazısı bu sunucunun bir hatası olduğunu ve maymun-yama nasıl açıklanacağını açıklar httplib.HTTPResponse.read() yöntemiyle try..except perde arkasındaki şeyleri işlemek için yukarıda blok:

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)

Yamayı uyguladıktan sonra feedparser çalıştı:

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

Bu işleri yapmanın en güzel yolu değil, ama işe yarıyor. HTTP protokollerinde, sunucunun yanlış bir şey yapıp yapmadığını öğrenmek için yeterince uzman değilim. httplib bir kenar muhafazasını yanlış kullanıyor.


23
2018-01-07 23:41



Bir şey yapmanın iyi bir yolu olmadığını kabul etsem de, kullandığım yöntemden kesinlikle daha iyi. (Ben gerçekten dekoratörler kullanarak pratik yapmak gerekir). HTTP protokollerinde uzman değilim ya da https bu durumu doğru bir şekilde tedavi edip etmediğini sormuyor, bu yüzden bunun sorulması iyi bir soru olduğunu düşündüm. FWIW, bu sitedeki diğer her sayfa iyi çalışıyor ve sadece rss url'sine erişirken bu sorunun onların http sunucusunda meydana gelmesi. - umeboshi
@umeboshi - belki de yanıtın içerik türü ile ilgili bir şey, yani sunucunun yapılandırılma şekli text/html cevaplar iyi çalışıyor ama text/xml değil mi? Daha kapsamlı bir cevap gösterilmezse, bu soruyu her zaman Python posta listesine göndermeyi deneyebilir ve tanıyabilecek herhangi birinin bulunup bulunmadığını görebilirsiniz. - Blair


Benim durumumda bir HTTP / 1.0 isteği gönder, sorunu çöz, sadece bu kodu ekliyorum:

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

isteği yaptıktan sonra:

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

http 1.1 ile geri döndükten sonra (1.1 destekleyen bağlantılar için):

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

6
2017-12-17 22:14



Benim için de çalıştın! Çok teşekkürler! Bunun neden olduğu hakkında bir fikrin var mı? Tamamlanmamış okumalar için 1.0'da çok özel olan nedir? - Alexander Dzyoba
eski bağlantı türünü zorlarsanız, büyük bir dosya indirmeyi denediğinizde sık sık ortaya çıkması gereken bir http 1.1 özelliği kullanamazsınız. - Sérgio
Tüm sunucular http 1.0 kabul etmez - bunlardan birinden 404 alıyorum. - Vitaly Zdanevich