mail mail
Нужен макрос для Excel?
Сделайте заказ прямо сейчас!
Ищете готовое решение?
Выбирайте и покупайте!
У вас есть интернет-магазин?
Настроим парсер под любой сайт!

Скачать файл из интернета без использования WinAPI

Часто требуется макросом скачать некий файл из интернета.
Обычно в этом помогает WinAPI-функция URLDownloadToFile, но есть также возможность загрузить файл без её использования:

Чем чревато использование функции URLDownloadToFile - по сути, ничем, кроме как необходимостью прописывать её в 4 вариантах,
для обеспечения совместимости с 64-битной Windows и Office 2010

Я же предлагаю другое решение - функцию DownloadFile с использованием объектов Microsoft.XMLHTTP и ADODB.Stream:

 

Sub ПримерИспользования()
    СсылкаНаФайл$ = "http://excelvba.ru/sites/default/files/3.jpg"
    ПутьДляСохранения$ = "C:\ПЖиВ.jpg"
 
    ' скачиваем файл из интернета
    DownloadFile СсылкаНаФайл$, ПутьДляСохранения$
 
    ' открываем скачанный файл
    CreateObject("wscript.shell").Run """" & ПутьДляСохранения$ & """"
End Sub

Function DownloadFile(ByVal URL$, ByVal LocalPath$) As Boolean
    ' Функция скачивает файл по ссылке URL$
    ' и сохраняет его под именем LocalPath$
    Dim XMLHTTP, ADOStream, FileName
    On Error Resume Next: Kill LocalPath$
 
    Set XMLHTTP = CreateObject("Microsoft.XMLHTTP")
    XMLHTTP.Open "GET", Replace(URL$, "\", "/"), "False"
    XMLHTTP.send
    If XMLHTTP.statustext = "OK" Then
        Set ADOStream = CreateObject("ADODB.Stream")
        ADOStream.Type = 1: ADOStream.Open
        ADOStream.Write XMLHTTP.responseBody
 
        ADOStream.SaveToFile LocalPath$, 2
        ADOStream.Close: Set ADOStream = Nothing
        DownloadFile = True
    Else
        'MsgBox "Не удаётся скачать файл " & XMLHTTP.statustext
    End If
    Set XMLHTTP = Nothing
End Function

Комментарии

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".

Надо применить к ссылке преобразование URLencode
http://excelvba.ru/code/URLEncode

Добрый день. Спасибо за отличную функцию, работает на ура! Но не работает, если в ссылке есть русские буквы. Можете подсказать что делать в этом случае? Пожалуйста.

В коде по-русски написано, что последняя команда открывает скачанный файл:

 ' открываем скачанный файл
    CreateObject("wscript.shell").Run """" & ПутьДляСохранения$ & """"

Попробовал скачать .jpg вашим макросом. По окончании скачки почему-то картинка открывается программой просмотра фотографий. Как устранить это?

Здравствуйте. У меня такая же проблема с Яндексом, но я нашёл площадку преобразующую "дисковые" временные ссылки в прямые. Сама ссылка закачку даёт, но по Вашему методу чего-то, видимо, не хватает. Вот вид ссылки https://getfile.dokpub.com/yandex/get/https://yadi.sk/i/LnS4iLRMg4NWr. Буду признателен, если что подскажите. Спасибо.

Здравствуйте Игорь. Благодарю Вас за предложение. Я уже решил свою проблему благодаря Вашей функции GetURLstatus, спасибо и за неё.

Здравствуйте, Кирилл.
Это сделать можно (чтобы таймаут можно было задать), - но код надо полностью переписывать.
Могу написать функцию для скачивания файлов под заказ, если готовы оплатить

Добрый дань! Спасибо за макрос. Подскажите пожалуйста , как решить проблему, Ваш код файлы качает на ура но, как только сайт начинает виснуть или отключатся макрос зависает вместе с ним. Как выходить из макроса если он не отвечает больше 5 секунд? Заранее спасибо

Проблема непонятна, - не понимаю, как может быть такое:
1) во внутренностях файла Эксель не хватает 2 файлов
(когда там в принципе никаких файлов во внутренностях быть не должно)
2) какая программа выдает сообщение, что диск не может быть открыт?
причем тут устаревший браузер?
Всё это не должно иметь никакого отношения к файлу Excel

В любом случае, проблема тут не в коде
Возможно, для вашей задачи код нужен несколько иной, - посложнее, что-то типа такого
http://excelvba.ru/code/DownloadFileWithAuth

