Python: скачать файл с FTP-сервера

Я пытаюсь загрузить некоторые общедоступные файлы данных. Я делаю скриншот, чтобы получить ссылки на файлы, которые выглядят примерно так:

ftp://ftp.cdc.gov/pub/Health_Statistics/NCHS/nhanes/2001-2002/L28POC_B.xpt

Я не могу найти документацию на веб-сайте библиотеки Requests.


person user1507455    schedule 01.08.2012    source источник


Ответы (9)


requests библиотека не поддерживает ftp-ссылки.

Чтобы загрузить файл с FTP-сервера, вы можете:

import urllib 

urllib.urlretrieve('ftp://server/path/to/file', 'file')
# if you need to pass credentials:
#   urllib.urlretrieve('ftp://username:password@server/path/to/file', 'file')

Or:

import shutil
import urllib2
from contextlib import closing

with closing(urllib2.urlopen('ftp://server/path/to/file')) as r:
    with open('file', 'wb') as f:
        shutil.copyfileobj(r, f)

Python3:

import shutil
import urllib.request as request
from contextlib import closing

with closing(request.urlopen('ftp://server/path/to/file')) as r:
    with open('file', 'wb') as f:
        shutil.copyfileobj(r, f)
person jfs    schedule 01.08.2012
comment
Спасибо за это, но как вы можете предоставить учетные данные? - person SSH This; 14.02.2014
comment
@SSHThis: попробуйте: 'ftp://username:password@server/path/to/file' или используйте @Rakesh answer. Если вы не можете заставить его работать, спросите. - person jfs; 14.02.2014
comment
Немного информации о urlib и запросах здесь: blog.pythonlibrary.org/2012/06/07/ - person cbare; 07.08.2014
comment
@cbare: в чем смысл ссылки. requests вообще поддерживает ftp? - person jfs; 03.11.2015
comment
@Дж.Ф. Себастьян: в статье показано параллельное сравнение requests и urllib. Может быть, это поможет кому-то перейти с requests на urllib, чтобы получить поддержку FTP? Или вы считаете, что лучше удалить комментарий? - person cbare; 05.11.2015
comment
@cbare: решать тебе - person jfs; 05.11.2015
comment
@ J.F.Sebastian Есть ли шанс, что мы сможем получить обновление? Это не работает в Py3, и ftblib не работает. - person zelusp; 08.10.2016
comment
@zelusp, если замена import urllib2 на import urllib.request не работает для вас, задайте отдельный вопрос (укажите конкретные ошибки, которые вы получаете). В любом случае, возможно, стоит задать новый вопрос с вашими конкретными требованиями (опишите в вопросе, как именно ftplib не обрезает его: что вы ожидаете? Что происходит вместо этого? (подробно)). - person jfs; 08.10.2016
comment
@ J.F.Sebastian, ты совершенно прав - было очень поздно, и я просто хотел получить волшебный ответ. Но, может быть, я решу свою проблему сейчас, когда я выспался - спасибо за ответ! - person zelusp; 09.10.2016
comment
При загрузке нескольких FTP-файлов IOError: [Errno ftp error] 200 Переключение в двоичный режим. будет выброшено при использовании urllib.urlretrieve. - person alextc; 04.01.2018
comment
Я понимаю, что это действительно старый пост, извините, что наткнулся на него. Но в вашем ответе на @SSHThis 'ftp://username:password@server/path/to/file' имя пользователя и пароль зашифрованы или скрыты, или любой, кто видит ваш трафик, может прочитать его так же, как он мог бы прочитать URL-адрес? Извините, я не слишком много знаю о шифровании и о том, как все это работает, но мне было любопытно. - person Marses; 12.01.2018
comment
@LimokPalantaemon эквивалентен вызову ftp.login(user, passw) и, следовательно, не зашифрован (ftp — очень старый протокол — мало безопасности). Вместо этого вы можете попробовать sftp (fabric/paramiko). - person jfs; 12.01.2018
comment
Вау, я поражен, что для загрузки файла требуется три модуля и шесть строк ... Большое спасибо за ваш ответ Python3 - я был в отчаянии после попытки urllib, requests и wget (последний не может перезаписывать существующие файлы. ..) - person AstroFloyd; 22.10.2019
comment
Почему вы используете contextlib.closing, когда urllib.response.addinfourl.__exit__ уже звонит self.close()? - person gerrit; 15.01.2020
comment
@gerrit: я предполагаю, что объект ответа не поддерживал протокол диспетчера контекста в 2012 году. - person jfs; 15.01.2020
comment
зачем shutil нужен с urilib.request? - person grisaitis; 16.06.2021
comment
@grisaitis это просто цикл: while data := r.read(blocksize): f.write(data) (скопировать данные из объекта входного файла r в выходной файл f) - person jfs; 16.06.2021

