CoderCastrov logo
CoderCastrov
Airtable

Парсинг поверхности Airtable (Часть 2)

Парсинг поверхности Airtable (Часть 2)
просмотров
6 мин чтение
#Airtable

Прежде чем мы начнем, давайте оценим факт, что первая часть вышла 2 года назад!

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

Эта часть будет построена на основе первой, или, чтобы подытожить: оказывается, я на правильном пути, и requestId не имеет большого значения, может быть, я сделал ошибку при его копировании в последнем посте? В любом случае, в этом посте я расскажу о нескольких вещах:

  • Почему я решил не использовать Airtable API?
  • Почему я решил использовать нативные запросы и не использовал безголовый браузер
  • Мое текущее решение, использующее только запросы и регулярные выражения (оно не очень красивое, но работает :))
  • Куда я могу пойти отсюда

Если вы хотите следовать за мной, вы можете найти блокнот и исходный код на моем GitHub или вы можете запустить его на Google Colab. Если вы просто хотите использовать пакет, вы можете установить его из pip. И используйте код на свой страх и риск, так как это поведение не гарантируется быть постоянным со временем (я не знаю, решит ли команда Airtable изменить это в ближайшее время).

Почему не использовать API Airtable?

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

  • API ограничен скоростью до 5 запросов в секунду, и в моей текущей базе уже несколько сервисов обращаются к API. Чтобы минимизировать риск превышения лимита скорости и понести наказание в виде 30-секундной задержки, я решил не использовать официальное API.
  • Я хочу создать решение, которое может работать только с помощью общей ссылки на таблицу, чтобы ограничить доступ только к определенной части базы (а не ко всей базе целиком).
  • И, наконец, иногда бывает весело заниматься такими вещами :)

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

Почему не использовать Headless Browser

Используя headless браузер, я мог бы просто перейти по ссылке и нажать на кнопку "Скачать CSV" и закончить работу. И, если честно, это кажется лучшим вариантом. Однако, я хочу, чтобы решение было "легким" насколько это возможно, а headless браузер не является самой компактной программой. Поэтому я решил работать, используя только минимальное количество пакетов Python. В данном случае, для работы практически достаточно beautifulsoup4.

Текущее решение

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

Создание пользовательского представления и создание секретной ссылки

Я все еще использую тот же метод, что и в первой части, и первое, что мне нужно сделать, это создать секретную общую ссылку на представление. Для этого просто перейдите к интересующей вас таблице, в данном случае мы будем использовать таблицу "Stories" и представление "All stories". Затем нажмите кнопку "Поделиться представлением" и скопируйте сгенерированную ссылку на сетку. О, не забудьте оставить активированной опцию "Разрешить пользователям копировать данные из этого представления".

Создание общей ссылки на представление в Airtable

Для остальной части этой статьи мы будем использовать ссылку, сгенерированную из этой базы: https://airtable.com/shr5aMEsXCxORIwhk

Получение необходимой информации из ответа

Какая необходимая информация??

Я расскажу немного о том, как я определил, какая информация является необходимой. Сначала я открыл инструменты разработчика браузера и перешел на вкладку "Сеть" (оставил ее открытой, чтобы убедиться, что сетевая активность будет записана), затем нажал кнопку "Скачать CSV". Я нашел запрос, отправленный моим браузером для загрузки CSV.

https://airtable.com/v0.3/view/viwJuiikzJnQ0cyqj/downloadCsv?x-time-zone=Asia%2FJakarta&x-user-locale=en&x-airtable-application-id=app7CUJtL7vQWbiDA&stringifiedObjectParams=%7B%22origin%22%3A%22viewMenuPopover%22%7D&requestId=req18VeOicyq8MN7f&accessPolicy=%7B%22allowedActions%22%3A%5B%7B%22modelClassName%22%3A%22view%22%2C....

Что это вообще означает? Чтобы узнать, давайте перейдем в Postman и позволим ему разобрать параметр. Оказывается, что запрос попадает на конечную точку https://airtable.com/v0.3/view/{viewId}/downloadCsv?{query_params}, где viewId - это идентификатор нашего общего представления, а параметры запроса показаны ниже.

Хорошо, теперь следующая задача, которую нам нужно выполнить, - выяснить, какие параметры являются необходимыми и как их сгенерировать. Я сделал это, удаляя один параметр за другим и многократно отправляя запрос. После часа проб и ошибок я выяснил, что практически ни один заголовок не нужно явно устанавливать. И для успешного выполнения запроса нам нужны следующие параметры:

  • viewId, который генерируется каждый раз при загрузке страницы
  • AccessPolicy, который указывает, что нам разрешено делать в общем доступе
  • AppId, я не знаю, что он указывает, но когда я удаляю этот параметр, запрос всегда завершается неудачно
  • Locale, который указывает локаль нашей машины, я просто использую значение en по умолчанию, так как мне не было интересно узнавать другие допустимые значения для этого
  • Timezone, который используется для преобразования столбца времени в представлении в соответствии с часовым поясом пользователя.

С учетом этого давайте перейдем к извлечению этих данных со страницы общего доступа.

Извлечение информации

После того, как я попробовал другие GET-запросы к URL общего доступа и искал имена параметров, я обнаружил, что тег script сразу после тега title содержит всю необходимую информацию.

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


Соберите URL для загрузки CSV и выполните запрос!

С этими параметрами последний шаг - сбор URL, необходимого для загрузки CSV, и использование его для отправки GET-запросов.

Он вернет данные CSV, которые мы хотим, в виде строки. Вы можете сохранить его в файл или использовать StringIO, чтобы передать его в pandas и многое другое. Кстати, я думаю, что Airtable использует кодировку UTF-8 для кодирования данных CSV, поэтому убедитесь, что измените кодировку ответа после получения запросов.

Готовый скрипт

Если вы просто хотите получить готовый продукт, вы можете склонировать готовый пакет из моего репозитория на GitHub или установить его с помощью pip и использовать его как CLI.

Куда пойти отсюда?

Ну, есть несколько вещей, которые мы можем развить в этой идее:

  • Создать функцию Google для использования в качестве конечной точки для резервного копирования представления Airtable.
  • Использовать ее в качестве части конвейера ETL (например, airflow, singer и т. д.).
  • Развернуть cron-задание, вызывающее этот скрипт для резервного копирования данных на ваш сервер.

Для следующей части я думаю, что я расскажу о том, как использовать это в качестве части конвейера ETL в Google Cloud Platform с использованием функций и BigQuery, но учитывая, что первая часть заняла целых два года, посмотрим, сколько времени мне понадобится для следующей части :)

На данный момент, спасибо за чтение, и если вам интересна дальнейшая дискуссия, не стесняйтесь связаться со мной в комментариях или в моем твиттере @BanditelolRP