Потоковое скачивание файлов из Sharepoint

Sharepoint – один из наиболее встречающихся инструментов для организации веб-порталов в больших организациях. Ключевым преимуществом системы является удобное прототипирование, создание списков с данными и т.д.

В рамках одной из систем в организации реализована такая схема – есть проект и по каждому проекту хранятся файлы в материалах Sharepoint.

Была поставлена задача – нужно выкачать файлы за весь период, а за 5 лет их накопилось очень много (примерно 122 тысячи файлов), соответственно, решать эту задачу руками – равноценно тому чтобы остаться жить на работе на ближайшие десять лет.

Для начала приведем схему, как сейчас реализовано взаимодействие.

Потоковое скачивание файлов из Sharepoint

Ссылки на материалы обычно имеют такой вид:

Потоковое скачивание файлов из Sharepoint

Для начала из БД сервиса через SQL запрос сформируем ссылки на материалы для всего необходимого списка.

Как хранятся данные может сильно отличаться в зависимости от организации, в моем случае я просто сджойнил ИД документов с БД Sharepoint и на выходе получил необходимые ссылки.

Потоковое скачивание файлов из Sharepoint

Итак, у нас есть csv файл (ссылки по понятным причинам пришлось скрыть), который хранит в себе все ссылки на необходимые нам материалы.

Возьмем python и для скачивания будем использовать библиотеку requests.

Первым делом авторизируемся по логину/паролю Windows. Для этого используем модуль авторизации HttpNtlmAuth из пакета requests_ntlm.

Чтобы получить список файлов – используем запрос к api, который вернет нам xml-документ с ссылками на материалы.

staticmethod def is_remote_host_available(host_link, username, password): return requests.get(host_link + '/_api/files/', auth=HttpNtlmAuth(username, password), verify=False)
Потоковое скачивание файлов из Sharepoint

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

Распарсим полученную XML для выделения ссылок на каждый файл по отдельности.

staticmethod def download_specified_files(response, username, password, output_path): try: doc = ET.fromstring(response.text) except AttributeError: return False tree = ET.ElementTree(doc) xml_to_parse = tree.findall('{http://www.w3.org/2005/Atom}entry') # если пустая, пропускаем номер и даем False if len(xml_to_parse) < 1: return False temp_links_list = SharepointRequest.__generate_download_links(xml_to_parse, output_path) for file_name, file_link in temp_links_list.items(): status = False status = SharepointRequest.download_files(file_link, file_name, username, password) if status: continue else: time.sleep(5)
@staticmethod def __generate_download_links(xml_from_request, output_path): temp_links_list = {} for entry in xml_from_request: content = entry.find('{http://www.w3.org/2005/Atom}content') properties = content.find('{http://schemas.microsoft.com/ado/2007/08/dataservices/metadata}properties') url = properties.find('{http://schemas.microsoft.com/ado/2007/08/dataservices}Url') if (url.text != ""): # Получаем ссылку на файл из xml и вытаскиваем все нужное download_link = url.text download_file_name = ''.join([output_path,'/', url.text.split('/')[-1]]) temp_links_list[download_file_name] = download_link return temp_links_list

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

Для визуализации прогресса, используем iter_content

def download_files(host_link, file_name, username, password): with open(file_name, 'wb') as file_loading: print(f"Downloading {file_name}") response = requests.get(host_link, auth=HttpNtlmAuth(username, password), verify=False, stream=True) total_file_length = response.headers.get('Content-Length') # Берем длину файла if total_file_length is None: file_loading.write(response.content) else: dl = 0 total_file_length = int(total_file_length) for data in response.iter_content(chunk_size=8192): dl += len(data) file_loading.write(data) done = int(50 * dl / total_file_length) sys.stdout.write("\r[%s%s]" % ('=' * done, ' ' * (50 - done))) sys.stdout.flush() if dl == total_file_length: return True

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

На этом все. Данное решение позволило мне выкачать около 500 гб файлов за 2 дня. Используйте в работе!

2
Начать дискуссию