Получение ответов на свои вопросы по программированию, не выходя из терминала

Около месяца назад я наткнулся на проект 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.

Удачного кодирования!