【问题标题】:twitter4j since id not getting updatedtwitter4j 因为 id 没有得到更新
【发布时间】:2016-11-24 09:28:33
【问题描述】:

我正在尝试使用 since_id 来获取使用 twitter 搜索 api 的推文。下面是我的代码,这里我正在创建一个查询对象的映射,并且因为 id.我将自 id 默认为 0,我的目标是每次运行查询时更新自 id。这样当我下次运行查询时,它不会得到相同的推文,应该从最后一条推文开始。

import java.io.{PrintWriter, StringWriter}
import java.util.Properties
import com.google.common.io.Resources
import twitter4j._
import scala.collection.JavaConversions._
// reference: http://bcomposes.com/2013/02/09/using-twitter4j-with-scala-to-access-streaming-tweets/
object Util {
    val props = Resources.getResource("twitter4j.props").openStream()
    val properties = new Properties()
    properties.load(props)

    val config = new twitter4j.conf.ConfigurationBuilder()
        .setDebugEnabled(properties.getProperty("debug").toBoolean)
        .setOAuthConsumerKey(properties.getProperty("consumerKey"))
        .setOAuthConsumerSecret(properties.getProperty("consumerSecret"))
        .setOAuthAccessToken(properties.getProperty("accessToken"))
        .setOAuthAccessTokenSecret(properties.getProperty("accessTokenSecret"))
    val tempKeys =List("Yahoo","Bloomberg","Messi", "JPM Chase","Facebook")
    val sinceIDmap : scala.collection.mutable.Map[String, Long] = collection.mutable.Map(tempKeys map { ix => s"$ix" -> 0.toLong } : _*)
    //val tweetsMap: scala.collection.mutable.Map[String, String]
    val configBuild = (config.build())
    val MAX_TWEET=100
    getTweets()

    def getTweets(): Unit ={
        sinceIDmap.keys.foreach((TickerId) => getTweets(TickerId))
    }

    def getTweets(TickerId: String): scala.collection.mutable.Map[String, scala.collection.mutable.Buffer[String]] = {
        println("Search key is:"+TickerId)
        var tweets = scala.collection.mutable.Map[String, scala.collection.mutable.Buffer[String]]()
        try {
            val twitter: Twitter = new TwitterFactory(configBuild).getInstance
            val query = new Query(TickerId)
            query.setSinceId(sinceIDmap.get(TickerId).get)
            query.setLang("en")
            query.setCount(MAX_TWEET)
            val result = twitter.search(query)
            tweets += ( TickerId -> result.getTweets().map(_.getText))

            //sinceIDmap(TickerId)=result.getSinceId
            println("-----------Since id is :"+result.getSinceId )
            //println(tweets)
        }
        catch {
            case te: TwitterException =>
                println("Failed to search tweets: " + te.getMessage)
        }
        tweets
    }
}

object StatusStreamer {
    def main(args: Array[String]) {
        Util
    }
}

输出:

Search key is:Yahoo    
log4j:WARN No appenders could be found for logger (twitter4j.HttpClientImpl).
log4j:WARN Please initialize the log4j system properly.
-----------Since id is :0
Search key is:JPM Chase
-----------Since id is :0
Search key is:Facebook
-----------Since id is :0
Search key is:Bloomberg
-----------Since id is :0
Search key is:Messi
-----------Since id is :0

问题是当我在运行查询后尝试打印自 id 时,它给出的值与我最初设置的值相同。有人可以指出我在这里做错了什么吗?或者如果我的方法是错误的,如果有人知道可以在这里工作,可以分享任何其他方法。

谢谢

