Как обращаться с 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)
Другие вопросы по тегам