c# - 列出朋友 - 在过程中遇到身份验证失败

c# - Listing Friends -- Hitting auth failure mid-process

所以,我正在尝试向某人所有关注者的朋友求助。不是递归挖掘,就是那个单层。

我能够很好地吸引追随者(看起来它可以处理超过 75k 的追随者,所以我 90% 确定我的速率限制很好)。

但是我拉朋友的代码在 returns 15 个关注朋友之后抛出身份验证错误。

换句话说,在这段代码中:

for (var i = 0; i < followerList.Count; i++)
{
  await followersFriends(followerList[i]);
}

我在 i == 15 时收到此错误:

LinqToTwitter.TwitterQueryException HResult=0x80131500 Message={"request":"/1.1/friends/ids.json","error":"Not authorized."} - Please visit the LINQ to Twitter FAQ (at the HelpLink) for help on resolving this error.

它似乎完全获得了 15 个列表,它是第 16 个抛出它的。我感觉这不是巧合,它与速率限制相同,尽管如果它是速率限制是一个奇怪的错误。

我会检查一下我们是否在 15 的倍数上,然后暂停 15 分钟,但是,如果这不起作用,有没有人有其他理论可以在这里进行吗?

ETA:我确实尝试在每个 运行 到 followersFriends 上重做我的身份验证(基于应用程序)。没有帮助。

预计到达时间 2:

这是新的调用代码:

for (var i = 0; i < followerList.Count; i++)
{
  if (i % 15 == 0 && i != 0) {
    Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - i = " + i + " and user = " + followerList[i]);
    PauseThatRefreshes("friends");
    RunMe();
  }

  await followersFriends(followerList[i]);
}

这里是被调用的代码:

private async Task followersFriends(ulong uid)
{
  var twitterCtx2 = new TwitterContext(m_foo);

  Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Start Friend Get for " + uid.ToString() + " ***");

  long cursor = -1;

  do
  {
    var friendList = await (from friend in twitterCtx2.Friendship where friend.Type == FriendshipType.FriendIDs && friend.UserID == uid.ToString() && friend.Cursor == cursor select friend).SingleOrDefaultAsync();

    if (twitterCtx2.RateLimitRemaining <= 2)
    {
      Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Pausing A ***");
      Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - Friends Rate Limit Remaining at Pause A: " +
        twitterCtx2.RateLimitRemaining.ToString());
      PauseThatRefreshes("friends");
    }

    if (friendList != null &&
      friendList.IDInfo != null &&
      friendList.IDInfo.IDs != null) {
      cursor = friendList.CursorMovement.Next;
      Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - Friends Rate Limit Remaining: " + twitterCtx2.RateLimitRemaining.ToString());
      friendList.IDInfo.IDs.ForEach(id => Output(uid.ToString(), id.ToString()));
    }

    if (twitterCtx2.RateLimitRemaining <= 2)
    {
      Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Pause B ***");
      Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - Friends Rate Limit Remaining at Pause B: " + twitterCtx2.RateLimitRemaining.ToString());
      PauseThatRefreshes("friends");
    }
  } while (cursor != 0);

  Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Stop Friend Get for " + uid.ToString() + " ***");
  Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - Friends Rate Limit Remaining at stop: " + twitterCtx2.RateLimitRemaining.ToString());

  return;
}

ETA 只是为了澄清,调用 followersFriends 的代码。是的,我知道,我没有更改我的按钮名称 =D 这更多是关于收集数据,我更喜欢表单而不是命令行...我不知道为什么。无论如何,不​​在这里也不在那里:

        private async void button2_Click(object sender, EventArgs e)
    {

        var twitterCtx = new TwitterContext(m_foo);
        string[] header = { "Account,Follows" };
        File.WriteAllLines(@"C:\temp\followersFriends.txt", header);

        //List to store ids of followers of main account
        List<ulong> followerList = new List<ulong>();
        // get main accounts followers and put into an array
        long cursor = -1;
        Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Start Follower Get ***");
        do
        {

            var followers =
    await
    (from follower in twitterCtx.Friendship
     where follower.Type == FriendshipType.FollowerIDs &&
           follower.ScreenName == "[[redacted]]" && 
           follower.Cursor == cursor
     select follower)
    .SingleOrDefaultAsync();
            if (followers != null &&
                followers.IDInfo != null &&
                followers.IDInfo.IDs != null
                &&
                followers.CursorMovement != null)
            {
                cursor = followers.CursorMovement.Next;
                followers.IDInfo.IDs.ForEach(id =>
                  followerList.Add(id));
            }

            if (twitterCtx.RateLimitRemaining <= 2)
                PauseThatRefreshes("followers");
        } while (cursor != 0);
        Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Done Follower Get ***");

        for (var i = 0; i < followerList.Count; i++)
        {
            if (i % 15 == 0 && i != 0)
            {
                Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - i = " + i 
                    + " and user = " + followerList[i]);
                PauseThatRefreshes("friends");
                RunMe();
            }
            await followersFriends(followerList[i]);
        }
    }