Обнаружил следующую проблему:
Скачиваю с яндекс-диска по публичной ссылке следующего вида: https://yadi.sk/d/7Hi5WQ79_тратата....
Обычный файл с расширением xls. У меня стоит уже устаревшая Windows XP и 2007 офис.

Файл файл скачивается, но при открытии экселевского файла он сообщает что в его внутренностях не хватает как минимум 2 файлов. И демонстрирует мне следующую надпись: ДИСК НЕ МОЖЕТ БЫТЬ ОТКРЫТ, тк ваш браузер устарел. А содержимое файла отсутствует...

В то же время с со старого сайта на НАРОДЕ -нормальные ссылки с полным указанием пути к файлу - качаются без проблем.

Т.е оба кода не качают ПУБЛИЧНЫЕ ССЫЛКИ, в случае работы в устаревшей системе с устаревшим IE... Или есть какая то иная возможность?

Спасибо большое за отличный пример!
У меня вопрос такой: с одного источника файлы скачиваются нормально, а с другого - вместо того содержимого, которое должно быть, файл содержит кусок html-кода веб-страницы, с которой я его беру. При этом, если просто подставить в браузер ссылку, файл скачивается.
И zip-файл, скачанный с этого же сайта, не хочет открываться.
Подскажите, пожалуйста, почему такое может происходить?

узнать размер файла после его скачивания - не проблема,
для этого в VBA есть функция filelen(ПолныйПутьКФайлу)

Благодарю, работает! Если не секрет, то как узнать размер загружаемого файла???

Сергей, проблема не в моём макросе, — а в том, что каспер распознает ваш файл как подозрительный.
Как макрос не переделывай, - тут ничем не помочь.
Разбирайтесь либо с файлом, либо с техподдержкой касперского.

Доброго, вначале работало на ура, но сейчас еба***й касперский удаляет файл сходу...
Есть вариант реализовать скачивание без подобных акцессов?

Мне нужно переодически загружать 1 файл, исполнять его, после отсылать почтой результаты, все это было реализовано 2мя вашими функциями, экономило кучу времени...

Здравствуйте, JeyCi.
Код можно использовать и в VBS (только там есть некоторые отличия, не все из которых я помню)
Например, надо убрать все объявления переменных, в частности, удалить строку Dim XMLHTTP, ADOStream, FileName
А в остальном, - должно работать.

кстати, только один небольшой вопрос есть - можно ли этот код использовать для vbs скрипта?.. я попробовала, но получила ошибку в строке1 "XMLHTTP" объект как-то не задаётся видимо CreateObject'ом... этот код вообще в скрипт не переделать или есть какой-то способ?

"приведённый в этой статье код может давать ошибку"... вот и у меня такое случилось... методом высоко-научного тыка, прочитав MsgBox(Text), спустя пол-дня, увидев что до значения 200 код добирается, но всё равно выдает ошибку, всё-таки дополнила текстом ошибки строку If XMLHTTP.statustext = "OK" Or XMLHTTP.statustext = "SAMEORIGIN" Then ... SAMEORIGIN - был этим текстом... и оказалось, что как минимум такая ошибка совсем не страшна, её можно обойти (оператором or как дополнила строку указанную)... и у меня всё сохранилось!... вобщем не все ошибки страшные... Игорю спасибо за код

Если файл доступен для скачивания (вы копируете этот адрес в браузер, нажимаете Enter, - и файл начинает скачиваться), - то функция DownloadFile сможет загрузить этот файл.

Если же для загрузки этого файла нужна авторизация на FTP-сервере, - то тогда нужно уже совсем другое решение
(макросы для работы с FTP у меня тоже есть на сайте)

Подскажите, а если URL ведет на ftp://aaa.bbb.ru/111.jpg, то есть возможность что-то подправить в функции DownloadFile чтобы макрос заработал? Или есть какой обходной путь чтобы скачивать не только по http но и по ftp? Спасибо.

Сделать можно (если вы вручную можете посмотреть список файлов, т.е. если доступ к этому списку есть)
Оформляйте заказ, и пишите, что и как должно работать.

Спасибо, очень полезная функция. Но у меня несколько расширенная задача: прежде чем скачивать файл, необходимо вывести список файлов, находящихся на фтп сервере. Закачанные файлы сохраняются строго в одни и тот же каталог и переименовываются по определенному алгоритму. Поэтому использование интернет эксплорера является не самым удобным вариантом для меня.