Вы можете попробовать это

import ftplib

path = 'pub/Health_Statistics/NCHS/nhanes/2001-2002/'
filename = 'L28POC_B.xpt'

ftp = ftplib.FTP("Server IP") 
ftp.login("UserName", "Password") 
ftp.cwd(path)
ftp.retrbinary("RETR " + filename, open(filename, 'wb').write)
ftp.quit()
person Rakesh    schedule 14.09.2012
comment
Что, если имя файла на сервере содержит специальные символы, например. ' ', $ и т. д. Нужно ли мне избегать их? - person Dilawar; 09.09.2015
comment
Имя файла может быть произвольной последовательностью байтов с несколькими исключениями, такими как b'\xff' (я не знаю никакого стандартного способа избежать таких имен). Здесь подробнее. Вы можете задать отдельный вопрос о переполнении стека, если у вас есть конкретная проблема с именами файлов ftp. - person jfs; 02.10.2016
comment
У меня сработало кодирование имени файла из юникода в utf-8. Возможно, это отличается в разных ОС: ftp.retrbinary(u"RETR täßt.jpg".encode('utf-8'), open('local.jpg', 'wb').write) - person Aidas Bendoraitis; 26.04.2017
comment
Если возвращаемые данные больше, чем размер блока, я полагаю, что это продолжит перезаписывать файл и сохранит только последний блок. - person mgilbert; 15.05.2019

Попробуйте использовать библиотеку wget для python. Документацию по нему можно найти здесь.

import wget
link = 'ftp://example.com/foo.txt'
wget.download(link)
person Gaurav Shrivastava    schedule 10.01.2018
comment
Самый простой и хорошо работает. Вы также можете установить имя файла с параметром out в wget.download. - person wordsforthewise; 24.09.2019
comment
Это работает для меня, и другой метод вызвал разрушение файла. - person Samoth; 14.10.2019

Используйте urllib2. Подробнее см. этот пример с doc.python.org:

Вот фрагмент из учебника, который может помочь

import urllib2

req = urllib2.Request('ftp://example.com')
response = urllib2.urlopen(req)
the_page = response.read()
person Parker    schedule 01.08.2012

Как заметили несколько человек, запросы не поддерживают FTP, но у Python есть другие библиотеки, которые поддерживают. Если вы хотите продолжать использовать библиотеку запросов, существует пакет requests-ftp, который добавляет возможности FTP к запросам. Я немного использовал эту библиотеку, и она действительно работает. Однако документы полны предупреждений о качестве кода. Что касается версии 0.2.0, в документах говорится: «Эта библиотека была собрана вместе примерно за 4 часа общей работы, не имеет тестов и опирается на несколько уродливых хаков».

import requests, requests_ftp
requests_ftp.monkeypatch_session()
response = requests.get('ftp://example.com/foo.txt')
person Nelson    schedule 07.01.2015
comment
Это решение работает, по крайней мере, в моих руках, как s = requests.Session() response = s.get(... (а не как requests.get) - person Matteo Ferla; 16.12.2019

urllib2.urlopen обрабатывает ftp-ссылки.

person Victor Gavro    schedule 01.08.2012

urlretrieve мне не подходит, и официальный документ сказал, что они могут стать устаревшими в какой-то момент в будущем.

import shutil 
from urllib.request import URLopener
opener = URLopener()
url = 'ftp://ftp_domain/path/to/the/file'
store_path = 'path//to//your//local//storage'
with opener.open(url) as remote_file, open(store_path, 'wb') as local_file:
    shutil.copyfileobj(remote_file, local_file)
person GoatWang    schedule 15.04.2018

Если вы хотите воспользоваться преимуществами асинхронных функций последних версий Python, вы можете использовать aioftp (от то же семейство библиотек и разработчиков, что и более популярная библиотека aiohttp). Вот пример кода, взятый из их руководства по работе с клиентом:

client = aioftp.Client()
await client.connect("ftp.server.com")
await client.login("user", "pass")
await client.download("tmp/test.py", "foo.py", write_into=True)
person Dean Gurvitz    schedule 25.03.2020

person    schedule
comment
У меня есть вопрос, совершенно не связанный с этой веткой, но связанный с вашим кодом, загруженным на github: stackoverflow.com/questions/27584233/ - person user961627; 20.12.2014