Python: загрузка большого файла по локальному пути и установка пользовательских заголовков http

Я хочу загрузить файл с URL-адреса http в локальный файл. Файл достаточно большой, поэтому я хочу загрузить его и сохранить кусками, а не read() и write() весь файл в виде одной гигантской строки.

Интерфейс urllib.urlretrieve, по сути, то, что я хочу. Однако я не вижу способа установить заголовки запросов при загрузке через urllib.urlretrieve, что мне нужно сделать.

Если я использую urllib2, я могу установить заголовки запросов через его объект Request. Однако я не вижу API в urllib2 для загрузки файла непосредственно по пути на диске, например urlretrieve. Похоже, вместо этого мне придется использовать цикл для перебора возвращаемых данных по частям, самостоятельно записывать их в файл и проверять, когда мы закончим.

Как лучше всего создать функцию, которая работает как urllib.urlretrieve, но позволяет передавать заголовки запросов?


person Community    schedule 08.04.2009    source источник
comment
Что плохого в том, чтобы из любопытства зацикливаться на кусках возвращаемых данных?   -  person Parand    schedule 08.04.2009
comment
Как я узнаю, когда остановиться? read(), возвращающая пустую строку, не обязательно означает конец (как в случае с файлами), потому что данные могут все еще поступать. Я могу полагаться на заголовок длины содержимого, но мне кажется, что механизм для этого должен где-то уже есть.   -  person    schedule 08.04.2009


Ответы (2)


Какой вред в написании собственной функции с использованием urllib2?

import os
import sys
import urllib2

def urlretrieve(urlfile, fpath):
    chunk = 4096
    f = open(fpath, "w")
    while 1:
        data = urlfile.read(chunk)
        if not data:
            print "done."
            break
        f.write(data)
        print "Read %s bytes"%len(data)

и используя объект запроса для установки заголовков

request = urllib2.Request("http://www.google.com")
request.add_header('User-agent', 'Chrome XXX')
urlretrieve(urllib2.urlopen(request), "/tmp/del.html")
person Anurag Uniyal    schedule 08.01.2010

Если вы хотите использовать urllib и urlretrieve, создайте подкласс urllib.URLopener и используйте его метод addheader() для настройки заголовков (то есть: addheader('Accept', 'sound/basic'), который я беру из строки документации для urllib.addheader).

Чтобы установить свой URLopener для использования urllib, см. пример в urllib._urlopener раздел документов (обратите внимание на подчеркивание):

import urllib

class MyURLopener(urllib.URLopener):
    pass # your override here, perhaps to __init__

urllib._urlopener = MyURLopener

Тем не менее, вам будет приятно услышать ваш комментарий к комментариям вопроса, чтение пустой строки из read() действительно является сигналом к ​​остановке. Вот как urlretrieve обрабатывает, например, когда нужно остановиться. TCP/IP и сокеты абстрагируют процесс чтения, блокируя ожидание дополнительных данных, если только соединение на другом конце не является EOF и не закрыто, и в этом случае read() из соединения возвращает пустую строку. Пустая строка означает, что данные не просачиваются... вам не нужно беспокоиться о повторной сборке упорядоченного пакета, так как все это было сделано за вас. Если вас беспокоит urllib2, я думаю, вы можете безопасно его использовать.

person Jarret Hardie    schedule 08.04.2009
comment
Вышеприведенное выдало TypeError: должен быть тип, а не classob (см. -style-class" title="супер поднимает ошибку типа, для нового класса стиля должен быть тип, а не classobj">stackoverflow.com/questions/9698614/ ), и из документов API похоже, что следует добавить скобки: urllib. _urlopener = MyURLopener() - person user1255933; 11.04.2016