1313bearer = "Bearer AAAAAAAAAAAAAAAAAAAAAPYXBAAAAAAACLXUNDekMxqa8h%2F40K4moUkGsoc%3DTYfbDKbT3jJPCEVnMYqilB28NHfOPqkca3qaAxGfsyKCs0wRbw"
1414v2bearer = "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA"
1515androidBearer = "Bearer AAAAAAAAAAAAAAAAAAAAAFXzAwAAAAAAMHCxpeSDG1gLNLghVe8d74hl6k4%3DRUMF4xAQLsbeBhTSRrCiQpJtxoGWeyHrDb5te2jpGskWDFW82F"
16- tweetdeckBearer = "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF"
1716
1817requestUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0"
1918
20- bearerTokens = [tweetdeckBearer , bearer ,v2bearer ,androidBearer ]
19+ bearerTokens = [bearer ,v2bearer ,androidBearer ]
2120
2221guestToken = None
2322guestTokenUses = 0
3635androidGraphql_api = "k3rtLsS9kG5hI-Jr0dTMCg"
3736
3837tweetDetailGraphqlFeatures = '{"rweb_tipjar_consumption_enabled":true,"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"communities_web_enable_tweet_community_results_fetch":true,"c9s_tweet_anatomy_moderator_badge_enabled":true,"articles_preview_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"creator_subscriptions_quote_tweet_preview_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_enhance_cards_enabled":false}'
39- tweetDetailGraphql_api = "e7RKseIxLu7HgkWNKZ6qnw "
38+ tweetDetailGraphql_api = "YVyS4SfwYW7Uw5qwy0mQCA "
4039
4140# this is for UserTweets endpoint
4241tweetFeedGraphqlFeatures = '{"rweb_video_screen_enabled":false,"profile_label_improvements_pcf_label_in_post_enabled":true,"rweb_tipjar_consumption_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"premium_content_api_read_enabled":false,"communities_web_enable_tweet_community_results_fetch":true,"c9s_tweet_anatomy_moderator_badge_enabled":true,"responsive_web_grok_analyze_button_fetch_trends_enabled":false,"responsive_web_grok_analyze_post_followups_enabled":true,"responsive_web_jetfuel_frame":false,"responsive_web_grok_share_attachment_enabled":true,"articles_preview_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"responsive_web_grok_show_grok_translated_post":false,"responsive_web_grok_analysis_button_from_backend":true,"creator_subscriptions_quote_tweet_preview_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_grok_image_annotation_enabled":true,"responsive_web_enhance_cards_enabled":false}'
@@ -116,7 +115,7 @@ def cycleBearerTokenGet(url,headers):
116115
117116def twitterApiGet (url ,btoken = None ,authToken = None ,guestToken = None ):
118117
119- if authToken .startswith ("oa|" ):
118+ if authToken != None and authToken .startswith ("oa|" ):
120119 url = url .replace ("https://x.com/i/api/graphql/" ,"https://api.twitter.com/graphql/" )
121120 authToken = authToken [3 :]
122121 key = authToken .split ("|" )[0 ]
@@ -132,7 +131,8 @@ def twitterApiGet(url,btoken=None,authToken=None,guestToken=None):
132131 response = requests .get (url ,headers = headers )
133132 else :
134133 if btoken is None :
135- return cycleBearerTokenGet (url ,getAuthHeaders (bearer ,authToken = authToken ,guestToken = guestToken ))
134+ btoken = v2bearer
135+ #return cycleBearerTokenGet(url,getAuthHeaders(bearer,authToken=authToken,guestToken=guestToken))
136136 headers = getAuthHeaders (btoken ,authToken = authToken ,guestToken = guestToken )
137137 response = requests .get (url , headers = headers )
138138
@@ -437,7 +437,10 @@ def request_with_token(twid, authToken):
437437 return tweet
438438 return parallel_token_request (twid , tokens , request_with_token )
439439
440- def extractStatusV2Anon (url ,x ):
440+ def extractStatusV2Rest_Anon (url ,workaroundTokens ):
441+ return extractStatusV2Rest (url ,None )
442+
443+ def extractStatusV2Rest (url ,workaroundTokens ):
441444 # get tweet ID
442445 m = re .search (pathregex , url )
443446 if m is None :
@@ -450,7 +453,17 @@ def extractStatusV2Anon(url,x):
450453 try :
451454 vars = json .loads ('{"tweetId":"0","withCommunity":false,"includePromotedContent":false,"withVoice":false}' )
452455 vars ['tweetId' ] = str (twid )
453- tweet = requests .get (f"https://x.com/i/api/graphql/{ v2AnonGraphql_api } /TweetResultByRestId?variables={ urllib .parse .quote (json .dumps (vars ))} &features={ urllib .parse .quote (v2AnonFeatures )} " , headers = getAuthHeaders (v2bearer ,guestToken = guestToken ))
456+ if workaroundTokens is not None and len (workaroundTokens ) > 0 :
457+ tokens = workaroundTokens
458+ random .shuffle (tokens )
459+ for authToken in tokens :
460+ try :
461+ tweet = twitterApiGet (f"https://x.com/i/api/graphql/{ v2AnonGraphql_api } /TweetResultByRestId?variables={ urllib .parse .quote (json .dumps (vars ))} &features={ urllib .parse .quote (v2AnonFeatures )} " , btoken = v2bearer ,authToken = authToken ,guestToken = guestToken )
462+ except Exception as e :
463+ continue
464+ else :
465+ tweet = twitterApiGet (f"https://x.com/i/api/graphql/{ v2AnonGraphql_api } /TweetResultByRestId?variables={ urllib .parse .quote (json .dumps (vars ))} &features={ urllib .parse .quote (v2AnonFeatures )} " , btoken = v2bearer ,guestToken = guestToken )
466+
454467 try :
455468 rateLimitRemaining = tweet .headers .get ("x-rate-limit-remaining" )
456469 print (f"Twitter Anon Token Rate limit remaining: { rateLimitRemaining } " )
@@ -498,7 +511,7 @@ def fixTweetData(tweet):
498511
499512def extractStatus (url ,workaroundTokens = None ):
500513 # TODO: commented out methods are too slow/unreliable at the moment
501- methods = [extractStatusV2Anon ,extractStatusV2 ,extractStatusV2Android ]#,extractStatusV2TweetDetail]
514+ methods = [extractStatusV2Rest_Anon ,extractStatusV2 , extractStatusV2Rest ,extractStatusV2Android ]#,extractStatusV2TweetDetail]
502515 for method in methods :
503516 try :
504517 result = method (url ,workaroundTokens )
0 commit comments