scala使用log4j
介绍
我以前的文章展示了如何在Scala中使用Twitter4j访问Twitter流 。 这篇文章展示了如何使用Twitter4j控制Twitter用户的操作。 此功能的主要目的可能是为Twitter创建界面(例如TweetDeck),但也可以用于创建在Twitter上执行自动操作的机器人(我正在使用的一个机器人是@tshrdlu ,使用本教程中的代码以及tshrdlu信息库中的代码)。 这篇文章只涵盖了您可以做的一小部分,但是它们是一些更常见的事情,我提供了一些简单但有趣的用例。 一旦具备了这些功能,就可以很容易地弄清楚如何使用Twitter4j API文档 (和Stack Overflow)来完成其余的工作。
设置:代码和授权
我没有在阅读本教程的过程中让读者构建代码,而是在存储库twitter4j-tutorial中设置了代码。 本教程所需的版本为v0.2.0。 您可以下载该版本的tarball,如果自编写本教程以来对该存储库进行了进一步的开发,则可能更易于使用。 立即签出或下载该代码。 感兴趣的主要文件是:
- src / main / scala / TwitterUser.scala
本教程主要是通过博客形式对该文件进行逐步介绍,并在此处和此处提供了一些其他的指针和说明。 您还需要设置授权详细信息。 见节“授权设置” 上一篇文章中这样做,如果你还没有准备好。
重要说明:对于本教程,您必须将应用程序的权限设置为“ 读写 ”。
在上一教程中,授权详细信息已放入代码中。 这次,我们将使用twitter4j.properties文件。 这很容易:只需将具有该名称的文件添加到twitter4j-tutorial目录中,其中包含以下内容,并根据需要替换您的详细信息。
oauth.consumerKey=[your consumer key here]
oauth.consumerSecret=[your consumer secret here]
oauth.accessToken=[your access token here]
oauth.accessTokenSecret=[your access token secret here]
速率限制和注意事项
与对Twitter的流式访问不同,通过API执行用户操作受速率限制。 一旦达到极限,Twitter将抛出异常并拒绝遵守您的请求,直到一段时间(通常为15分钟)过去。 Twitter这样做是为了限制不良机器人并保留其计算资源。 有关限速的更多信息,请参阅Twitter的限速页面。
我将在后面的文章中讨论如何管理速率限制,但是我会提前提到它们,以防万一您在处理早期事情时超出了它们。
还要注意一点:由于您将能够自动执行操作,例如关注用户,发布状态和转推,因此您最终可能会快速连续执行许多这些操作。 这将(a)很快用完您的速率限制,(b)可能不是有趣的行为,并且(c)可能会导致您的帐户被暂停。 确保遵循规则,尤其是遵循用户规则。
如果您打算在实际发布中花很多时间,您可能还想考虑创建一个不是您的主要Twitter帐户的帐户,以免惹恼您的实际关注者。 (建议:有关如何添加具有相同gmail地址的多个帐户的提示,请参阅我的“应用NLP”课程的第一阶段项目的第一阶段中 “创建帐户”的段落。)
基本互动:搜索,时间表,发布
下面的所有示例均通过使用twitter4j.Twitter对象执行某些操作的主要方法实现为对象。 为了做到这一点,我们不必重复调用TwitterFactory ,我们首先定义一个特征,该特征可以设置Twitter实例并准备使用。
trait TwitterInstance {
val twitter = new TwitterFactory().getInstance
}
通过扩展此特征,我们的对象可以方便地访问twitter对象。
作为第一个简单的示例,我们可以使用搜索方法搜索与查询匹配的推文。 以下对象采用命令行查询中给出的查询字符串,使用该查询搜索推文,然后打印它们。
object QuerySearch extends TwitterInstance {
def main(args: Array[String]) {
val statuses = twitter.search(new Query(args(0))).getTweets
statuses.foreach(status => println(status.getText + '\n'))
}
}
请注意,这使用Query对象,而使用TwitterStream则需要FilterQuery 。 另外,为使此工作正常,我们必须具有以下导入功能:
import collection.JavaConversions._
这确保了我们可以使用由twitter4j.QueryResult的getTweets方法返回的java.util.List ,就好像它是具有foreach方法(以及地图,过滤器等)的Scala集合一样。 这是通过隐式转换完成的,与Java库相比,隐式转换使Java库的使用变得更好。
要运行此命令,请转到twitter4j-tutorial目录,然后执行以下操作(显示一些示例输出):
$ ./build
> run-main bcomposes.twitter.QuerySearch scala
[info] Running bcomposes.twitter.QuerySearch scala
E' avvilente non sentirsi all'altezza di qualcosa o qualcuno, se non si possiede quella scala interiore sulla quale l'autostima pu? issarsi
Scala workshop will run with ECOOP, July 2nd in Montpellier, South of France. Call for papers is out. http://t.co/3WS6tHQyiF
#scala http://t.co/JwNrzXTwm8 Even two of them in #cologne #germany . #thumbsup
RT @MILLIB2DAL: @djcameo Birthday bash 30th march @ Scala nightclub 100 artists including myself make sur u reach its gonna be #Legendary
@kot_2010 I think it's the same case with Scala: with macros it will tend to 'outsource' things to macro libs, keeping a small lang core.
RT @waxzce: #scala hiring or job ? go there : http://t.co/NeEjoqwqwT
@esten That's not only a front-end problem. Scala devs should use scalaz.Equal and === for type safe equality. /cc @sharonw
<...more...>
[success] Total time: 1 s, completed Feb 26, 2013 1:54:44 PM
您可能会看到来自SBT的一些额外通讯,可能需要下载依赖项并编译代码。 对于下面的其余示例,您可以以类似的方式运行它们,替换正确的对象名称并提供任何必要的参数。
每个用户可以使用各种时间线,包括主时间线,提及时间线和用户时间线。 可通过twitter4j.api.TimelineResources访问它们。 例如,以下对象显示了身份验证用户的家庭时间轴上的最新状态(这是用户关注的人的推文)。
object GetHomeTimeline extends TwitterInstance {
def main(args: Array[String]) {
val num = if (args.length == 1) args(0).toInt else 10
val statuses = twitter.getHomeTimeline.take(num)
statuses.foreach(status => println(status.getText + '\n'))
}
}
要显示的推文数量作为命令行参数给出。
您还可以使用以下对象从命令行更新身份验证用户的状态。 调用它将发布到验证用户的帐户中(因此,只有在您熟悉将其传递到时间轴上的命令行参数时才执行此操作)。
object UpdateStatus extends TwitterInstance {
def main(args: Array[String]) {
twitter.updateStatus(new StatusUpdate(args(0)))
}
}
您可以使用许多其他有用的方法与Twitter进行交互,并且如果您成功运行了上述三种方法,则应该能够查看Twitter4j javadocs并开始使用它们。 下面给出了一些做一些更有趣的事情的示例。
回复写给您的推文
以下对象通过了提及身份验证用户的最新推文,并答复“确定”。 给他们。 它包括原始tweet的作者以及其中提到的任何其他实体。
object ReplyOK extends TwitterInstance {
def main(args: Array[String]) {
val num = if (args.length == 1) args(0).toInt else 10
val userName = twitter.getScreenName
val statuses = twitter.getMentionsTimeline.take(num)
statuses.foreach { status => {
val statusAuthor = status.getUser.getScreenName
val mentionedEntities = status.getUserMentionEntities.map(_.getScreenName).toList
val participants = (statusAuthor :: mentionedEntities).toSet - userName
val text = participants.map(p=>'@'+p).mkString(' ') + ' OK.'
val reply = new StatusUpdate(text).inReplyToStatusId(status.getId)
println('Replying: ' + text)
twitter.updateStatus(reply)
}}
}
}
这应该是不言而喻的,但是有两点需要注意。 首先,您可以通过twitter4j.Status类的getUserMentionEntities方法在推文中找到所有已提及的实体(通过@ -mentions)。 该代码确保原始推文的作者(不一定在其中提到)被包括为响应的参与者,并且我们还删除了进行身份验证的用户。 因此,如果消息“ @tshrdlu,您如何看待@tshrdlc? 是从@jasonbaldridge发送的,响应将是“ @jasonbaldridge @tshrdlc好。 ”请注意,屏幕名称如何没有@符号,因此必须在回复的推文中添加该名称。
其次,请注意,可以通过向其添加更多信息的链接方法来创建StatusUpdate对象,例如setInReplyToStatusId和setLocation ,它们可以逐步构建实际发布的StatusUpdate对象。 (这是一种常见的Java策略,基本上可以避免这样的事实:类的参数既不能用Java中的名称指定,也不能像Scala那样具有默认值。)
查看和管理限速信息
以上代码均未从Twitter发出许多请求,因此几乎没有超出速率限制的危险。 这些限制是时间和请求数量的混合:基本上每个认证用户每小时都会收到一定数量的请求(当前为350个)。 由于存在这些限制,您应该考虑在可能的情况下使用流方法来访问tweet,时间轴等。
从Twitter获得的每个响应都作为twitter4j.TwitterResponse的子类返回,它不仅为您提供所需的内容(如QueryResult ),而且还提供有关与Twitter的连接的信息。 有关速率限制的信息,可以使用getRateLimitStatus方法,该方法随后可以通知您仍然可以发出的请求数量以及重置限制之前的时间。
下面的特征RateChecker具有一个checkAndWait函数,当给它一个TwitterResponse对象时,它检查是否已超过速率限制,然后等待是否已达到。 当超过该速率时,它将找出剩余的时间,直到重置速率限制为止,并使线程进入睡眠状态,直到经过该时间(加上10秒)为止。
trait RateChecker {
def checkAndWait(response: TwitterResponse, verbose: Boolean = false) {
val rateLimitStatus = response.getRateLimitStatus
if (verbose) println('RLS: ' + rateLimitStatus)
if (rateLimitStatus != null && rateLimitStatus.getRemaining == 0) {
println('*** You hit your rate limit. ***')
val waitTime = rateLimitStatus.getSecondsUntilReset + 10
println('Waiting ' + waitTime + ' seconds ( ' + waitTime/60.0 + ' minutes) for rate limit reset.')
Thread.sleep(waitTime*1000)
}
}
}
使用速率限制实际上比这更复杂。 例如,该策略忽略了以下事实:不同的请求类型具有不同的限制,但它使事情变得简单。 这肯定不是最佳解决方案,但可以解决目前的问题。
还要注意,您可以使用getRateLimitStatus方法直接从twitter4j.Twitter实例本身请求速率限制信息。 与TwitterResponse上相同方法的结果不同,这提供了从各种请求类型到每个请求的当前速率限制状态的映射 。 在实际的应用程序中,您希望使用此信息在更细粒度的级别上控制这些不同的限制。
并非所有Twitter4j类的方法实际上都可以使用Twitter API。 要查看给定的方法是否有效,请查看其Javadoc:如果描述中显示“ 此方法调用http://api.twitter.com/1.1/some/method.json ”,那么它确实可以访问该API。 否则,它就不会,并且您也不需要保护它。
下面给出了使用checkAndWait函数的示例。
从追随者的描述创建词云
这是一个更有趣的任务:给一个Twitter用户,计算其追随者的简历中给出的描述中的单词数,并从中建立一个单词云。 以下代码执行此操作,将结果计数输出到一个文件中,该文件的内容可以粘贴到Wordle的高级词云输入中 。
object DescribeFollowers extends TwitterInstance with RateChecker {
def main(args: Array[String]) {
val screenName = args(0)
val maxUsers = if (args.length==2) args(1).toInt else 500
val followerIds = twitter.getFollowersIDs(screenName,-1).getIDs
val descriptions = followerIds.take(maxUsers).flatMap { id => {
val user = twitter.showUser(id)
checkAndWait(user)
if (user.isProtected) None else Some(user.getDescription)
}}
val tword = '''(?i)[a-z#@]+'''.r.pattern
val words = descriptions.flatMap(_.toLowerCase.split('\\s+'))
val filtered = words.filter(_.length > 3).filter(tword.matcher(_).matches)
val counts = filtered.groupBy(x=>x).mapValues(_.length)
val rankedCounts = counts.toSeq.sortBy(- _._2)
import java.io._
val wordcountFile = '/tmp/follower_wordcount.txt'
val writer = new BufferedWriter(new FileWriter(wordcountFile))
for ((w,c) <- rankedCounts)
writer.write(w+':'+c+'\n')
writer.flush
writer.close
}
}
要考虑的事情是,如果将此对象指向具有数百名关注者的人,则您将超出速率限制。 对getFollowersID的调用是单个匹配 ,然后对showUser的每个调用都是匹配 。 因为showUser调用是快速连续的,所以我们使用checkAndWait检查每个端口的速率限制状态(由于我们混入了RateChecker特性,因此可以使用该速率),并且它等待该限制重新设置,如前所述,以防止超出速率限制并从Twitter获得例外。
getFollowersID返回的用户数最多为5000。如果在具有更多关注者的用户上运行此用户,则不会考虑超过5000的关注者。 如果要处理这样的用户,则需要使用游标(这是作为getFollowersID的参数提供的整数),并在递增该游标以获取更多信息时进行多次调用。
其余大多数代码只是用于获取单词计数并将其输出到文件的标准Scala内容。 请注意,已做了一些努力来减少非字母字符(但允许使用#和@)并过滤掉短单词。
作为输出的示例,当将其放入Wordle时,这是我的关注者的词云。
这对我来说是正确的,实际上是完全可以预期的,但是从我的追随者的自我描述中得出的结论仍然很酷。 人们可能会开始思考一些有趣的算法,以利用用户的这种表示形式来调查不同用户与他们的关注者的对齐或不匹配程度,或者寻找不同类型关注者的集群等。
自动转发
厌倦了在时间轴上实际阅读这些推文并转发其中一些推文? 以下代码获取身份验证用户所遵循的一些帐户,抓取其中的20个用户,对其进行过滤以获取有趣的帐户,然后最多提取10个其余的帐户并转发其最新状态(前提是他们未回复)其他人)。
object RetweetFriends extends TwitterInstance with RateChecker {
def main(args: Array[String]) {
val friendIds = twitter.getFriendsIDs(-1).getIDs
val friends = friendIds.take(20).map { id => {
val user = twitter.showUser(id)
checkAndWait(user)
user
}}
val filtered = friends.filter(admissable)
val ranked = filtered.map(f => (f.getFollowersCount, f)).sortBy(- _._1).map(_._2)
ranked.take(10).foreach { friend => {
val status = friend.getStatus
if (status!=null && status.getInReplyToStatusId == -1) {
println('\nRetweeting ' + friend.getName + ':\n' + status.getText)
twitter.retweetStatus(status.getId)
Thread.sleep(30000)
}
}}
}
def admissable(user: User) = {
val ratio = user.getFollowersCount.toDouble/user.getFriendsCount
user.getFriendsCount < 1000 && ratio > 0.5
}
}
getFriendsIDs方法用于获取身份验证用户正在关注的用户(但尽管使用了“朋友”一词,但不一定跟随身份验证用户)。 我们再次注意收集用户的速率限制。 我们过滤这些用户,寻找那些关注少于1000个用户的用户以及关注者/朋友比率大于.5的用户,从而轻松地过滤掉一些不太有趣(或垃圾邮件)的帐户。 然后,根据剩余的关注者人数(排名第一)对其余用户进行排名。 最后,我们接受(最多)其中的10个(如果您要求10个,但是只有3个,则take方法返回3个东西),查看它们的最新状态,如果它不是null且不是对有人,我们转发。 在这两种方法之间,我们要等待30秒,以便关注我们帐户的任何人都不会收到大量的转发。
结论
这篇文章和相关代码应该足以提供使用Twitter4j的良好感觉,包括必要的设置以及使用某些方法来开始在Scala中使用它创建应用程序。 请参阅我的Applied NLP课程的项目阶段三 ,以查看练习和代码,以进一步利用这些内容和代码为自动化的bot做有趣的事情,包括混合流访问和用户访问以获得更复杂的行为。
参考:在Bcomposes博客上, 将Twitter4j与Scala结合使用来执行 JCG合作伙伴 Jason Baldridge的 用户操作 。
翻译自: https://www.javacodegeeks.com/2013/02/using-twitter4j-with-scala-to-perform-user-actions.html
scala使用log4j