Как обращаться с IncompleteRead: в Python
Я пытаюсь получить некоторые данные с веб-сайта. Однако это возвращает меня incomplete read
, Данные, которые я пытаюсь получить, представляют собой огромный набор вложенных ссылок. Я провел некоторое онлайн-исследование и обнаружил, что это может быть связано с ошибкой сервера (кодирование передачи по частям завершается до достижения ожидаемого размера). Я также нашел обходной путь для выше по этой ссылке
Тем не менее, я не уверен, как использовать это для моего случая. Ниже приведен код, над которым я работаю
br = mechanize.Browser()
br.addheaders = [('User-agent', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1;Trident/5.0)')]
urls = "http://shop.o2.co.uk/mobile_phones/Pay_Monthly/smartphone/all_brands"
page = urllib2.urlopen(urls).read()
soup = BeautifulSoup(page)
links = soup.findAll('img',url=True)
for tag in links:
name = tag['alt']
tag['url'] = urlparse.urljoin(urls, tag['url'])
r = br.open(tag['url'])
page_child = br.response().read()
soup_child = BeautifulSoup(page_child)
contracts = [tag_c['value']for tag_c in soup_child.findAll('input', {"name": "tariff-duration"})]
data_usage = [tag_c['value']for tag_c in soup_child.findAll('input', {"name": "allowance"})]
print contracts
print data_usage
Пожалуйста, помогите мне с этим. Спасибо
9 ответов
Ссылка, которую вы включили в свой вопрос, является просто оболочкой, которая выполняет функцию read() urllib, которая перехватывает любые неполные исключения для чтения для вас. Если вы не хотите реализовывать весь этот патч, вы всегда можете просто включить цикл try/catch, где читаете ваши ссылки. Например:
try:
page = urllib2.urlopen(urls).read()
except httplib.IncompleteRead, e:
page = e.partial
для python3
try:
page = request.urlopen(urls).read()
except (http.client.IncompleteRead) as e:
page = e.partial
Я выясняю в моем случае: отправьте 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'
хитрость в том, чтобы использовать http 1.0, а http / 1.1 по умолчанию http 1.1 может обрабатывать куски, но по какой-то причине веб-сервер этого не делает, поэтому мы делаем запрос в http 1.0
Что мне помогло, так это перехват IncompleteRead в качестве исключения и сбор данных, которые вам удалось прочитать на каждой итерации, путем помещения их в цикл, как показано ниже: (Обратите внимание, я использую Python 3.4.1, а библиотека urllib изменилась между 2.7 и 3.4)
try:
requestObj = urllib.request.urlopen(url, data)
responseJSON=""
while True:
try:
responseJSONpart = requestObj.read()
except http.client.IncompleteRead as icread:
responseJSON = responseJSON + icread.partial.decode('utf-8')
continue
else:
responseJSON = responseJSON + responseJSONpart.decode('utf-8')
break
return json.loads(responseJSON)
except Exception as RESTex:
print("Exception occurred making REST call: " + RESTex.__str__())
Ты можешь использовать requests
вместо urllib2
, requests
основывается на urllib3
так что с этим редко возникают какие-либо проблемы. Поместите это в петлю, чтобы попробовать это 3 раза, и это будет намного сильнее. Вы можете использовать это так:
import requests
msg = None
for i in [1,2,3]:
try:
r = requests.get(self.crawling, timeout=30)
msg = r.text
if msg: break
except Exception as e:
sys.stderr.write('Got error when requesting URL "' + self.crawling + '": ' + str(e) + '\n')
if i == 3 :
sys.stderr.write('{0.filename}@{0.lineno}: Failed requesting from URL "{1}" ==> {2}\n'. format(inspect.getframeinfo(inspect.currentframe()), self.crawling, e))
raise e
time.sleep(10*(i-1))
Python 3 FYI
from urllib import request
import http.client
import os
url = 'http://shop.o2.co.uk/mobile_phones/Pay_Monthly/smartphone/all_brand'
try:
response = request.urlopen(url)
file = response.read()
except http.client.IncompleteRead as e:
file = e.partial
except Exception as result:
print("Unkonw error" + str(result))
return
# save file
with open(file_path, 'wb') as f:
print("save -> %s " % file_path)
f.write(file)
Хитрость заключается в том, чтобы продолжить загрузку с помощью 'request.add_header('Range', 'bytes=%d-' % len(return_raw))', если сервер поддерживает это.
import urllib.request
from http.client import IncompleteRead
import time
def download_file(request, unsafe=False, max_retries=15):
bytes_ranges_supported = False
return_raw = b''
# Check if is supported bytes ranges
try:
with urllib.request.urlopen(request) as response:
if response.headers.get('Accept-Ranges') == 'bytes':
bytes_ranges_supported = True
except:
pass
i = max_retries
while (i > 0):
i -= 1
try:
if bytes_ranges_supported:
request.add_header('Range', 'bytes=%d-' % len(return_raw))
with urllib.request.urlopen(request) as response:
return_raw += response.read()
break # If the read was successful, break the loop
except IncompleteRead as e:
return_raw += e.partial
if not bytes_ranges_supported and (unsafe or i == 0):
break # If bytes ranges not supported and unsafe or no retries left, break the loop
except:
raise
finally:
try:
time.sleep(0.10)
except OSError:
break
except KeyboardInterrupt:
raise
return return_raw
url = 'https://google.com/'
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'})
with open('file.html', 'wb') as f:
f.write(download_file(req))
Я перепробовал все эти решения, и ни одно из них не помогло мне. На самом деле, что работало, вместо того, чтобы использовать urllib, я просто использовал http.client (Python 3)
conn = http.client.HTTPConnection('www.google.com')
conn.request('GET', '/')
r1 = conn.getresponse()
page = r1.read().decode('utf-8')
Это прекрасно работает каждый раз, тогда как с urllib он каждый раз возвращал непрочитанное исключение.
Я обнаружил, что мой антивирус / брандмауэр вызывает эту проблему. "Онлайн Щит" часть AVG.
Я просто добавляю еще одно исключение для прохождения этой проблемы.
как
try:
r = requests.get(url, timeout=timeout)
except (requests.exceptions.ChunkedEncodingError, requests.ConnectionError) as e:
logging.error("There is a error: %s" % e)