Как сохранить файл Google Sheets как CSV из Python 3 (или 2)?

Я ищу простой способ сохранить CSV-файл, созданный на основе опубликованного документа Google Sheets? Поскольку он опубликован, он доступен по прямой ссылке (специально изменено в приведенном ниже примере).

Все мои браузеры предложат мне сохранить CSV-файл, как только я запущу ссылку.

Ни:

DOC_URL = 'https://docs.google.com/spreadsheet/ccc?key=0AoOWveO-dNo5dFNrWThhYmdYW9UT1lQQkE&output=csv'    

f = urllib.request.urlopen(DOC_URL)
cont = f.read(SIZE)
f.close()
cont = str(cont, 'utf-8')
print(cont)

ни

req = urllib.request.Request(DOC_URL)
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.13 (KHTML, like Gecko) Chrome/24.0.1284.0 Safari/537.13')
f = urllib.request.urlopen(req)
print(f.read().decode('utf-8'))

напечатать что-нибудь, кроме содержимого HTML.

(Пробовал 2-ую версию после прочтения этого другого поста: Загрузите электронную таблицу Google Docs в CSV с Python.)

Есть идеи, что я делаю не так? Я вышел из своей учетной записи Google, если это чего-то стоит, но это работает из любого браузера, который я пробовал. Насколько я понял, API Google Docs еще не портирован на Python 3 и, учитывая "игрушечную" величину моего маленького проекта для личного использования, даже не было бы особого смысла использовать его с самого начала, если Я могу обойти это.

Во 2-й попытке я оставил "User-Agent", так как думал, что, возможно, запросы, воспринимаемые как скрипты (поскольку идентификационная информация отсутствует) могут игнорироваться, но это не имеет значения.

2 ответа

Решение

Google отвечает на первоначальный запрос серией переадресаций 302 с настройками файлов cookie. Если вы не сохраняете и не отправляете файлы cookie между запросами, он перенаправляет вас на страницу входа.

Итак, проблема не в заголовке User-Agent, а в том, что по умолчанию urllib.request.urlopen не хранит куки, но будет следовать перенаправлениям HTTP 302.

Следующий код прекрасно работает с общедоступной электронной таблицей, доступной по адресу, указанному DOC_URL:

>>> from http.cookiejar import CookieJar
>>> from urllib.request import build_opener, HTTPCookieProcessor
>>> opener = build_opener(HTTPCookieProcessor(CookieJar()))
>>> resp = opener.open(DOC_URL)
>>> # should really parse resp.getheader('content-type') for encoding.
>>> csv_content = resp.read().decode('utf-8')

Показав вам, как это сделать в vanilla python, я сейчас скажу, что для решения этой проблемы необходимо использовать библиотеку самых превосходных запросов. Он чрезвычайно хорошо задокументирован и делает такие задачи невероятно приятными для выполнения.

Например, чтобы получить то же самое csv_content как указано выше, используя requests Библиотека так же проста, как:

>>> import requests
>>> csv_content = requests.get(DOC_URL).text

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

В то время как requests библиотека является золотым стандартом для HTTP-запросов от Python, этот стиль загрузки (хотя пока не устарел) вряд ли будет длиться долго, особенно в отношении использования ссылок, управления файлами cookie, перенаправлениями и т. д. Одна из причин не предпочитает ссылки является то, что это менее безопасно, и, как правило, такой доступ требует авторизации. Вместо этого в настоящее время приемлемым способом экспорта Google Sheets в виде CSV является использование Google Drive API.

Так почему же Drive API? Разве это не должно быть что-то для Sheets API вместо этого? Итак, API Sheets предназначен для функциональных возможностей, ориентированных на электронные таблицы, т. Е. Для форматирования данных, изменения размера столбцов, создания диаграмм, проверки ячеек и т. Д., В то время как Drive API предназначен для функциональных возможностей, ориентированных на файлы, т. Е. Для импорта / экспорта, копирования, переименования, и т.п.

Ниже приведено полное решение cmd-line. (Если вы не используете Python, вы можете использовать его в качестве псевдокода и выбрать любой язык, поддерживаемый клиентскими библиотеками API Google.) Для фрагмента кода предположим, что самый последний лист называется inventory (старые файлы с таким именем игнорируются) и DRIVE является конечной точкой службы API:

FILENAME = 'inventory'
SRC_MIMETYPE = 'application/vnd.google-apps.spreadsheet'
DST_MIMETYPE = 'text/csv'

# query for latest file named FILENAME
files = DRIVE.files().list(
    q='name="%s" and mimeType="%s"' % (FILENAME, SRC_MIMETYPE),
    orderBy='modifiedTime desc,name').execute().get('files', [])

# if found, export Sheets file as CSV
if files:
    fn = '%s.csv' % os.path.splitext(files[0]['name'].replace(' ', '_'))[0]
    print('Exporting "%s" as "%s"... ' % (files[0]['name'], fn), end='')
    data = DRIVE.files().export(fileId=files[0]['id'], mimeType=DST_MIMETYPE).execute()

    # if non-empty file
    if data:
        with open(fn, 'wb') as f:
            f.write(data)
        print('DONE')

Если ваш лист большой, вам, возможно, придется экспортировать его порциями - см. Эту страницу, чтобы узнать, как это сделать. Если вы, как правило, плохо знакомы с API Google, у меня есть (несколько устаревшее, но) удобное вводное видео для вас. (После этого есть 2 видео, которые тоже могут быть полезны.)

Другие вопросы по тегам