Twitter — популярный ресурс для анализа социальных сетей и обработки естественного языка. Если мы хотим делать эти вещи в Clojure, логично, что нам нужен способ доступа к Twitter. Это простой пример того, как обрабатывать данные Twitter.

вступление

Первый шаг к работе с Twitter — настройка учетной записи разработчика. Я не буду вдаваться в подробности. В Твиттере есть отличная документация для разработчиков, с которой вам обязательно стоит ознакомиться, и довольно просто создать учетную запись разработчика (подсказка: идите сюда).

Мне нравится twitter-api в качестве предпочтительной библиотеки твиттера Clojure, и именно ее мы будем здесь использовать. Добавьте последнюю версию в описание вашего проекта Leinengen или загрузите файл .jar. Все, что плывет в вашей лодке. Это все, что вам нужно для этой демонстрации.

Первые шаги

После того, как вы настроили проект с помощью twitter-api, вы готовы написать код. Первое, что мы хотим сделать, это добавить библиотеки и пройти аутентификацию с вашими учетными данными:

(ns WonderfulCoyote-twitterDemo (:use [twitter.oauth] [twitter.callbacks] [twitter.callbacks.handlers] [twitter.api.restful]) (:import [twitter.callbacks.protocols SyncSingleCallback]) ) (def my-creds (make-oauth-creds "cnsmr-key" "cnsmr-secrt" "accss-key" "accss-secrt" ))

Очевидно, используйте свои настоящие учетные данные вместо фиктивных учетных данных.

[Примечание: если вы запускаете это в REPL, используйте версии использования и импорта REPL, например, (use '(twitter.oauth))]

Наш первый запрос в Твиттере

Для нашего первого запроса давайте посмотрим на аккаунт POTUS в Twitter:

(users-show :oauth-creds my-creds :params {:screen-name "POTUS"})

Довольно легко, да? Библиотека twitter-api дает нам удобные функции для большинства конечных точек. (Хотите знать все, о чем идет речь? Читайте документы!)

Здесь мы просто передаем кредиты в качестве именованного аргумента функции users-show и указываем желаемое имя пользователя в качестве параметра. Вы захотите прочитать документы Twitter, чтобы выяснить все параметры, которые вы можете использовать для указания ваших запросов.

Немного больше…

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

(map ;; Notice that get/get-in can be used to easily and clearly access nested pieces of the nested map/JSON (fn [x] [(x :text) (map #(get % :text) (get-in x [:entities :hashtags])) (x :retweet_count) (x :favorite_count) (x :id)]) ;; We use get-in body/statuses to get the tweets (Twitter calls these "statuses") in the "body" of the HTTP response (get-in (search-tweets :oauth-creds my-creds :params {:q "#friday" :count 100}) [:body :statuses]) )

Распределение количества хэштегов

Возможно, нас интересуют не отдельные твиты, а распространение поведения, например использование хэштегов. Здесь мы группируем твиты по количеству используемых в них хэштегов. В этом случае мы используем поисковый термин «пятница» (поиск в Твиттере нечувствителен к регистру, к вашему сведению, поэтому это соответствует «пятница», но также и «пятница», «FRiday», «friDAY» и т. д.)

;; Start with let, just to take the search business out of the way (let [tweets (get-in (search-tweets :oauth-creds my-creds :params {:q "friday" :count 100}) [:body :statuses])] ;; Return first element as first elem and count number of tweets for second elem (map (fn [x] [(get x 0) (count (get x 1))]) ;; Group tweets by the number of hashtags they use  (group-by (fn [x] (count (get-in x [:entities :hashtags]))) tweets)) )

Это вернет аккуратную небольшую последовательность пар целых чисел. Первое — это количество хэштегов, а второе — количество твитов из нашего опроса, в которых было столько хэштегов. Мои результаты были:

([0 10] [7 5] [1 18] [4 9] [6 7] [3 12] [12 2] [2 26] [11 1] [5 5] [8 2])

Это похоже, что мы можем смоделировать с помощью распределения Пуассона

Повторная выборка

Скажем, мы заинтересованы в тестировании частоты хэштегов для разных тем, мы будем хотеть делать эту группировку снова и снова. Это требует функции. Мы можем построить его так:

(defn countByHashtagSearch "Takes string and returns a 100-sample hashtag-use distribution" ;; Notice that we've overloaded the function definition here ;; You *can* specify the number of tweets you'd like -- otherwise it defaults to 10 ([my-string] (countByHashtagSearch my-string 10)) ([my-string n] (let [tweets (get-in (search-tweets :oauth-creds my-creds :params {:q my-string :count n}) [:body :statuses])] (map (fn [grp] [(get grp 0) (count (get grp 1))]) (group-by (fn [twt] (count (get-in twt [:entities :hashtags]))) tweets)))))

Обратите внимание на перегрузку функций здесь. Здесь мы просто используем его, чтобы разрешить необязательный параметр.

Теперь давайте используем нашу функцию для использования:

(countByHashtagSearch "clojure" 100) (countByHashtagSearch "scala" 100) (countByHashtagSearch "haskell" 100) (countByHashtagSearch "lisp" 100)

И получаем обратно:

;; clojure ([0 49] [1 33] [2 9] [3 5] [5 1] [9 2] [12 1]) ;; scala ([0 82] [1 8] [3 2] [2 7] [4 1]) ;; haskell ([0 85] [1 11] [10 1] [2 2] [3 1]) ;; lisp ([0 88] [1 7] [2 3] [4 2])

Мне кажется, что жители Clojurian предпочитают хэштеги больше, чем пользователи некоторых похожих языков (хотя мы, вероятно, хотим быть осторожными — «шепелявость» может означать не то, что мы хотим, чтобы это означало здесь). Тем не менее, наше распределение Пуассона думало, что тут точно развалится. 12 находится довольно далеко в хвосте для распределения с λ ≅ 1.

Более

Для сбора большого количества данных Twitter я рекомендую сохранять данные полностью в виде файлов .json или .txt, где каждая строка представляет собой твит. Мне нравится clj-json для обработки JSON в Clojure.

Код этого руководства доступен на моем GitHub

Первоначально опубликовано на www.jtwolohan.com.