Если сайт требует авторизации, и вы авторизовались, используя браузер InternetExplorer, — то им и надо скачивать файл.
Авторизация же не распространяется на любые соединения с компа (согласитесь, если после авторизации открыть ту же страницу в другом браузере, вы же не будете авторизованы...)
Вот и тут так. (хоть тут скачивание производится не браузером, а средствами компонентов Windows, - авторизация, выполненная через IE, никакого отношения к этому макросу не имеет)
Т.е. этот макрос вам не нужен.
В том макросе, где происходит авторизация, добавьте код скачивания файла (какой конкретно код - не знаю, ни разу не приходилось качать файлы через IE)

я попал именно в этот 1%...
C помощью указанной функции удачно авторизовался на сайте, а файл скачивать отказывается (пишет что доступ закрыт и неоходимо залогиниться), что я делаю не правильно:
URL = "https://www.atsenergo.ru/reporting/personal/sib/sell_norem/20130331/имя файла/"
Dest = "путь сохранения.xls"
If URLDownloadToFile(0, URL, Dest, 0, 0) = 0 Then MsgBox "файл скачан в " & Dest
Причем тот же самый код с ссылкой на файл из незакрытой зоны закачивает правильно.

Есть возможность запрашивать список файлов с сервера автоматически.
А остальное можно автоматизировать.

Вроде бы, мне уже приходилось делать подобную программу для этого сайта, для загрузки файлов и обработки данных с atsenergo.ru
Только давно было, не помню подробностей.
Если готовы оплатить работу - обращайтесь в личку, доработаем существующую программу, или напишем новую.

"А зачем вам вход по логину-паролю, если все файлы для скачивания доступны и без этого?"

На этом же сайте есть персональный раздел: https://www.atsenergo.ru/auth
С которого идет скачка и последующая обработка персональных данных.

На счет ответа #20: каждый раз человек не может делать одну и туже операцию которая описана в ответе. Есть ли возможность запрашивать список автоматически? (далее процедура будет запускаться по времени и работать ночью)

А зачем вам вход по логину-паролю, если все файлы для скачивания доступны и без этого?

А получить список файлов можно веб-запросом в Excel
(и обновлять этот запрос макросом, или при открытии файла)

Как сделать веб-запрос в Excel для получения списка файлов на сервере:
(щелкните на картинке для увеличения)

веб-запрос в Excel - список файлов на сервере

Спасибо. Попробую)

Еще вопрос по скачке, в директории на сервере лежат в одной папке несколько отчетов:
https://www.atsenergo.ru/reporting/public/eur/carana_sell_units/20130215

День ото дня количество и названия отчетов могут меняться: Как правило добавляется один файл с новым названием.
Какой механизм лучше использовать для загрузки полного списка файлов. Может быть подойдет что-то вроде Dir()?

Да, можно и это сделать.
Есть 2 варианта:

1) использовать эту функцию, при этом логин\пароль прописывать в строке URL в определённом формате (после http://)
не уверен, что сработает (далеко не все сайты принимают этот стандартный для http метод авторизации) - но можно попробовать

2) использовать функцию для авторизации на сайте
http://excelvba.ru/code/ConnectServer
и после авторизации скачивать файл средствами Internet Explorer
(этот способ в вашем случае сработает с вероятностью 99%)

Файл прекрасно работает, но также есть необходимость скачивать данные с закрытого раздела сайта (вход по коду участника/логину/паролю). Это как-нибудь можно реализовать?

Strateg, в этом случае код усложнится.
Я в таких случаях подключаюсь в сайту через IE (Internet Explorer), где программно нажимаю согласие с сертификатом, и потом уже скачиваю файл.

Можно сделать это и с использованием объекта "Microsoft.XMLHTTP"

К сожалению, пример кода дать не могу (я как-то публиковал примеры на форумах, но оба форума у меня в данный момент недоступны. пробовал найти в кеше яндекса - не получилось)
Поищите в интернете - наверняка найдёте примеры.

Выяснилось, что проблема в сертификате узла, к которому подключаюсь. Ранее, подключаясь к не доверенному сертификату, возникало сообщение, хочу ли я продолжить. Теперь программа просто падает с ошибкой. Как исправить ситуацию?

Здравствуйте. Подскажите, почему может быть такая ситуация.
У меня есть ссылка на файл, если эту ссылку я вставляю в браузер, начинается загрузка файла.
Если использую данную функцию, на строке
XMLHTTP.send
возникает ошибка

