LinqToTwitter 列出指定日期以来的 DM

Posted

技术标签:

【中文标题】LinqToTwitter 列出指定日期以来的 DM【英文标题】:LinqToTwitter List DMs since a specified date 【发布时间】:2021-05-13 06:54:27 【问题描述】:

是否可以在指定日期之后列出私信?如果我有大量直接消息,如果我必须翻阅许多结果,我会很快达到速率限制。我想跟踪我上次查询 DirectMessageEventsType.List 的时间,并将下一次查询限制为仅在该日期之后发送/接收的消息。

【问题讨论】:

【参考方案1】:

您可能已经知道,Twitter API 中用于列出 DM 的唯一参数是 countcursor。也就是说,这里有一个可能很方便的解决方法。它涉及在 LINQ to Twitter 查询之后的 LINQ to Objects 查询:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using LinqToTwitter;
using LinqToTwitter.OAuth;
using System.Diagnostics;

namespace TwitterDMListDate

    class Program
    
        static async Task Main()
        
            TwitterContext twitterCtx = await GetTwitterContext();

            int count = 50; // set to a low number to demo paging
            string cursor = "";
            List<DMEvent> allDmEvents = new();

            bool isPastCreatedAt = false;
            DateTime lastCreatedAt = DateTime.UtcNow.AddHours(-1);

            // you don't have a valid cursor until after the first query
            DirectMessageEvents dmResponse =
                await
                    (from dm in twitterCtx.DirectMessageEvents
                     where dm.Type == DirectMessageEventsType.List &&
                           dm.Count == count
                     select dm)
                    .SingleOrDefaultAsync();

            isPastCreatedAt = CheckPastCreatedAt(dmResponse, lastCreatedAt);

            allDmEvents.AddRange(dmResponse?.Value?.DMEvents ?? new List<DMEvent>());
            cursor = dmResponse?.Value?.NextCursor ?? "";

            while (!string.IsNullOrWhiteSpace(cursor) && !isPastCreatedAt)
            
                dmResponse =
                    await
                        (from dm in twitterCtx.DirectMessageEvents
                         where dm.Type == DirectMessageEventsType.List &&
                               dm.Count == count &&
                               dm.Cursor == cursor
                         select dm)
                        .SingleOrDefaultAsync();

                allDmEvents.AddRange(dmResponse?.Value?.DMEvents ?? new List<DMEvent>());
                cursor = dmResponse?.Value?.NextCursor ?? "";

                isPastCreatedAt = CheckPastCreatedAt(dmResponse, lastCreatedAt);
            

            if (!allDmEvents.Any())
            
                Console.WriteLine("No items returned");
                return;
            

            Console.WriteLine($"Response Count: allDmEvents.Count");
            Console.WriteLine("Responses:");

            allDmEvents.ForEach(evt =>
            
                DirectMessageCreate? msgCreate = evt.MessageCreate;

                if (evt != null && msgCreate != null)
                    Console.WriteLine(
                        $"DM ID: evt.ID\n" +
                        $"From ID: msgCreate.SenderID ?? "None"\n" +
                        $"To ID:  msgCreate.Target?.RecipientID ?? "None"\n" +
                        $"Message Text: msgCreate.MessageData?.Text ?? "None"\n");
            );
        

        static bool CheckPastCreatedAt(DirectMessageEvents dmResponse, DateTime lastCreatedAt)
        
            return
                (from dm in dmResponse.Value.DMEvents
                 where dm.CreatedAt <= lastCreatedAt
                 select dm)
                .Any();
        

        static async Task<TwitterContext> GetTwitterContext()
        
            var auth = new PinAuthorizer()
            
                CredentialStore = new InMemoryCredentialStore
                
                    ConsumerKey = "",
                    ConsumerSecret = ""
                ,
                GoToTwitterAuthorization = pageLink =>
                
                    var psi = new ProcessStartInfo
                    
                        FileName = pageLink,
                        UseShellExecute = true
                    ;
                    Process.Start(psi);
                ,
                GetPin = () =>
                
                    Console.WriteLine(
                        "\nAfter authorizing this application, Twitter " +
                        "will give you a 7-digit PIN Number.\n");
                    Console.Write("Enter the PIN number here: ");
                    return Console.ReadLine() ?? string.Empty;
                
            ;

            await auth.AuthorizeAsync();

            var twitterCtx = new TwitterContext(auth);
            return twitterCtx;
        
    

实现这项工作的两个变量是isPastCreatedAtlastCreatedAtisPastCreatedAt 标记一组 DM(来自大小为 count 的查询)包含一个或多个早于某个日期的 DM 的条件。符合isPastCreatedAt 条件的日期是lastCreatedAt。本质上,一旦我们的推文早于lastCreatedAt,我们就不想继续查询,因为后续查询保证返回所有早于lastCreatedAt 的推文。

演示将lastCreatedAt 设置为提前一小时。请注意,它使用的是 UTC 时间,因为那是 Twitter 使用的时间。在您的应用程序中,您应该跟踪这个时间,将其重新设置为自上一组查询以来收到的最旧推文的CreatedAt 属性。

在每次 LINQ to Twitter 查询 DM 之后,都会调用 CheckPastCreatedAt。这是设置isPastCreatedAt 的地方。该方法的内部是一个 LINQ to Objects 查询。它查询 LINQ to Twitter 刚刚返回的 DM 列表,检查是否有任何 DM 包含早于lastCreatedAt 日期的日期。它使用CreatedAt 属性,顾名思义,这就是在此演示中命名变量和方法的原因,以确保查询不会过度浪费速率限制。它还使用了Any 运算符,比Count 高效得多,但我跑题了。

请注意,Main 中的 while 语句为您可能用于遍历游标的内容添加了一个附加条件:&amp;&amp; !isPastCreatedAt。这就是防止你走得太远和浪费速率限制的原因。

完成此操作后,您只需要再做一件事 - 过滤掉您已经收到的 DM 以避免重复。但是,我的直觉是你已经知道了。

虽然这不是您可能希望的答案,但它确实为使用 Twitter API 的任何人概述了一个重要的模式,无论是 LINQ to Twitter 还是任何其他优秀的库。也就是说,使用 Twitter API 为您提供的内容进行查询,然后在本地过滤结果。虽然其他一些库提供了有时感觉很有帮助的额外抽象,但 LINQ to Twitter 采用更原始的方法来更接近 Twitter API 本身。因为在这种情况下,最好直观地了解发生了什么问题,这样您就可以推断出满足您需求的其他解决方案。

【讨论】:

感谢您的详尽回复!我现在会深入研究。

以上是关于LinqToTwitter 列出指定日期以来的 DM的主要内容,如果未能解决你的问题,请参考以下文章

用python 列出指定目录下所有的txt文件,并输出每个文件的创建日期和大小

linux 基本命令

sql怎样列出一个月的全部日期

时间差函数列出两个时间内的所有日期

我很难从一年中的某一天和自午夜以来的秒数获取日期/时间组件

js获取当前指定的前几天的日期(如当前时间的前七天的日期)