StreamingApi.scala (5161B)
1 package twitterCrawler 2 3 import java.io.File 4 import java.text.SimpleDateFormat 5 import java.util.Date 6 7 import com.danielasfregola.twitter4s.entities.streaming.common.{DisconnectMessage, LimitNotice, WarningMessage} 8 import com.danielasfregola.twitter4s.entities.{Tweet, User} 9 import com.danielasfregola.twitter4s.http.clients.streaming.TwitterStream 10 import com.danielasfregola.twitter4s.{TwitterRestClient, TwitterStreamingClient} 11 import com.github.tototoshi.csv.CSVWriter 12 import com.typesafe.config.{Config, ConfigFactory} 13 import com.typesafe.scalalogging.StrictLogging 14 import org.joda.time.{DateTime, DateTimeZone} 15 16 import scala.collection.JavaConverters._ 17 import scala.concurrent.ExecutionContext.Implicits.global 18 import scala.concurrent.{Await, Future} 19 20 21 object RestAPISingleton { 22 private var restAPI: TwitterRestClient = _ 23 def getRestAPI: TwitterRestClient = { 24 this.restAPI 25 } 26 27 def setRestAPI(restAPI: TwitterRestClient): Unit = { 28 this.restAPI = restAPI 29 } 30 31 } 32 33 /** 34 * 35 * StreamingAPI class is the connector for the Twitter Streaming Api 36 * 37 * It mainly has the purpose to get Tweets of the users from the Lists and Hashtags defined inside the Config 38 * 39 * @param streamingClient holds the current Client for the Twitter Streaming API 40 */ 41 class StreamingApi(val streamingClient: TwitterStreamingClient) extends StrictLogging { 42 val conf: Config = ConfigFactory.load() 43 val restClient: TwitterRestClient = RestAPISingleton.getRestAPI 44 45 /** 46 * fetchTweets is a async function, that listens on Twitter's Streaming API for the defined Lists and Hastags 47 * 48 * @return 49 */ 50 def fetchTweets: Future[TwitterStream] = { 51 val trackedWordsConf = 52 conf.getStringList("twitter.trackedWords") 53 var trackedWords: Seq[String] = Seq() 54 val trackedLists: List[String] = 55 conf.getStringList("twitter.lists").asScala.toList 56 val trackedUsers: Seq[Long] = Await.result( 57 this.getListUsers(trackedLists), 58 scala.concurrent.duration.Duration.Inf 59 ) 60 61 trackedWordsConf.forEach((s: String) =>{ 62 trackedWords = trackedWords :+ s 63 }) 64 65 logger.info( 66 s"Launching streaming session with tracked keywords: $trackedWords\r\n" + 67 s"And with tracked Users: $trackedUsers" 68 ) 69 70 streamingClient.filterStatuses(tracks = trackedWords, follow = trackedUsers) { 71 case tweet: Tweet => 72 println("=============") 73 logger.info("Found a new Tweet... Saving...") 74 logger.debug(tweet.text) 75 this.saveIDforLater(tweet) 76 logger.debug("Done Saving") 77 println("=============") 78 case disconnect: DisconnectMessage => 79 logger.warn("Disconnect: ", disconnect.disconnect) 80 case limit: LimitNotice => 81 logger.warn("Limit: ", limit) 82 case warning: WarningMessage => 83 logger.warn("Warning: ", warning.warning) 84 case default => 85 logger.debug(default.toString) 86 } 87 } 88 89 /** 90 * saveIDforLater saves the tweetID and indexing Date to a csv as soon as the Tweet gets published 91 * 92 * @todo implement 93 * @param tweet holds the currently processed Tweet 94 */ 95 private def saveIDforLater(tweet: Tweet): Unit = { 96 val currentDate = 97 new Date(DateTime.now(DateTimeZone.UTC).getMillis) 98 val today = new SimpleDateFormat("dd_MM_yyyy").format(currentDate) 99 val dir = new File("data/") 100 if (!dir.exists()) { 101 dir.mkdir() 102 } 103 val todaysTweets = new File(s"data/tweets.$today") 104 if (!todaysTweets.exists()) { 105 todaysTweets.createNewFile() 106 } 107 val writer = CSVWriter.open(todaysTweets, append = true) 108 writer.writeRow(List(tweet.id_str, currentDate.toString)) 109 110 writer.close() 111 } 112 113 /** 114 * getListUsers is used to ask the Twitter API about what users are in a List 115 * 116 * Uses the Twitter Rest API 117 * 118 * @param trackedLists holds the list slugs and corresponding Users for all tracked lists 119 * @return 120 */ 121 private def getListUsers(trackedLists: List[String]): Future[Seq[Long]] = { 122 Future { 123 var trackedUsers: Seq[Long] = Seq() 124 trackedLists.foreach((v: String) => { 125 val splitted = v.split("/") 126 val username = splitted(0) 127 val slug = splitted(1) 128 129 var listUsers = Await.result( 130 restClient.listMembersBySlugAndOwnerName( 131 slug = slug, 132 owner_screen_name = username, 133 include_entities = false 134 ), 135 scala.concurrent.duration.Duration.Inf 136 ) 137 listUsers.data.users.foreach((user: User) => { 138 trackedUsers = trackedUsers :+ user.id 139 }) 140 while (listUsers.data.next_cursor != listUsers.data.previous_cursor) { 141 listUsers = Await.result( 142 restClient.listMembersBySlugAndOwnerName( 143 slug = slug, 144 owner_screen_name = username, 145 include_entities = false, 146 cursor = listUsers.data.next_cursor 147 ), 148 scala.concurrent.duration.Duration.Inf 149 ) 150 listUsers.data.users.foreach((user: User) => { 151 trackedUsers = trackedUsers :+ user.id 152 }) 153 } 154 155 }) 156 trackedUsers 157 } 158 } 159 }