【问题讨论】:

    标签: scala twitter twitter4j


    【解决方案1】:

    首先,从您的方法的初始描述中,我可以告诉您,您使用since_id 的方法是不正确的。我过去犯过同样的错误,无法让它发挥作用。此外,您的做法不符合官方Working with Timelines。当时的官​​方指南对我有用,我建议你遵循它们。长话短说,您不能单独使用 since_id 来浏览推文时间线(在您的情况下,GET search / tweets 返回的时间线)。你肯定需要max_id 来做你描述的事情。而且,实际上,我相信since_id 具有完全次要/可选的功能(也可以在您的代码中实现)。 API docs 让我相信我可以像使用 max_id 一样使用 since_id,但我错了。只指定since_id,我注意到返回的推文非常新鲜,好像since_id 被完全忽略了。 Here 是另一个证明这种意外行为的问题。如我所见,since_id 仅用于修剪,而不用于在时间轴上移动。单独使用since_id 将获得最新/最新的推文,但将返回的推文限制为ID 大于since_id 的推文。不是你想要的。取自官方指南的最后一条证据是特定请求的图形表示:

    since_id 不仅不会让你通过时间线,而且它恰好在这个特定的请求中完全没用。不过,它不会在下一个请求中无用,因为它会修剪 Tweet 10(以及之前的任何内容)。但事实是since_id 不会让你穿越时间线。

    一般来说,您需要考虑从最新的推文到最旧的推文,而不是相反。要从最新推文转到最旧推文,您需要在请求中指定 max_id 作为要返回的推文的 ID(包括 ID)上限,并在连续请求之间更新此参数。

    max_id 在请求中的存在将为要返回的推文设置包含 ID 在内的上限。从返回的推文中,您可以获得出现的最小 ID,并将其用作后续请求中 max_id 的值(您可以将最小 ID 减一并将此值用于下一个请求的 max_id,因为 @987654346 @ 是包容性的,这样您就不会再次从上一个请求中获得最旧的推文)。第一个请求应该没有指定max_id,以便返回最新/最新的推文。使用这种方法,第一个请求之后的每个请求都会让您更深入地了解过去。

    since_id 可以在您需要限制过去的旅行时派上用场。想象一下,在某个时间点,t0,您开始搜索推文。让我们假设从您的第一次搜索开始,您最大的推文 ID 是 id0。在第一次搜索之后,后续搜索中的所有推文 ID 都会变小,因为您要返回。一段时间后,您将获得大约一周的推文,而搜索您的推文将一无所获。在那个时间点,t1,你知道这趟过去的旅程已经结束了。但是,在t0t1 之间将会发布更多推文。所以,另一个过去的旅行应该从t1开始,直到你到达ID为id0的推文(在t0之前发布过推文)。此行程可以通过在行程请求中使用id0 来限制since_id,依此类推。或者,可以避免使用since_id,如果您确保在收到 ID 小于或等于id0 的推文时结束您的旅行(请记住,推文可以被删除) .但我建议您尝试使用since_id 以方便和高效。请记住,since_id 是独占的,而 max_id 是包容的。

    更多信息请见官方Working with Timelines。您会注意到“max_id 参数”部分先出现,“使用 since_id 获得最大效率”部分在后。后一部分的标题表明since_id 不是用于在时间轴中移动。

    一个粗略的未经测试的示例,使用 Java 中的 Twitter4J,打印从最新开始到过去的推文,如下所示:

    // Make sure this is initialized correctly.
    Twitter twitter;
    
    /**
     * Searches and prints tweets starting from now and going back to the past.
     * 
     * @param q
     *            the search query, e.g. "#yolo"
     */
    private void searchAndPrintTweets(String q) throws TwitterException {
        // `max_id` needed by `GET search/tweets`. If it is 0 (first iteration),
        // it will not be used for the query.
        long maxId = 0;
        // Let us assume that it will run forever.
        while (true) {
            Query query = new Query();
            query.setCount(100);
            query.setLang("en");
            // Set `max_id` as an inclusive upper limit, unless this is the
            // first iteration. If this is the first iteration (maxId == 0), the
            // freshest/latest tweets will come.
            if (maxId != 0)
                query.setMaxId(maxId);
            QueryResult qr = twitter.search(query);
            printTweets(qr.getTweets());
            // For next iteration. Decrement smallest ID by 1, so that we will
            // not get the oldest tweet of this iteration in the next iteration
            // as well, since `max_id` is inclusive.
            maxId = calculateSmallestId(qr.getTweets()) - 1;
        }
    }
    
    /**
     * Calculates the smallest ID among a list of tweets.
     * 
     * @param tweets
     *            the list of tweets
     * @return the smallest ID
     */
    private long calculateSmallestId(List<Status> tweets) {
        long smallestId = Long.MAX_VALUE;
        for (Status tweet : tweets) {
            if (tweet.getId() < smallestId)
                smallestId = tweet.getId();
        }
        return smallestId;
    }
    
    /**
     * Prints the content of the tweets.
     * 
     * @param tweets
     *            the tweets
     */
    private void printTweets(List<Status> tweets) {
        for (Status tweet : tweets) {
            System.out.println(tweet.getText());
        }
    }
    

    没有错误处理,没有特殊条件检查(例如查询结果中的推文列表为空),也没有使用since_id,但它应该让你开始。

    【讨论】:

    • 您好 xnakos 感谢您的回复,您有上述概念的任何工作示例吗?
    • @Novice 你会关心使用 twitter4j 的 Java 示例吗?
    • @Novice 添加了 Twitter4J/Java 示例,虽然未经测试,但它应该或多或少地工作。
    • 感谢@xnakos 的描述性回复。我会试一试的。
    • @Novice 玩得开心! ;)
    【解决方案2】:

    Twitter API 返回最初由查询请求的 since_id 值。这意味着QueryResult.getSinceId 与您输入的Query 相同。

    最简单的解决方案是将 next sinceId 设置为响应中的最大推文 ID。

    sinceIDmap(TickerId) = result.getTweets().max(Ordering.by(_.getId)).getId
    

    一般来说,为了使结果更流畅,您可以使用since_idmax_id 查询参数的组合。 Official twitter guide 有很好的解释如何使用它们。

    【讨论】:

    • 感谢 Nazarii 的解释,所以如果我使用 val id = QResult.getTweets.max.getId 并将这个 id 设置为下一次迭代的自 id,它会工作吗? query.setSinceId(id)
    • 如果它的行为符合您的预期,您应该尝试一下。至少它将是since_id 的新值,因此搜索结果会更准确。无论如何,请阅读指南以获取您需要的确切内容dev.twitter.com/rest/public/timelines
    【解决方案3】:

    粗略查看您的代码,您似乎从未更新sinceIDmap 中的值。您已注释掉以下内容:

    //sinceIDmap(TickerId)=result.getSinceId
    

    因此,对于每个关键字,since_id 永远不会从 0 更新。

    如果您还有其他问题,可能值得研究一下 GitHub 上的 Twitter4J SearchTweets 示例。

    【讨论】:

    • 嗨乔纳森,感谢您的回复,我注释掉了该行,因为我只是想打印结果,并且我检查了它没有引用 since_id 和 max_id 的示例。
    【解决方案4】:

    since_id 和 max_id 都是非常简单的参数,您可以使用它们来限制从 API 中返回的内容。来自文档:

    since_id - 返回 ID 大于(即更新)指定 ID 的结果。可以通过 API 访问的推文数量是有限制的。如果自 since_id 以来已发生 Tweets 限制,则 since_id 将被强制为可用的最旧 ID。 max_id - 返回 ID 小于(即早于)或等于指定 ID 的结果。 因此,如果您有给定的推文 ID,则可以使用这两个参数搜索较旧或较新的推文。

    count 更简单——它指定了您想要返回的最大推文数,最多 200 条。

    不幸的是,API 不会准确地返回您想要的内容 - 您无法在查询 user_timeline 时指定日期/时间 - 尽管您可以在使用搜索 API 时指定日期/时间。无论如何,如果您需要使用 user_timeline,那么您将需要轮询 API,收集推文,确定它们是否符合您想要的参数,然后相应地计算您的统计数据。

    【讨论】:

      猜你喜欢
      • 2013-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-12
      • 2021-04-10
      • 2016-01-16
      • 1970-01-01
      相关资源
      最近更新 更多