Run-time error '-2147467259 (80004005)':
Неопознанная ошибка

Да, конечно можно.
Обычно так всегда и делаю.

После этой строки кода добавьте строку

debug.print СсылкаНаФайл$

и потом из окна Immediate скопируйте выведенную ссылку в браузер.

Сразу увидите, в чем проблема (может, имя файла некорректно формируется)

Добрый день!
Подскажите, пожалуйста, можно ли ссылку на файл указать в следующем виде:
СсылкаНаФайл$ = "http://excelvba.ru/sites/default/files/" & имя_файла
А имя_файла сформировать отдельно?
У меня данный метод не работает. Может подскажите как это осуществить.

Да, вы правы.
Скачать по прежнему не удается...
Скачивается но не то что надо, т.е с маской скачать не получится.

C InstrRev пробовала, но т.к ссылки полностью нет, все по той же причине, то этот вариант не проходит.

Скачивать файлы с маской у меня вроде получилось, теперь осталась проблема только с сохранением. Под другим именем файлы скачиваются и сохраняются.

Сохранить под новым именем а потом переименовать тоже не получилось, т.к не знаю где можно узнать имя, которое должно быть.

Может можно как-то узнать имя файла которое было скачано? может эти ссылки где-то хранятся?

Путь (точнее, имя файла) для сохранения можно сформировать, взяв кусок текста из ссылки.
(например, при помощи функции InstrRev взяв текст после последнего слэша)
Главное, чтобы ссылка была полностью известна, - остальное уже мелочи.

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

Спасибо!

А подскажите тогда, как указать путь сохранения, если имя неизвестно? можно ли как-то указать путь без имени, чтобы файл сохранялся под тем же именем под которым скачивается?

Нет, так скачать файл из интернета не получится.
Если искать файл в папке на компе - тогда можно было бы найти его поиском по маске.
А в интернете такой способ не работает - надо знать точную ссылку на файл.

Если на сайте где-то есть список доступных файлов (ссылок) - тогда другое дело, можно проанализировать этот список, и найти подходящее имя файла.
По-другому - увы, никак.

Добрый день!
Столкнулась со следующей проблемой.
Программа работает, если известно имя файла и расширение. но в моем случае о файле который скачивается известно только расширение. Имя файла составляется частично автоматически, частично в зависимости от данных таблицы. Можно ли как-то скачать такой файл и чтобы сохранялся файл именно с таким именем. Т.е. переименовывать файл нельзя.

Например:

вот имя файла C600965000263161.dsp
В этом имени заранее известно:
Первая буква она всегда С, вторая и третья цифра заранее не известны(в нашем случае 60), 0965 и 000263 надо взять из двух ячеек в таблице и последние 3 цифры тоже не известны (161).

Можно ли как-то скачать файл например по такому принципу
номер = A1 + A2 ' склеиваем ту часть что известна
имя файла = С** & номер & ***
СсылкаНаФайл$ = "http://ссылка/" & имя файла

Номеров идентичных не бывает. т.е нам все равно какие цифры под звездочками, главное чтобы номер, что мы берем из таблицы совпадал.

И как сохранить данный файл именно под тем именем, под которым он лежит в интернете.

Надеюсь, я более менее понятно объяснила что мне надо. Сразу предупрежу, что в vba я не сильна, поэтому не судите строго за данный вопрос.

Если кто-то вызовется помочь, могу скинуть конкретный пример на почту.

Здравствуйте, Алексей.

По ссылке расширение файла ну никак не узнать.
Веб-сервер получает по этой ссылке данные, и возвращает файл, но не тот, который написан в ссылке, а тот, какой считает нужным возвратить.

Т.е. даже если ссылка имеет вид /.../чего_то_там.jpg,
сервер может вам выдать файл СовсемДругоеИмя.exe

А если расширение в ссылке не содержится, то узнать тип файла можно, только скачав его, и проанализировав.

Впрочем, можно и не анализировать - Windows сама корректно распознаёт тип графического файла, не обращая внимание на расширение.
Т.е. вы можете переименовать файл JPG в BMP или PNG, потом открыть - и файл корректно откроется, без каких либо уведомлений.
Т.е. сохраняйте файл с любым расширением (я обычно ставлю JPG), и работайте с ним дальше как с файлом формата JPG,
- все программы (с вероятностью 99%) не заметят подвоха.

