خب سلام دوستان امروز خواستم تو این مقاله نحوه لاگین کردن تو سایت اینستاگرام با پایتون و لایبرری aiohttp رو برسی کنیم و ببینیم به چه شکل هستش، برای اینکه تو سایت اینستا گرام لاگین کنیم یا لایک، فالو و... رو انجام بدیم در پایتون میتونیم یا از لایبرری های که نوشته شدن استفاده کنیم یا بیایم خودمون اون متود هایی که نیاز داریم رو بنویسیم که ما هم میخوایم همین کار رو انجام بدیم، بعضی از لایبرری ها هستن که با requests نوشته شدن و بعضی هم با لایبرری selenium و.. که میتونید ازشون استفاده کنید ولی امروز ما میخوایم با لایبرری aiohttp بنویسیم .
در آخر این post لینک گیت هاب قرار گرفته که میتونید کد هایی نوشته شده رو دریافت کنید.
خب در مرحله اول نیاز هستش که خود پایتون رو بلد باشید، و یه درکی از http header ها داشته باشید، مورد بعدی بهتر هستش که داخل گوگل یک سرچی راجب اینکه خود request چی هستش متود هاش چی هست و چجوری کار میکنه و این دسته از موارد بکنید تا یه درکی ازش پیدا بکنید و همچنین اگر کار با لایبرری asyncio و aiohttp هم بلد باشید خیلی بهتون کمک میکنه پیشنهاد میکنم اگه ازشون استفاده نکردید یه سری به داکیومنتشون بزنید یا 1 2 مورد فیلم یا مقالت موجود رو ببینید و بخونید که مشکلی نداشته باشید..
نکته: برای ماژول asyncio در پایتون مقاله زیر خوب هستش و در کل خوندش خالی از لطف نیست!(در ادامه برای درک کد هایی که مینویسیم بهتون خیلی کمک میکنه)
برای اینکه که ما بفهمیم وقتی ریکوئستی فرستاده میشه دقیقا چه اتفاقی میفته و البته بر این اساس کدمون رو بنویسیم میتونیم از خود مرورگر، مرورگر هایی با قابلیت های بیشتر و یا افزونه ها و برنامه های دیگه استفاده کنیم،اینجا 3 مورد رو مینویسم که بیشتر استفاده میشه و در ادامه مثال هایی هم میزنیم ازشون:
اولین مورد که قسمت نتورک developer tools مروگرتون هستش و در دامه با این قسمت بیشتر آشنا میشیم.
دومین مورد هم یه برنامه مولتی پلتفرم و قدرتمند هستش که اینجا بدردمون میخوره و همچنین برای پنتست رو وب اپلیکیشن ها هم استفاده میشه و.. برای این مقاله ما میتونیم ازش برای دریافت، فرستادن و تغیر ریکوئست ها و بقیه موارد استفاده کنیم.
اخرین مورد هم میتونید در برنامش یا در add onsش یا در بستر وب ازش استفاده کنید .
از اون مواردی که بالا گفتیم اول میخوایم با Developer tools مروگر کار کنیم چون ساده تر هستش و برای استفاده کردنش لازم نیست کاری بکنید.
خب اولین کاری که باید انجام بدیم این هستش که بریم سایت اینستا و قسمت لاگین و بعدش Developer tools مروگر رو باز کنیم، بعد از این میتونیم تمام ریکوست هایی که در این tab فعلی ما به سمت اینستا میره رو ببینیم و همین درخواست ها رو با لایبرری aiohttp هم بفرستیم، در واقع تو مرورگر شما میاید درخواست هایی که میره رو اسنیف و برسی میکنید تا ببینید چه هدر هایی ست شده براشون و درخواست ها به کجا رفتن و... بعد میاید اون ها رو با این کتابخونه یا کتابخونه های دیگه مینویسید.
خب بریم اون مواردی که بالا گفتیم رو انجام بدیم ببینم چی میشه اول باید بریم سایت اینستا گرام و بعد قسمت Developer tools رو باز میکنیم بعد میریم قسمت Network و بعد اونجا ما میتونیم درخواست ها و ریسپانس ها رو ببینیم و ازشون استفاده کنیم :
وقتی میرید قسمت network مروگر(تصویر بالا) میبینید یه درخواست هایی فرستاده شده و برای هر درخواست شما میتونید ریسپانس و هدر request ها رو ببینید.(کافیه رو این درخواست هایی که فرستاده شده کلیک بکنید) ولی ما الان با این درخواست هایی که تا الان رفته کاری نداریم، چون میخوایم درخواست لاگین کردن رو ببینیم نه این موارد رو برای همین میتونید اون دکمه clear رو بزنید که ریکوست هایی که تا الان رفته رو پاک کنه و تمیز بشه یا اینکه اون دکمه قرمز رنگ سمت چپ رو بزنید بعد رفرش بکنید اینشکلی تا زمانی که فعالش نکنید درخواست ها رو براتون رکورد نمیکنه.
حالا ما برای اینکه درخواست لاگین کردن رو ببینیم نیاز داریم که یوزرنیم و پسورد رو تو اون فیلد های مربوط قرار بدیم و بعد دکمه login رو بزنیم و بعد از اون باید requestی که فرستاده میشه رو تو همین قسمت network مرورگر ببینیم(دقت کنید که دکمه قرمز رنگی که بالا گفتم قرمز باشه که رکورد کنه ریکوست ها رو)
خب من اول قسمت dev tools رو جابجا کردم و اون دکمه clear رو زدم که تمیز بشه و بهتر بتونیم ببینیمش، الان اینجا همونطور که مشاهده میکنید یه سری request فرستاده شده، الان ما اینجا درخواست های که تایپشون xhr هست رو میتوینم ببینیم ( xhr یا XmlHttpRequest یه ابجکت هستش که برای تعامل با سرور استفاده میشه، دیتا رو میتونید بگیرید از سرور بدونه اینکه صفحه رو رفرش کنید و اینکه میتونه به صورت synchronously و asynchronously این کار رو انجام بده؛ برای مثال زمانی که فالو میکنید، تو سرچ بار چیزی مینویسید یا لایک میکنیدو... درخواست های xhr هستن که فرستاده میشن و از سرور اون دیتا رو میگیرن و بهتون نشون میدن)
خب بیاید درخواست های مربوط Login رو باز کنیم تا بتونیم هدر هاشون رو ببینیم(برای اینکه بدونید کدوم درخواست مربوط به Login کردن هستش اول میتونید متود درخواست رو چک کنید و بعد تایپ درخواست، مثلا همونxhr)
خب وقتی میرید قسمت Header شامل چند قسمت میشه خودش
General
این قسمت یه info کلی میده بهمون که کلیک بکنید روش میتونید ببینیدش .
Response Header
اینجا هدر response اون درخواستی که فرستادیم رو میتونیم مشاهد کنیم.
Request Header
هدر اون requestی که فرستادیم رو میتونیم اینجا مشاهده کنیم.
قسمت اخر هم ممکن متغیر باشه مثلا الان ما یوز پسورد فرستادیم تو اینجا Form Data رو میتونید ببینید که داخلش دیتای هستش که فرستادیم .
خب در تصویر بالا شما هدر requestی که برای لاگین کردن فرستادیم رو میبینید که شامل خیلی چیزا میشه میتونید راجب http headers سرچ کنید و بفهمید چه مواردی داخل هدر قرار میگیره و.. اما قسمت پایین که با رنگ صورتی هایلایت شده اون قسمت دیتایی هستش که فرستادیم اونجا user و password ما قرار داره البته پسوردش یکم پیچیده میشه چون میتونید authentication version ست کنید که 0 برای تکست خالی هستش(همون عدد بین : : که اینجا 9 هستش) و میتونید صرفا پسورد رو بنویسید و تکست خالی رو میفرسته و خب امنیتش هم پایین چون میشه اسنیفش کرد... در ادامه باز بیشتر میگیم.. و البته درکل پسورد شامل time - version - password و قسمت ثابتی که اولش هست میشه.
الان تو تصویر بالا ما یک درخواست فرستادیم به /accounts/login/ajax/ و متودی که استفاده شده هم post هستش. یک سری از موارد داخل این header ست شده ولی ما اون ها رو نداریم و به صورت داینامیک هستن یعنی مثلا از درخواست های قبلی یه مقادری بدست میاد و بعد تو هدر این درخواست ست میشه و بعد فرستاده میشه به سمت سایت مثلا وقتی از متود post استفاده میکنیم یه هدری ست میشه روی درخواست هدر csrf-token ولی ما اینجا مقدارش رو نداریم این متغیر هستش هربار که درخواست بفرستیم سمت سایت نباید مقدار ثابت بدیم بهش و باید متغیر بدیم بهش این موارد معمولا از درخواست هایی که قبل تر فرستاده شده حالا چه در header چه در html اون پیج بدست میاد .
در تصویر بالا اومدیم صفحه رو رفرش کردیم میبنید که درخواست اول متود GET فرستاده شده به ادرس /accounts/login/ و در اینجا اگر هدر Responseی که برمیگرده رو دقت کنید میبینید که داره Cookie رو ست میکنه (اگر خواستید راجب ست کردن کوکی بدونید اینجا رو میتونید بخونید..)و همونجا هم داخل هدر csrf_token روهستش (قسمت سبز رنگ ) و خب ما به این csrf_token رو برای لاگین کردن نیاز داریم و البته از جا های دیگه ای هم میشه بدستش اورد که در ادامه میگیم .
بالاتر دیدیم که ریکوئست یه هدر هایی داره که باید ست کنیم تا درخواست ما معتبر باشه و ریسپانس درستی رو دریافت کنیم چون اگر هدر درست نباشه ممکنه جواب های مختلفی دریافت کنیم پس برای همین اون هدر هایی که در عکس بالا دیدیم رو داخل یک فایل به اسم config.py مینویسم البته الزامی نیست که همه اون هدر ها رو ست کنیم میتونید اون مواردی که نیاز دارید رو ست کنید(راجب شون میتونید سرچ کنید و.. یا تست کنید)
class Config: def __init__(self): self.user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36" def shared_data(self) -> tuple: url = "https://www.instagram.com/data/shared_data/" headers = { "user-agent":self.user_agent, } return url, headers def login(self, rollout_hash: str, csrf: str, username: str, password: str, version: int = 0, time: int = 0) -> tuple: url = "https://www.instagram.com/accounts/login/ajax/" headers = { "accept-encoding":"gzip, deflate", "accept-language":"en-US,en;q=0.9", "user-agent":self.user_agent, "origin":"https://www.instagram.com", "referer":"https://www.instagram.com/accounts/login/", "sec-fetch-site":"same-origin", "sec-fetch-mode":"cors", "x-instagram-ajax": rollout_hash, "X-CSRFToken":csrf, "x-requested-with":"XMLHttpRequest", } data = { "username":username, "enc_password":f"#PWD_INSTAGRAM_BROWSER:{version}:{time}:{password}", "queryParams":{}, "stopDeletionNonce":"", "optIntoOneTap":"false", "trustedDeviceRecords":{} } return url, headers, data
خب الان هدر های مورد نیازمون رو داخل فایل config.py نوشتیم و اینجا دوتا فانکشن نوشتیم یکی برای لاگین کردن و اون یکی هم برای گرفتن یک سری داده که بدردمون میخوره از جمله csrf-token و x-instagram-ajax و خیلی چیزای دیگه، که اگر نیاز بود میتونیم ازشون استفاده کنیم، اون user-agent هم چون هر هدری که ما بنویسیم ثابت هستش پس داخلی init تعریفش کردیم (در هدر بالا میتونید هرکدوم که ست شده رو سرچ کنید و متوجه میشید که برای چه کاری هستن ولی مینیموم هدری که برای لاگین کردن نیاز هست شامل user-agent و csrf-token میشه؛ یعنی این 2 تا هدر وجود داشته باشه کفایت میکنه و میتونید پروسه لاگین رو انجام بدید درضمن الان ما 2 تا هدر رو اینجا متغیر گذاشتیم(x-instagram-ajax و csrf) چون مقدارشون ثابت نیست و از shared_data بدستشون میاریم.)
import aiohttp import asyncio from datetime import datetime from config import Config # ==> local config file
خب اول میایم لایبرری های مورد نیاز مون رو ایمپورت میکنیم( اون لایبرری datetime رو هم برای قسمتی هستش که باید time رو ست کنیم داخل دیتایی که میفرستیم برای لاگین همراه با پسورد) و فایل کانفیگ مون رو هم ایمپورت کردیم.
async def login_user(session, username: str = None, password: str = None) -> bool: url, headers = Config().shared_data() async with session.get(url=url, headers=headers) as resp: data = await resp.json() csrf_token = data.get("config").get("csrf_token") rollout_hash = data.get("rollout_has")
در ادامه یک coroutine ساختیم به اسم login_user و 3تا ارگمان میگیره اولیش session هستش در واقع ابجکت ClientSession مون هستش و همچنین ارگمان های یوزرنیم و پسورد.
در خط بعد اون url که برای shared_data ست کردیم رو گرفتیم و الان دو متغیر url , headers مقدار دهی شدن(داخل کانفیگ فایل ما url , headers رو به شکل تاپل ریترن کردیم) و خب در ادامه میایم یه context manager ایجاد میکنیم و یک request با متود GET به اون url و با اون header که گرفتیم میفرستیم .
(اگر با Context manager مشکل دارید یا نمیدونید... میتونید این لینک رو بیبنید)
داخل بلوک context manger که ساختیم میایم ریسپانس درخواستمون رو دریافت میکنیم، میتونیم تکستش رو بگیریم یا اگر json باشه jsonش رو بگیریم که خیلی بهتر هستش و خب ما هم همین کار رو انجام میدیم و json میریزیم داخل متغیر data و بعد اومدیم ازمتود get استفاده کردریم و از اون دیتامون csrf_token رو گرفتیم در قدم بعدی اومدیم به همین شکل مقدار x-instagram-ajax v که نیاز داشتیم رو هم گرفتیم(بالاتر داخل کانفیگ فایل این دو مقدار رو به بعنوان پارامتر های تابعمون تعریف کرده بودیم).
الان باید هدر مورد نیاز برای لاگین کردن رو بگیریم یا بهتر بگم بسازیم :
url, headers, data = Config().login(rollout_hash ,csrf_token, username, password, 0, int(datetime.now().timestamp()))
اول متود login رو صدا زدیم و بهش اون مقادیر مورد نیاز رو دادیم، 2 تا ارگمان اول برای قسمت header هستن و 2 ارگمان بعدی هم یوزر پسورد ما هستش و 2 ارگمان اخر هم authentication version و timestamp مون هستش که ست کردیم براش.
اینجا لازمه که یه مورد رو بگم همونطور که بالا تر هم گفتیم authentication version میتونید ورژن دیگه ای رو قرار بدید و پسورد تون رو به صورت تکست خالی نفرستید و با استفاده از الگوریتم های رمز نگاری بیاید encrypt کنید پسورد تون رو و بعد بفرستید؛ در اینجا اگر بخواید همیچن کاری رو انجام بدید قبلا کدش نوشته شده مثلا میتونید از کدی که در لینک زیر قرار داره استفاده کنید برای جنریت کردن پسورد encrypt شده
https://gist.github.com/lorenzodifuccia/c857afa47ede66db852e6a25c0a1a027
والبته میتونید بیشتر هم سرچ کنید راجبش و.. در اینجا چون ما برامون مهم نیست که حالا پسورد مون تکست فرستاده بشه یا encrypt بشه پس همون ورژن 0 میزاریم که تکست خالی باشه و راحت لاگین بشیم، ولی اگه خواستید میتونید encryptش هم بکنید و اما اون shared_link رو هم برای همین اوردم و داخل کانفیگ ازش استفاده کریدم چون اینجا اگه بخواید پسورد تون رو encrypt بکنید نیاز دارید به یک key_id و یک public_key که این دو مورد داخل همین shared_link هستش و به شکل jsonهم بهمون میده و خیلی مناسب تر هستش وگرنه میتونید html سایت اینستا رو هم نگاه بکنید اونجا هم هستش که میتونید با لایبرری bs4 اسکرپ کنید اون قسمت رو ولی خب وقتی اینجا به شکل json میتونیم بدستش بیاریم دیگه چه کاریه! و البته csrf_token رو هم خیلی ساده از همینجا گرفتیم(اون رو هم باز میتونستید یه ریکوست بفرستید به سایت اینستا و از ریسپانس هدر اون ریکوست و از قسمت کوکی بدستش بیارید..)
در ادامه کار میایم با هدرها و دیتایی که داریم درخواستمون برای لاگین کردن رو میفرستیم:
async with session.post(url=url, headers=headers, data=data) as r: data = await r.json() print(data) if data.get("authenticated") == True: return True else: return False
خب میایم یه context manger منیجر دیگه مثل قبل ایجاد میکنیم و درخواست مون رو به اون url برای لاگین کردن میفرستیم ولی این بار از متود POST استفاده میکنیم چون میخوایم یوزنیم و پسورد رو هم بفرستیم(دیتامون) بعد میایم response این درخواستی که فرستادیم رو پرینت میکنیم اگر یوزرنیم و پسورد تون درست باشه لاگین میشید و باید همچین چیزی رو براتون پرینت بکنه(این پرینت رو گذاشتیم صرفا برای اینکه یه نگاهی به ریسپانس بندازیم):
{'user': True, 'userId': '46059443573', 'authenticated': True, 'oneTapPrompt': True, 'status': 'ok'}
والبته اگر لاگین تون موفقیت امیز نباشه همچین response رو دریافت خواهید کرد:
{'user': False, 'authenticated': False, 'status': 'ok'}
خب ما هم شرط گذاشتیم اگر اینجا authenticated برابر True بود یعنی با موفقیت لایگن کردیم و همه چی اوکی هستش و همونطور که قرار گذاشته بودیم True رو return میکنیم در غیر اینصورت هم False. (بهتر هستش که این قسمت رو داخل یه try قرار بدید که except های احتمالی رو هم هندل کنید براش و...)
و اما یک قسمت دیگه از کد باقی میمونه الان ما فقط یک Coroutine نوشتیم و باید اجراش کنیم برای اجرا کردنش هم به این شکل عمل میکنیم
async def main(): async with aiohttp.ClientSession() as session: login_task = asyncio.create_task(login_user(session, "Username", "Password")) response = await login_task if response: print("\nYou have successfully logged in") else: print("\nWrong username or password") asyncio.run(main())
خب قسمت اخر کدمون هم تابع main هستش(coroutine) که داخلش اومدیم یک تسک ایجاد کردیم و ارگمان های تابع لاگین یوزر مون رو هم بهش دادیم اولین ارگمان ابجکت Client session هستش و بعد یوزنیم و پسورد. خط بعد اومدیم با await اون تسک مون رو اجرا کردیم و چیزی که return میشه رو هم داخل response ریختیم و بعد یه پیامی رو هم پرنیت کردیم که بگیم لاگین شد یا نشد.
همونطور که قبلا گفتم میتونید این پروسه رو هم با اون بزار هایی که قبلا معرفی کردم تست کنید و انجام بدید اونا هم میتونن در بعضی مواقع خیلی مفید باشن... مثلا در تصویر زیر ما درخواست POST رو فرستادیم و اولین درخواست با موفقیت لاگین کردیم و هدر هم همونطور که مشخص کردم فقط csrf-token و user-agent باشه کفایت میکنه میتویند لاگین بشید و در تصویر بعدی هم پسورد اشتباه دادیم و لایگن انجام نشد و response متفاوتی رو دریافت کردیم.
یه نکته اگر از postman استفاده کردید بعد از اینکه لاگین کردید اگر خواستید باز هم تست کنید یادتون نره کوکی هاش رو پاک کنید، اون گوشه سمت راست زیر دکمه send گذینش هست چون وقتی شما کوکی ها رو پاک نکنید اکانت لاگین هستش و url ی که برای لایگن کردن هستش رو دیگه پیدا نمیکنه.(اگه دوباره send کنید)
اما الان شما لاگین کردید و در واقع اون قسمت که درخواست post رو فرستادیم اونجا از هدر اون responseمون میتونیم cookie رو بگیریم و اون رو داخل یک فایل یا دیتابیس ذخیره کنیم از این به بعد کافیه داخل فایل کانفیگ و داخل هدر هایی که میخوایم اون کوکی رو قرار بدیم و دیگه هرکاری انجام بدیم با اون اکانت انجام دادیم میتویند لایک کنید فالو کنید، لیست فالور هاتون رو بگیرید، پیام بدید و هرکار دیگه ای که میخواید.
پیشنهاد میکنم سورس های که داخل GitHub قرار گرفتن رو بخونید برسیش کنید باهاشون کار کنید تا بیشتر دستتون بیاد حالا شاید بعدا هم تو یه پست دیگه یه سری مثلا زدیم برای کار هایی مثل لایک ، فالو ، سرچ کردن، اپلود و..
و خب این قسمت همینجا تموم شد امید وارم مفید بوده باشه و اینکه اره سعی کنید خوشحال باشید، امید داشته باشید- - و به زندگیتون ادامه بدید، مرسی که تا اینجا خوندید ❤️
اگر نظری انتقادی پیشنهادی چیزی داشتید میتونید کامنت بزارید ✍️
کد هایی که نوشتیم رو هم در لینک زیر میتونید مشاهد و دانلود کنید: