11import argparse
2+ import time
3+ import uuid
24import requests
35from urllib .parse import quote_plus
46from json import dumps , decoder
1012)
1113import pycountry
1214
15+ USER_AGENT = "Instagram 317.0.0.34.109 Android (31/12; 420dpi; 1080x2276; samsung; SM-G991B; o1s; exynos2100)"
16+ IG_APP_ID = "936619743392459"
17+ COMMON_HEADERS = {
18+ "User-Agent" : USER_AGENT ,
19+ "X-IG-App-ID" : IG_APP_ID ,
20+ "X-IG-Connection-Type" : "WiFi" ,
21+ "Accept-Language" : "en-US,en;q=0.9" ,
22+ "Accept-Encoding" : "gzip, deflate" ,
23+ }
24+ MAX_RETRIES = 3
25+ RETRY_BASE_DELAY = 2
26+
27+
28+ def _create_session (sessionId ):
29+ session = requests .Session ()
30+ session .headers .update (COMMON_HEADERS )
31+ session .cookies .set ("sessionid" , sessionId , domain = ".instagram.com" )
32+ session .headers ["X-IG-Device-ID" ] = str (uuid .uuid4 ())
33+ return session
34+
35+
36+ def _request_with_retry (method , session , url , ** kwargs ):
37+ for attempt in range (MAX_RETRIES ):
38+ response = method (url , ** kwargs )
39+ if response .status_code == 429 :
40+ delay = RETRY_BASE_DELAY ** (attempt + 1 )
41+ print (f"Rate limited, retrying in { delay } s... (attempt { attempt + 1 } /{ MAX_RETRIES } )" )
42+ time .sleep (delay )
43+ continue
44+ return response
45+ return response
46+
1347
14- def getUserId (username , sessionsId ):
15- headers = { "User-Agent" : "iphone_ua" , "x-ig-app-id" : "936619743392459" }
16- api = requests .get (
48+ def getUserId (username , session ):
49+ response = _request_with_retry (
50+ session .get , session ,
1751 f'https://i.instagram.com/api/v1/users/web_profile_info/?username={ username } ' ,
18- headers = headers ,
19- cookies = {'sessionid' : sessionsId }
2052 )
21- try :
22- if api .status_code == 404 :
23- return {"id" : None , "error" : "User not found" }
53+ if response .status_code == 404 :
54+ return {"id" : None , "error" : "User not found" }
55+ if response .status_code == 401 :
56+ return {"id" : None , "error" : "Invalid or expired session ID" }
57+ if response .status_code == 429 :
58+ return {"id" : None , "error" : "Rate limit" }
2459
25- id = api .json ()["data" ]['user' ]['id' ]
26- return {"id" : id , "error" : None }
60+ try :
61+ user_id = response .json ()["data" ]['user' ]['id' ]
62+ return {"id" : user_id , "error" : None }
63+ except (decoder .JSONDecodeError , KeyError , TypeError ):
64+ return {"id" : None , "error" : f"Rate limit (status { response .status_code } )" }
2765
28- except decoder .JSONDecodeError :
29- return {"id" : None , "error" : "Rate limit" }
3066
67+ def getInfo (search , sessionId , searchType = "username" ):
68+ session = _create_session (sessionId )
3169
32- def getInfo (search , sessionId , searchType = "username" or "id" ):
3370 if searchType == "username" :
34- data = getUserId (search , sessionId )
71+ data = getUserId (search , session )
3572 if data ["error" ]:
3673 return data
3774 userId = data ["id" ]
@@ -41,12 +78,15 @@ def getInfo(search, sessionId, searchType="username" or "id"):
4178 except ValueError :
4279 return {"user" : None , "error" : "Invalid ID" }
4380
81+ time .sleep (1.5 )
82+
4483 try :
45- response = requests .get (
84+ response = _request_with_retry (
85+ session .get , session ,
4686 f'https://i.instagram.com/api/v1/users/{ userId } /info/' ,
47- headers = {'User-Agent' : 'Instagram 64.0.0.14.96' },
48- cookies = {'sessionid' : sessionId }
4987 )
88+ if response .status_code == 401 :
89+ return {"user" : None , "error" : "Invalid or expired session ID" }
5090 if response .status_code == 429 :
5191 return {"user" : None , "error" : "Rate limit" }
5292
@@ -57,40 +97,40 @@ def getInfo(search, sessionId, searchType="username" or "id"):
5797 return {"user" : None , "error" : "Not found" }
5898
5999 info_user ["userID" ] = userId
100+ info_user ["_session" ] = session
60101 return {"user" : info_user , "error" : None }
61102
62103 except requests .exceptions .RequestException :
63104 return {"user" : None , "error" : "Not found" }
64105
65106
66- def advanced_lookup (username ):
107+ def advanced_lookup (username , session ):
67108 """
68109 Post to get obfuscated login infos
69110 """
70111 data = "signed_body=SIGNATURE." + quote_plus (dumps (
71112 {"q" : username , "skip_recovery" : "1" },
72113 separators = ("," , ":" )
73114 ))
74- api = requests .post (
115+
116+ time .sleep (1.5 )
117+
118+ response = _request_with_retry (
119+ session .post , session ,
75120 'https://i.instagram.com/api/v1/users/lookup/' ,
76121 headers = {
77- "Accept-Language" : "en-US" ,
78- "User-Agent" : "Instagram 101.0.0.15.120" ,
79122 "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8" ,
80- "X-IG-App-ID" : "124024574287414" ,
81- "Accept-Encoding" : "gzip, deflate" ,
82123 "Host" : "i.instagram.com" ,
83- # "X-FB-HTTP-Engine": "Liger",
84124 "Connection" : "keep-alive" ,
85125 "Content-Length" : str (len (data ))
86126 },
87127 data = data
88128 )
89129
90130 try :
91- return ( {"user" : api .json (), "error" : None })
131+ return {"user" : response .json (), "error" : None }
92132 except decoder .JSONDecodeError :
93- return ( {"user" : None , "error" : "rate limit" })
133+ return {"user" : None , "error" : "rate limit" }
94134
95135
96136def main ():
@@ -108,6 +148,7 @@ def main():
108148 if not infos .get ("user" ):
109149 exit (infos ["error" ])
110150
151+ session = infos ["user" ].pop ("_session" , None )
111152 infos = infos ["user" ]
112153
113154 print ("Informations about : " + infos ["username" ])
@@ -119,14 +160,14 @@ def main():
119160 print (
120161 "Follower : " + str (infos ["follower_count" ]) + " | Following : " + str (infos ["following_count" ]))
121162 print ("Number of posts : " + str (infos ["media_count" ]))
122- # print("Number of tag in posts : "+str(infos["following_tag_count"]))
123163 if infos ["external_url" ]:
124164 print ("External url : " + infos ["external_url" ])
125- print ("IGTV posts : " + str (infos ["total_igtv_videos" ]))
126- print ("Biography : " + (f"""\n { " " * 25 } """ ).join (infos ["biography" ].split ("\n " )))
127- print ("Linked WhatsApp : " + str (infos ["is_whatsapp_linked" ]))
128- print ("Memorial Account : " + str (infos ["is_memorialized" ]))
129- print ("New Instagram user : " + str (infos ["is_new_to_instagram" ]))
165+ if "total_igtv_videos" in infos :
166+ print ("IGTV posts : " + str (infos ["total_igtv_videos" ]))
167+ print ("Biography : " + (f"""\n { " " * 25 } """ ).join (infos .get ("biography" , "" ).split ("\n " )))
168+ print ("Linked WhatsApp : " + str (infos .get ("is_whatsapp_linked" , "N/A" )))
169+ print ("Memorial Account : " + str (infos .get ("is_memorialized" , "N/A" )))
170+ print ("New Instagram user : " + str (infos .get ("is_new_to_instagram" , "N/A" )))
130171
131172 if "public_email" in infos .keys ():
132173 if infos ["public_email" ]:
@@ -140,11 +181,11 @@ def main():
140181 countrycode = region_code_for_country_code (pn .country_code )
141182 country = pycountry .countries .get (alpha_2 = countrycode )
142183 phonenr = phonenr + " ({}) " .format (country .name )
143- except : # except what ??
144- pass # pass what ??
184+ except ( phonenumbers . NumberParseException , AttributeError ):
185+ pass
145186 print ("Public Phone number : " + phonenr )
146187
147- other_infos = advanced_lookup (infos ["username" ])
188+ other_infos = advanced_lookup (infos ["username" ], session )
148189
149190 if other_infos ["error" ] == "rate limit" :
150191 print ("Rate limit please wait a few minutes before you try again" )
0 commit comments