Получение ответов на свои вопросы по программированию, не выходя из терминала
Около месяца назад я наткнулся на проект howdoi, созданный на Python. И, честно говоря, это было потрясающе, решение основных проблем без открытия браузера было спасением, поэтому я подумал о создании такого решения для себя. Одной из моих главных целей была скорость, поэтому я выбрал Голанг.
Итак, сегодня позвольте мне показать вам, как использовать Stack Overflow, используя только терминал.
Создайте среду Go
Я не буду вдаваться в подробности о том, как установить Go или как должна выглядеть структура каталогов. Вы можете найти все на официальной странице и в документации.
Что нам нужно
- Скребок для получения постов по поисковому запросу.
- Скребок для получения содержания каждого вопроса.
- Пользовательский интерфейс для отображения решения.
Получите результат поискового запроса
Общий поисковый URL-адрес Stack Overflow выглядит примерно так:
https://stackoverflow.com/search?q=how+to+add+2+numbers
Это упрощает получение результата, так как то, что нам нужно менять каждый раз, - это только часть после search?q=
.
После получения содержимого страницы нашей следующей задачей будет получение содержимого из правильных элементов, таких как заголовок, описание, ссылка на публикацию и голоса за. Для этого сначала нам нужно создать Struct для хранения этих данных.
Для получения содержимого страницы воспользуемся библиотекой goquery.
Фрагмент кода для получения данных из поиска:
При проверке исходного кода я обнаружил, что вопрос хранится в div с классом question-summary
. Итак, мы переберем каждый элемент с этим классом и получим необходимые детали из div.
Класс для:
- Ссылка для публикации -
.result-link
. - Описание вопроса
.excerpt
. - Количество голосов за
.vote-count-post
. - Заголовок такой же, как тег ссылки, все, что нам нужно, это получить текст для тега.
После получения всего содержимого мы сохраним данные в списке постструктур.
Окончательный исходный код для получения данных будет выглядеть примерно так:
После этого мы закончили получение содержимого страницы поиска и сохранение его в нашем массиве. Следующая часть будет получать контент для каждого вопроса и сохранять его в другом массиве.
Получите содержание каждого сообщения
У нас есть URL-адрес каждого сообщения, хранящегося в массиве из предыдущего раздела, наша следующая задача - перейти по каждой из этих ссылок, получить контент с этой страницы и сохранить его в другом массиве.
Страница ответов на переполнение стека состоит из двух частей: раздела вопросов и списка решений.
Мы получим каждое решение, сохраним его в другом массиве и вернем ответы вместе с принятым ответом. Это будет то же самое, что и в предыдущей части. Структура, которую мы будем использовать для этой части, будет:
type solution struct {
description string
upvotes string
}
Итак, класс для вопросов - .question
, а для принятого ответа - accepted-answer
.
После этого оставшиеся ответы будут извлечены с использованием относительного div из принятого ответного div.
Код для получения содержания вопроса:
var answers []solution
question := res.Find(".question").Find(".post-layout")
answers = append(answers, solution{strings.Trim(question.Find(".post-text").Text(), "\n"), question.Find(".js-vote-count").Text()})
Код для получения принятого ответа:
acceptedContainer := res.Find(".accepted-answer").Find(".post-layout")
acceptedAnswer := solution{strings.Trim(acceptedContainer.Find(".post-text").Text(), "\n"), acceptedContainer.Find(".js-vote-count").Text()}
И, наконец, для получения оставшихся ответов:
Итак, объединив все, мы получим:
У нас есть все, что нам нужно, список вопросов со страницы поиска, а затем решение для каждого сообщения.
Теперь нам нужно отобразить контент в пользовательском интерфейсе. Мы попытаемся получить две части: одну для вопросов, а другую - для описания вопроса. Что-то вроде этого:
Мы будем использовать библиотеку termui. В нашем пользовательском интерфейсе будет три раздела: один для списка вопросов, другой для описания вопроса и последний для возможного решения.
Мы будем отображать два раздела одновременно. Я не буду рассматривать всю библиотеку, поскольку нам нужны только некоторые ее части.
Для создания блока с абзацем внутри у нас есть виджет, уже предоставленный в библиотеке, но проблема в том, что мы не можем его прокрутить, поэтому для этого мы создадим наш собственный виджет абзаца.
Исходный код виджета приведен ниже.
Для структуры:
И оставшаяся кодовая база:
Теперь объяснение всего кода будет в другой статье, но, чтобы дать вам суть, он в основном берет заданный нами стиль и создает ячейки, а затем берет весь текст и разбивает его на строки.
Затем он перебирает каждую строку, втягивая ее в указанную выше ячейку и помещая в правильное положение.
Важная часть:
Эта часть обрабатывает прокрутку контента, то есть мы предоставляем два значения, одно - это начало, а другое - конец.
Затем он использует эти значения для нарезки массива, чтобы мы рисовали только часть всего содержимого на экране. Это начальное и конечное значение будет меняться при каждом нажатии клавиши, поэтому содержимое будет выглядеть так, как будто оно прокручивается.
Остальная часть этой части довольно проста, мы будем использовать этот недавно созданный виджет и создадим три блока с разным содержимым.
Я не буду показывать здесь код этой части, так как это сделает сообщение излишне длинным, вместо этого я объясню последовательность действий. Итак, сначала создадим три абзаца.
Пример кода:
И тогда единственной задачей будет отобразить правильный блок при правильном нажатии клавиши. Итак, termui предоставляет несколько функций, например Render, для визуализации определенного элемента и целую привязку клавиатуры для ссылки на каждую клавишу. Пример кода:
Таким образом, это обрабатывает закрытие пользовательского интерфейса, если кто-то нажимает q или CTRL + c, мы можем добавить другие случаи, чтобы отображать правильное поле при нажатии клавиши.
Финал будет работать примерно так:
Вы можете найти весь исходный код на GitHub.
Удачного кодирования!