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
异常,让查询继续迭代剩余的好友即可。
所以,我正在尝试向某人所有关注者的朋友求助。不是递归挖掘,就是那个单层。
我能够很好地吸引追随者(看起来它可以处理超过 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
异常,让查询继续迭代剩余的好友即可。