نحوه دریافت اطلاعات از سایت tsetmc زیاد پرسیده میشه و من موضوع رو خدمت دوستان شرح میدم تا چراغی باشه برای دوستان که به همین ترتیب سایر پارامترهای مورد نیازشون رو از این سایت استخراج کنند.
البته برای اینکار با روشهای استاندارد، API هایی وجود داره که اغلب پولی هستند، بنابراین ما ترجیح دادیم دیتاها رو مستقیم از سایت tsetmc بخونیم.
سایت tsetmc بسیار بد، غیر استاندارد و درهم کدنویسی شده که اصطلاحاً #اسپاگتی_کد گفته میشه! برای همین یکم کار مهندسی معکوس رو سخت میکنه.
در ابتدا وقتی در کروم روی صفحه یک نماد، ctrl+shift+i میزنید تا Developer Tools باز و وارد تب Network میشید، حتماً به عنوان اولین آدرسی که مرتب و تکرارشونده داره دیتاها رو میگیره به چیزی شبیه این میرسید:
http://www.tsetmc.com/tsev2/data/instinfodata.aspx?i=9211775239375291&c=70%20
درسته این دیتاهای جدید درون صفحه رو میگیره و خب با یک سری کارکتر کاما(,) و اَتساین(@) جدا شدن که میشه اونها رو تفکیک کرد.
مثلاً به ترتیب ساعت بروزرسانی، وضعیت، آخرین قیمت و... هستند که با یک کاما جدا شدند و میشه اونها رو تفکیک کرد.
اصطلاحاً parse کردن اونها کار سختی نیست چون من فرض رو قرار دادم شما یک برنامه نویس هستید. (تصویر شماره 1)
پس تا همینجای کار تونستید برخی داده ها رو استخراج کنید.
برمیگردیم به صورت مسئله یعنی استخراج PE که در مثال ما، روی نماد "ذوب" کار میکنیم که همونطور که در تصویر1 دیدید، اکنون مقدارش 30.47 هست، عدد PE رو در خروجی آدرس قبلی سرچ میکنیم اما وجود نداره! تقریباً همه مقادیر هستن بجز PE! درون صفحه اصلی view source میزنیم اونجا هم نیست!
دو احتمال هست، اینکه از یک آدرس دیگه داره خونده میشه یا با جاوااسکریپت در لحظه داره محاسبه میشه یا هر دو (شد سه تا!)
ابتدا سایر درخواست های کروم رو بررسی میکنیم ولی چیز بیشتری نیست!
صفحه اصلی یک نماد رو view source بزنید، در بخش ابتدایی صفحه کدهای جاوااسکریپتی هست که اگر اونها رو تمیز کنید متوجه سرنخ هایی میشیم! (تصویر شماره 2)
همینجا بگم برای مرتب سازی و clean کردن کدهای جاوااسکریپت میتونید از این سایت کمک بگیرید:
بعدم کپیش کنید ببرید توی ++NotePad که بهتر بتونید بررسیش کنید.
با بررسی اون قطعه کد متوجه میشید برخی آدرسها از بهم چسبیدن برخی پارامترها ساخته و سپس درخواست آژاکس به اونها ارسال میشه.(تصویر شماره 3)
اما چرا اون درخواست آژاکس رو در network نبینیم؟!
در ادامه توضیح میدم.
نکته اینجاست که بعضی درخواست ها رو در Network کروم احتمالاً نمیبینید. دلیلشم اینه که در اولین درخواست، سایت میاد برگشتی اونها رو در کش مرورگر ذخیره میکنه و در مرتبه بعدی دیگه اون درخواست ارسال نمیشه و از کش میخونه و بنابراین شما یک سری درخواست های آژاکسی رو نمیبینید. (این با کش طبیعی مرورگر اشتباه گرفته نشه چون اون حتی درخواست های کش رو هم نشون میده و بجای response code 200 کد رنج 300 برمیگرده ولی درخواست دیده میشه که الان مورد بحثمون نیست؛ اما اینجا در سایت بورس یک مکانیزم من درآوردی(!) هست که طراح سایت براش کد خاصی نوشته که اونها رو در متغییرهای local مرورگر ذخیره میکنه و سایتهای دیگه چنین رفتاری ندارند.)
برای بررسی کش، از تب application و قسمت local storage اونها رو پیدا کنید. (تصویر شماره 4)
و طبعاً اگر صفحه رو برای مرتبه اول باز کنید اون آدرسها رو میبینید که برای اینکار میتونید یا کش مرورگر رو پاک کنید(در همون تب application گزینه Clear Storage) و یا اینکه سایت رو در وضعیت Incognito باز کنید. (تصویر شماره 5)
خب حالا دیگه این سه آدرس جدید رو کشف کردیم و داریم:
http://www.tsetmc.com/tsev2/res/loader.aspx?t=i&_484<br/>http://www.tsetmc.com/tsev2/res/loader.aspx?t=j&_484<br/>http://www.tsetmc.com/tsev2/res/loader.aspx?t=s&_484
که اگرچه توشون دیتایی نیست ولی کدهای جاوااسکریپت تازه ای داریم که برای مهندسی معکوس بهشون نیازمندیم.
حالا که مقدار مد نظر رو پیدا نمیکنیم، از آخر به اول میایم!
سایت برای اینکه مقدار PE رو در جای خودش نشون بده حتماً به یک آیدی یا المانی نیاز داره پس توی صفحه نماد، روی مقدار PE از inspect استفاده و به آیدی "d12" میرسیم.(تصویر شماره 6)
در کدهای فایل جاوااسکریپت جدید بدست اومده، عبارت d12 رو سرچ میکنیم، در اولین فایل، دو جا استفاده شده، اولی:
"<tr><td>EPS:</td><td>" + EstimatedEPS + '</td><td>P/E:</td><td id="d12"></td>...
(تصویر شماره 7 قسمت بالایی)
که فقط html رو ساخته و درست جایی که انتظار داریم متغییرش رو ببینیم مقداری داده نشده(ظاهراً فقط html خام رو ایجاد کرده) درسته! پس در جای دومیه که استفاده شده:
ChangeContentStyle("#d12", "" + AdvRound(parseInt(Ov[3]) / parseInt(EstimatedEPS), 2), c1)
(تصویر شماره 7 قسمت پایینی)
تقریباً مسئله روشن شد که Ov[3] رو تقسیم بر EstimatedEPS میکنه و تا دو رقم اعشار گرد و در نهایت در المان آیدی d12 میریزه.
متغییر EstimatedEPS از اسمش پیداس که EPS هست و اگر در صفحه اصلی نماد view source کنید و همین اسم رو سرچ کنید مقدارش رو پیدا میکنید.(تصویر شماره 8)
اما Ov[3] رو اگر کمی بالاتر کدها رو بخونید(تصویر شماره 9 (https://t.me/JahanChart/59)) میبینید همون دیتاهایی که از اولین آدرس که در همین مطلب اشاره کردم (instinfodata.aspx...) رو داره با کاما از هم جدا و استفاده میکنه، پس چون اندیس 3 هست، چهارمین مقدار(چون اندیس از صفر شروع میشه) رو داره استفاده میکنه، عددش رو در صفحه سرچ میکنیم و میبینیم این عدد متناظر با قیمت پایانیه.(رجوع به تصویر شماره 1 که میبینید شماره 3 قیمت پایانیه)
البته بازهم این متغییر رو سرچ کنید، چیزی شبیه این هم پیدا میکنید:
var PClosingNew = parseInt(Ov[3]);
که اسم متغییر داره میگه قیمت پایانیه که ما به این اکتفا نکردیم.(تصویر شماره 9)
حتی از زاویه دیگه، حالا که مسئله حل شد باید یادآور بشم که همه ما از اول میدونستیم که فرمول نسبت P/E هست: Price / EPS اما باید به عنوان یک برنامه نویس تحقیقاً بهش میرسیدیم.?
الان دیگه همه مجهولات مسئله رو حل کردیم و فقط میمونه کدنویسی که دیگه نیاز به توضیح نداره و کدی شبیه به این میشه که من با PHP نوشتم شما با هر زبونی میتونید بنویسید:
<?php //Code by @NabiKAZ //Telegram: @JahanChart //Getting data from the site tsetmc.com //Symbol ID $symbol_id = '9211775239375291'; //Get EPS $contens = file_get_contents('http://www.tsetmc.com/Loader.aspx?ParTree=151311&i=' . $symbol_id); $contens = gzdecode($contens); preg_match('/EstimatedEPS=\'(.*?)\'/', $contens, $matches); $eps = $matches[1]; //Get Symbol Name preg_match('/LVal18AFC=\'(.*?)\'/', $contens, $matches); $symbol_name = $matches[1]; //Get Close Price $contens = file_get_contents('http://www.tsetmc.com/tsev2/data/instinfodata.aspx?i=' . $symbol_id . '&c=70%20'); $contens = gzdecode($contens); $data = explode(',', $contens); $close_price = $data[3]; //Calculate PE $pe = round($close_price / $eps, 2); //Results echo 'Symbol ID: ' . $symbol_id . PHP_EOL; echo 'Symbol Name: ' . $symbol_name . PHP_EOL; echo 'Close Price: ' . $close_price . PHP_EOL; echo 'EPS: ' . $eps . PHP_EOL; echo 'P/E: ' . $pe . PHP_EOL;
خروجی:
# php get_data_tsetmc.php Symbol ID: 9211775239375291 Symbol Name: ذوب Close Price: 4235 EPS: 139 P/E: 30.47
خب به عدد 30.47 مقدار PE در صورت مسئله رسیدیم. (تصویر شماره 10)
پایان. 1399/08/22
—نبی
برای مطالب بیشتر میتونید به کانال @JahanChart روی تلگرام مراجعه کنید.
#مقاله #بورس #برنامه_نویسی #روبات