如您的注释所示,遇到 1963joeym 帐户时会抛出带有 "Not Authorized" 消息的 TwitterQueryException。检查此帐户,我可以看到他们已经保护了它。 "protected" 的概念意味着没有人可以看到一个人的帐户或相关 activity 除非那个人 "authorizes" 您的帐户。由于他们尚未授权尝试查询其好友列表的帐户,因此您会收到来自 Twitter 的 HTTP 401 Unauthorized。因此,"Not Authorized" 消息的原因。

虽然用户实体有一个 bool Protected 属性,但在你的情况下检查它是不切实际的,因为你只使用 ID 列表并且不' 有可用的完整 User 实例。在这种情况下,您唯一能做的就是处理异常并从那里恢复。处理这个异常有两个地方:(1)查询原始好友列表时和(2)查询好友的好友列表时,如下所示:

        var allFollowerIds = new List<ulong>();
        Friendship followers = null;
        long cursor = -1;
        do
        {
            try
            {
                followers =
                    await
                    (from follower in twitterCtx.Friendship
                     where follower.Type == FriendshipType.FollowerIDs &&
                           follower.UserID == "1039951639" &&// "15411837" &&
                           follower.Cursor == cursor &&
                           follower.Count == 500
                     select follower)
                    .SingleOrDefaultAsync();
            }
            catch (TwitterQueryException tqExUnauthorized) when (tqExUnauthorized.StatusCode == HttpStatusCode.Unauthorized)
            {
                Console.WriteLine("This user hasn't given your account permission to view their account.");
            }
            catch (TwitterQueryException tqe)
            {
                Console.WriteLine(tqe.ToString());
                break;
            }

            if (followers != null &&
                followers.IDInfo != null &&
                followers.IDInfo.IDs != null)
            {
                cursor = followers.CursorMovement.Next;

                allFollowerIds.AddRange(followers.IDInfo.IDs);
            }

        } while (cursor != 0);

        cursor = -1;
        foreach (var uid in allFollowerIds)
        {
            Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Start Friend Get for " + uid.ToString() + " ***");

            do
            {
                Friendship friendList = null;
                try
                {
                    friendList = await (from friend in twitterCtx.Friendship where friend.Type == FriendshipType.FriendIDs && friend.UserID == uid.ToString() && friend.Cursor == cursor select friend).SingleOrDefaultAsync();
                }
                catch (TwitterQueryException tqExUnauthorized) when (tqExUnauthorized.StatusCode == HttpStatusCode.Unauthorized)
                {
                    Console.WriteLine("This user hasn't given your account permission to view their account.");
                }

                if (twitterCtx.RateLimitRemaining <= 2)
                {
                    Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Pausing A ***");
                    Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - Friends Rate Limit Remaining at Pause A: " +
                      twitterCtx.RateLimitRemaining.ToString());
                    //PauseThatRefreshes("friends");
                }

                if (friendList != null &&
                  friendList.IDInfo != null &&
                  friendList.IDInfo.IDs != null)
                {
                    cursor = friendList.CursorMovement.Next;
                    Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - Friends Rate Limit Remaining: " + twitterCtx.RateLimitRemaining.ToString());
                    //friendList.IDInfo.IDs.ForEach(id => Output(uid.ToString(), id.ToString()));
                }

                if (twitterCtx.RateLimitRemaining <= 2)
                {
                    Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Pause B ***");
                    Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - Friends Rate Limit Remaining at Pause B: " + twitterCtx.RateLimitRemaining.ToString());
                    //PauseThatRefreshes("friends");
                }
            } while (cursor != 0);

            Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - *** Stop Friend Get for " + uid.ToString() + " ***");
            Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + " - Friends Rate Limit Remaining at stop: " + twitterCtx.RateLimitRemaining.ToString());
        }

请注意,我使用了带有 when 子句的 try/catch,专门用于 401 Unauthorized 场景,重复如下:

        catch (TwitterQueryException tqExUnauthorized) when (tqExUnauthorized.StatusCode == HttpStatusCode.Unauthorized)
        {
            Console.WriteLine("This user hasn't given your account permission to view their account.");
        }

对于朋友列表,这让您可以只处理 Unauthorized 部分,并且仍然保护不符合该条件的任何其他 TwitterQueryException。对于好友的好友列表,只需要处理Unauthorized异常,让查询继续迭代剩余的好友即可。