Я создал свой первый ETL-конвейер, будучи полным новичком. Вот как это было.
Пошаговое руководство для начинающих по извлечению, преобразованию и загрузке данных с использованием API GitHub.
Делиться

Это вторая часть моей серии статей о моем пути в области инженерии данных. В первой части я поделился своим 12-месячным планом перехода от аналитика данных к инженеру данных. Именно здесь начинается настоящее строительство.
Когда я опубликовал свою первую статью, в которой описал свой путь в области инженерии данных, произошло нечто неожиданное. Она нашла отклик у людей. Ко мне стали обращаться незнакомые люди, говоря, что им интересно следить за моими успехами. Это было приятно.
Но это также сопровождалось давлением.
Внезапно это перестало быть просто личной целью, от которой я мог бы тихо отказаться, если бы стало трудно. За мной наблюдали. Люди были в той же ситуации. И эта ответственность, честно говоря, отчасти объясняет, почему вы читаете это сейчас.
Поэтому мне пришлось переехать. И, как и любой, кто начинает осваивать новую профессию, первым делом я стал искать ресурсы. В интернете бесчисленное множество руководств по инженерии данных. Видео на YouTube, курсы, письменные руководства. Их больше, чем вы когда-либо сможете пройти.
Но я не мог заставить себя довольствоваться лишь теорией. Мне нужно было что-то построить. Что-то реальное, с реальными данными, что действительно работало бы в итоге.
Поэтому я закрыл обучающие материалы и открыл вместо них блокнот Google Colab. Я нашел документацию по API GitHub и решил, что буду создавать свой первый ETL-конвейер с нуля. Без пошаговых инструкций. Просто я, немного Python и цель.
В этой статье подробно описан этот опыт. Код, путаница, небольшие успехи и то, чему я на самом деле научился, занимаясь этим.
Во-первых, что такое ETL?
Прежде чем я расскажу о том, что я создал, позвольте мне быстро объяснить, что на самом деле означает ETL, потому что мне самому пришлось это искать в интернете не так давно.
ETL расшифровывается как «Извлечение, Преобразование, Загрузка». Это одна из самых фундаментальных концепций в инженерии данных.
- Извлечение данных означает обращение к источнику информации. Это может быть API, база данных, веб-сайт или файл. Вы извлекаете необработанные данные из источника.
- Трансформация означает очистку и приведение данных в порядок. Удаление некорректных строк, добавление новых столбцов, реструктуризация данных для их реальной полезности.
- Загрузка означает сохранение очищенных данных где-либо. В базе данных, хранилище данных, простом CSV-файле.
Вот и всё. Эти три шага, выполняемые последовательно, и составляют основу конвейера обработки данных. Всё остальное в области инженерии данных — Airflow, Spark, Databricks — это просто более сложные способы выполнения тех же трёх задач в масштабе.
Я нахожусь в начале реализации своего плана, поэтому решил не усложнять. Чистый Python, никаких инструментов оркестровки пока нет. Но суть проблемы та же.
Что я построил
Я извлекла данные из API GitHub, а именно, самые популярные репозитории Python, созданные за последние 30 дней. Затем я очистила данные, добавила новый столбец и сохранила результат в виде CSV-файла.
Просто. Подлинно. Полностью моё.
Вот как всё прошло.
Шаг 1: Извлечение
Первым делом мне нужно было разобраться, как взаимодействовать с API GitHub. API — это, по сути, дверь, которую компания или платформа открывает, чтобы разработчики могли программно запрашивать у неё данные, не копируя и не вставляя ничего вручную.
GitHub предоставляет бесплатный общедоступный API. Для выполнения базовых поисковых запросов не требуется ни учетная запись, ни платный тарифный план.
Вот код, который я написал для извлечения данных:
import requests url = "https://api.github.com/search/repositories" params = { "q": "language:python created:>2025-04-22", "sort": "stars", "order": "desc", "per_page": 30 } response = requests.get(url, params=params) data = response.json() print(response.status_code) print(data.keys())
Честно говоря, этот блок поначалу меня смутил. Библиотека requests была для меня новой. Словарь params с синтаксисом q показался мне непривычным. Я не сразу понял, что делает .json() и зачем он мне нужен.
Позвольте мне объяснить это простыми словами.
-
requests.get()— это способ обратиться к GitHub с просьбой о чем-либо.url— это адрес того, что вы запрашиваете. - Конкретный вопрос, который вы задаете, касается словаря
params. В данном случае: «покажите мне репозитории Python, отсортированные по количеству звезд, созданные после 22 апреля, покажите 30 результатов». -
.json()преобразует ответ GitHub из необработанного текста в словарь Python, с которым вы можете работать.
Когда я запустил программу, получил вот это:
200 dict_keys(['total_count', 'incomplete_results', 'items'])
Код 200 означает успех. Так в интернете говорят: «Ваш запрос выполнен». Если вы видите 403 или 404, значит, что-то пошло не так.
Словарь имеет три ключа. total_count показывает, сколько репозиториев соответствовало поисковому запросу. incomplete_results показывает, пришлось ли GitHub что-либо сократить. А items — это место, где хранятся сами данные.
Затем я пробежал второй квартал, чтобы заглянуть внутрь:
print("Total matches on GitHub:", data['total_count']) print("Repos returned:", len(data['items'])) first_repo = data['items'][0] print("nFirst repo name:", first_repo['name']) print("Stars:", first_repo['stargazers_count']) print("Language:", first_repo['language']) print("URL:", first_repo['html_url'])
Выход:
Total matches on GitHub: 9228201 Repos returned: 30 First repo name: skills Stars: 139136 Language: Python URL: https://github.com/anthropics/skills
Первым результатом стал репозиторий Anthropic с 139 тысячами звезд. Реальные данные. В режиме реального времени. Получены с помощью написанного мной кода.
Экстракт готов.
Шаг 2: Преобразование
Теперь у меня было 30 репозиториев, хранящихся в списке Python, каждый из которых представлял собой вложенный словарь с десятками полей. Большинство из которых мне были не нужны. Этап преобразования — это когда вы берете эти необработанные, неряшливые данные и преобразуете их во что-то чистое и полезное.
Сначала я извлек только те поля, которые меня интересовали, и загрузил их в датафрейм Pandas:
import pandas as pd repos = [] for repo in data['items']: repos.append({ "name": repo['name'], "owner": repo['owner']['login'], "stars": repo['stargazers_count'], "forks": repo['forks_count'], "language": repo['language'], "description": repo['description'], "url": repo['html_url'], "created_at": repo['created_at'] }) df = pd.DataFrame(repos) df.head()
Увидев появившийся датафрейм, я испытал настоящий восторг. Из сплошного JSON-кода я всего за несколько строк превратился в чистую, читаемую таблицу с помеченными столбцами.
Затем я выполнил три преобразования:
# Drop rows where description is missing df_clean = df.dropna(subset=['description']) # Add a viral flag for repos with over 50k stars df_clean = df_clean.copy() df_clean['viral'] = df_clean['stars'].apply(lambda x: 'Yes' if x > 50000 else 'No') # Sort by stars descending df_clean = df_clean.sort_values('stars', ascending=False).reset_index(drop=True) print("Before cleaning:", len(df)) print("After cleaning:", len(df_clean))
Выход:
Before cleaning: 30 After cleaning: 29
Один репозиторий не имел описания и был удален. Столбец «Вирус» отобразился корректно. Данные теперь были отсортированы и структурированы.
Трансформация завершена.
Шаг 3: Загрузка
Последний шаг. Возьмите очищенные данные и сохраните их где-нибудь. Я поступил просто и загрузил их в CSV-файл:
df_clean.to_csv('github_trending_repos.csv', index=False) print("Pipeline complete. File saved.") print(f"{len(df_clean)} repos loaded into github_trending_repos.csv")
Выход:
Pipeline complete. File saved. 29 repos loaded into github_trending_repos.csv
Я скачал файл и открыл его. Чистая электронная таблица с 29 строками и 9 столбцами. Реальные данные с GitHub, сформированные и сохраненные с помощью созданного мной с нуля конвейера обработки данных.
Загрузка завершена.
Каково это было на самом деле
Раньше, когда мне нужны были данные для работы, я искал общедоступные наборы данных, которые кто-то уже обработал и загрузил. Kaggle, поиск наборов данных в Google, где угодно. Я всегда был потребителем данных, подготовленных кем-то другим.
Это кое-что изменило в моей жизни.
В тот момент, когда я понял, что могу просто указать Python на интересующий меня API и самостоятельно извлекать данные в режиме реального времени, передо мной открылись совершенно новые возможности. Я не ограничен уже существующими наборами данных. Я могу построить конвейер, который создаст этот набор данных.
Это совершенно другой вид власти. И именно это изначально привлекло меня к инженерии данных.
Что дальше?
Этот конвейер прост по своей конструкции. Я нахожусь в начале своего пути развития и пока не буду притворяться, что использую Airflow или Spark. Но основа реальна. Извлечение, преобразование, загрузка. Это работает. Я это создал. Я это понимаю.
Следующий шаг — сделать систему более надежной. Настройте ее на ежедневное выполнение. Сохраняйте выходные данные в базе данных SQLite вместо обычного CSV-файла. Начните отслеживать динамику изменений репозиториев с течением времени.
И в конечном итоге, всю систему можно будет организовать с помощью Airflow. Но это тема для будущей статьи.
На данный момент самое важное, что я доказал себе, это то, что процесс сборки учит тому, чему никогда не научишься, просто посмотрев видео. Я провел недели в мире обучающих материалов и почти не двигался с места. Я провел всего один день, непосредственно занимаясь сборкой, и теперь понимаю ETL лучше, чем мне казалось по любым видео.
Прекратите смотреть. Начните строить.
Это вторая часть моей продолжающейся серии статей по проектированию данных. Следите за каждым этапом, включая те моменты, которые проходят не совсем гладко. Более подробный обзор ETL-процессов вы можете посмотреть на моем YouTube-канале ниже.
Свяжитесь со мной в LinkedIn, YouTube и Twitter.
Ибрагим Салами. Все материалы от Ибрагима Салами.
Источник: towardsdatascience.com

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