То, что по длинной ссылке не скачивается - тут ничего не могу подсказать.
Во-первых, тот километр текста, что вы привели в качестве примера, ссылкой не является (начинается с «data:image/jpeg;base64,/9j/4AAQ», а ссылки начинаются с «http://»),
а во-вторых, очень может быть, что функция не принимает ссылки длинее 255 символов (или 1024 сиволов)

Я про эти ограничения не знаю - ибо не сталкивался.

И вообще, лучше для скачивания файлов пользоваться другим кодом - с использованием WinAPI функции URLDownloadToFile
(как тут недавно выяснилось, URLDownloadToFile качает всё, а приведённый в статье код может выдавать ошибку при некоторых файлах или ссылках.
Не помню точно в чем проблема - скорее всего, в размере файла. А функция на основе URLDownloadToFile качает что угодно)

 

 

#If Win64 Then
    #If VBA7 Then    ' Windows x64, Office 2010
        Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                (ByVal pCaller As LongLong, ByVal szURL As String, ByVal szFileName As String, _
                 ByVal dwReserved As LongLong, ByVal lpfnCB As LongLong) As LongLong
    #Else    ' Windows x64,Office 2003-2007
        Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                                           (ByVal pCaller As LongLong, ByVal szURL As String, ByVal szFileName As String, _
                                            ByVal dwReserved As LongLong, ByVal lpfnCB As LongLong) As LongLong
    #End If
#Else
    #If VBA7 Then    ' Windows x86, Office 2010
        Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, _
                 ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
    #Else    ' Windows x86, Office 2003-2007
        Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                                           (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, _
                                            ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
    #End If
#End If
 
Function DownLoadFileFromURL(ByVal URL$, ByVal LocalPath$) As Boolean
    On Error Resume Next: Kill LocalPath$
 
    shortFilename$ = Mid(LocalPath$, InStrRev(LocalPath$, "\") + 1)
    If shortFilename$ <> Replace_symbols(shortFilename$) Then
        Debug.Print "Wrong symbols in filename: " & shortFilename$
        Exit Function
    End If
 
    ' чтобы избежать кеширования
    URL$ = URL$ & "?rnd=" & Left(Rnd(Now) * 1E+15, 10)
 
    DownLoadFileFromURL = URLDownloadToFile(0, URL$, LocalPath$, 0, 0) = 0
End Function

Sub ПримерИспользования()
    Link$ = "http://ExcelVBA.ru/test.jpg"
    Debug.Print DownLoadFileFromURL(Link$, "c:\test2.test")
End Sub

PS: Километр текста из вашего комментария удалил

Столкнулся с проблемой -- не всегда при загрузке из интернета ссылка имеет вид http://excelvba.ru/.../чего_то_там.jpg
иногда попадаются (в случае с поиском по Гуглу) такие конструкции:
https://адрес сайта/images?q=iZBwCJ

и даже такие звери (простите за ужасный объем)
data:image/jpeg;base64,/9j/4AAQSkZJR ...очень-очень много букв... QCEIQCEIQCEIQf/2Q==

как в таких случаях узнать хотябы расширение привильное результирующего файла (jpg, png, gif и пр.)
ну и второй вопрос -- как закачать по второй ссылке (зверской)?
Ваш код отлично справляется с первой (если расширение jpg), а на вторую ругается

Спасибо.
Алексей.

Воспользовался этой функцией, но столкнулся с затруднением: при отсутствии интернета файл "достается" из локального кеша, в большинстве случаев это не проблема, но я проверяю дату последних обновлений, которая лежит в текстовом файле на сайте.
Решение: между строк
XMLHTTP.Open... и XMLHTTP.send
воткнуть
XMLHTTP.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"

Спасибо! Работает.

Спасибо!

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
CAPTCHA
Подтвердите, пожалуйста, что вы - человек:
   __     _            __        __          ___ 
/ /_ | |_ __ _ \ \ / / _ _ |_ _|
| '_ \ | __| / _` | \ \ /\ / / | | | | | |
| (_) | | |_ | (_| | \ V V / | |_| | | |
\___/ \__| \__, | \_/\_/ \__, | |___|
|___/ |___/
Введите код, изображенный в стиле ASCII-арт.

Не получается применить макрос? Не удаётся изменить код под свои нужды?

Оформите заказ у нас на сайте, не забыв прикрепить примеры файлов, и описать, что и как должно работать.