Получение информации с LeetCode о пользователе на Golang
LeetCode — популярная платформа для подготовки к собеседованиям по программированию, предоставляющая задачи на алгоритмы и структуры данных. Чтобы улучшить свои навыки и изучить свои успехи, пользователи могут хотеть получить информацию о своем профиле на LeetCode, такую как решенные задачи, статистика по времени и другие данные.
В данной статье будет рассмотрено, как можно написать программу на Golang для получения информации о пользователе с помощью API LeetCode. Для разработки будет использоваться библиотека graphql на Golang, чтобы отправить запросы к API LeetCode и получить необходимые данные о пользователе. Для простоты взаимодействия с пользователями будет использован Telegram API. Стоит добавить, что для Телеграм бота не нужно покупать отдельный хостинг, можно все сделать локально, нужно только доступ к интернету.
Почему Golang, а не Python?
Выбор между Golang и Python для разработки ботов зависит от конкретных требований проекта, но есть несколько аспектов, в которых Golang может оказаться более предпочтительным выбором по сравнению с Python:
Производительность: Golang обычно обладает более высокой производительностью и эффективностью исполнения кода по сравнению с Python. Это может быть критично для ботов, которые должны обрабатывать большие объемы данных или выполнять сложные вычисления.
Кроссплатформенность: Golang поддерживает кроссплатформенность, что означает, что боты, разработанные на Golang, могут легко работать на различных операционных системах без необходимости внесения изменений в код.
Статическая типизация: Golang является языком программирования со статической типизацией, что может помочь обнаружить ошибки на ранних этапах разработки и сделать код более надежным.
Многопоточность: Golang имеет встроенную поддержку горутин, которые облегчают параллельное выполнение операций, что особенно полезно для ботов, работающих с большим количеством одновременных запросов.
Эффективность работы с конкурентностью: Golang имеет механизмы управления конкурентностью, такие как каналы (channels) и слабые блокировки (mutexes), что облегчает создание многозадачных ботов.
Хотя Python также является популярным и мощным языком программирования для разработки ботов благодаря своей легкости и простоте в использовании, Golang может быть предпочтительным выбором, особенно если важны производительность, эффективность и работа с высокой нагрузкой.
Разработка
Перед тем как начать разрабатывать необходимо установить необходимые для работы библиотеки.
go install -v github.com/go-telegram-bot-api/telegram-bot-api/v5
go install -v github.com/machinebox/graphql
Для удобства поддержки и читаемости необходимо организовать код, храня различную функциональность в отдельных файлах. Начнем с того, что есть некая точка входа main.go через которую запускается бот:
main.go
package main
import (
"log"
)
func check(err error) {
if err != nil {
log.Println(err)
}
}
func main() {
startBot()
}
После точки входа следует создать файл telegram.go, в котором будет происходить логика работы Телеграм бота, такая как: получение информации от пользователя, отправка ответа пользователю, отправка инструкции использования пользователю:
telegram.go
package main
import (
"strconv"
botAPI "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
func isCallbackQuery(update *botAPI.Update) bool {
return update.CallbackQuery != nil && update.CallbackQuery.Message.Text != ""
}
func isStartMessage(update *botAPI.Update) bool {
return update.Message != nil && update.Message.Text == "/start"
}
func getKeyboardRow(buttonText string, buttonCode string) []botAPI.InlineKeyboardButton {
return botAPI.NewInlineKeyboardRow(botAPI.NewInlineKeyboardButtonData(buttonText, buttonCode))
}
func renderingMenu(bot *botAPI.BotAPI, chatId int64) {
msg := botAPI.NewMessage(chatId, "Select action")
msg.ReplyMarkup = botAPI.NewInlineKeyboardMarkup(
getKeyboardRow(left+" "+"Information about bot"+" "+right, "info"),
)
bot.Send(msg)
}
func updateProccessing(update *botAPI.Update, bot *botAPI.BotAPI) {
var message string
choice := update.CallbackQuery.Data
if choice == "info" {
message = "My functionality: \n Get username information from leetcode. You only need to send the username in a message and get the result immediately"
}
msg := botAPI.NewMessage(update.CallbackQuery.From.ID, message)
bot.Send(msg)
}
func startBot() {
var message string
bot, err := botAPI.NewBotAPI(token)
check(err)
updateConfig := botAPI.NewUpdate(0)
updateConfig.Timeout = timeout
updates := bot.GetUpdatesChan(updateConfig)
for update := range updates {
if isCallbackQuery(&update) {
updateProccessing(&update, bot)
} else {
if isStartMessage(&update) {
message = "Hi everyone! \nIt's a telegram bot. You can get information from leetcode by username. If you need more information than click info."
renderingMenu(bot, update.Message.Chat.ID)
} else {
username := getUsersInfo(update.Message.Text)
if username.MatchedUser.Username == "" {
message = cancel+"Information: \nusername: user not found"
} else {
message = "Information: \nusername: " + username.MatchedUser.Username
message += "\n" + solved + "solved: " + strconv.Itoa(username.MatchedUser.SubmitStats.AcSubmissionNum[0].Count) + " / " +strconv.Itoa(username.AllQuestionsCount[0].Count)
message += "\n" + easy + "Easy: " + strconv.Itoa(username.MatchedUser.SubmitStats.AcSubmissionNum[1].Count) + " / " + strconv.Itoa(username.AllQuestionsCount[1].Count)
message += "\n" + middle + "Middle: " + strconv.Itoa(username.MatchedUser.SubmitStats.AcSubmissionNum[2].Count) + " / " + strconv.Itoa(username.AllQuestionsCount[2].Count)
message += "\n" + hard + "Hard: " + strconv.Itoa(username.MatchedUser.SubmitStats.AcSubmissionNum[3].Count) + " / " + strconv.Itoa(username.AllQuestionsCount[3].Count)
}
}
msg := botAPI.NewMessage(update.Message.Chat.ID, message)
msg.ReplyToMessageID = update.Message.MessageID
bot.Send(msg)
}
}
}
Следующая функциональность бота — работа с graphql. Для удобства использования были созданы структуры и определены к ним поля, которые используются в graphql запросах и вынесено в отдельный файл model.go:
model.go
package main
type Submission struct {
Count int `json:"count"`
Difficulty string `json:"difficulty"`
}
type UserProfileData struct {
MatchedUser MatchedUser `json:"matchedUser"`
AllQuestionsCount []Submission `json:"allQuestionsCount"`
}
type SubmitStats struct {
AcSubmissionNum []Submission `json:"acSubmissionNum"`
}
type MatchedUser struct {
Username string `json: username`
SubmitStats SubmitStats `json:"submitStats"`
}
Для общения с API LeetCode был создан graphql.go. Для простоты использования были созданы функции, которые возвращают graphql запросы. Основная функция осуществляет запрос к API и возвращает структуру, в которой хранится информация о пользователе: имя пользователя, сколько всего решил задач и сколько по каждому уровню сложности было решено:
graphql.go
package main
import (
"context"
"github.com/machinebox/graphql"
)
func getQueryUserInfo() string {
return `query ($username: String!) { matchedUser(username: $username) {
username
submitStats {
acSubmissionNum {
difficulty
count
}
}
}
}`
}
func getQueryQntyQuestions() string {
return `{ allQuestionsCount {
difficulty
count
}
}`
}
func getUsersInfo(username string) UserProfileData {
var requestUser UserProfileData
client := graphql.NewClient("https://leetcode.com/graphql")
query := getQueryQntyQuestions()
request := graphql.NewRequest(query)
ctx := context.Background()
err := client.Run(ctx, request, &requestUser)
check(err)
query = getQueryUserInfo()
request = graphql.NewRequest(query)
request.Var("username", username)
err = client.Run(ctx, request, &requestUser)
if err != nil {
check(err)
}
return requestUser
}
Для хранения константных информаций: токен, таймаут, эмодзи, если нужно, создан constants.go:
constants.go
package main
const (
token = "Your Token"
left = "\U000025B6"
right = "\U000025C0"
easy = "\U0001F4D7"
hard = "\U0001F4D5"
middle = "\U0001F4D9"
solved = "\U00002705"
cancel = "\U0001F6AB"
timeout = 5
)
Проверка работоспособности
Предстоит протестировать бот. Для проверки будет взят username автора статьи и несуществующий пользователь (к существующему пользователю допишется цифра). Для начала предстоит проверка на существующем пользователе. Была получена данная информация, да эта информация верна, вот пользователь на LeetCode.
Приветствие бота и получение инструкции
Получение информации о пользователе
результат с сайта LeetCode
А теперь проверим на несуществующем. Бот ответил, что такого пользователя нет.
Получение информации, что нет такого пользователя
Результат, что пользователя нет такого
Вывод
Получение информации о пользователе с платформы LeetCode на языке программирования Golang может быть важным и полезным шагом для разработчиков, желающих улучшить свои навыки в алгоритмах и структурах данных. Используя API LeetCode, можно получить доступ к различным данным о пользователе.