توصیفِ نیاز
شروعِ کار
http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/1/Question/154&dd=R1EZgzuBR+K8K/rEr9Xp5w==
برای الگویابی چندتا دیگر را نیز از همین آزمون و همان پیج تست میکنم:
http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/1/Question/154&dd=R1EZgzuBR+K8K/rEr9Xp5w== http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/1/Question/106&dd=R1EZgzuBR+K8K/rEr9Xp5w== http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/1/Question/254&dd=R1EZgzuBR+K8K/rEr9Xp5w==
خوب. ظاهراً برای سوالات فقط یک عدد را در URL عوض کنی کار تمام است؛ یعنی فقط یک for بزنیم تا از ۱ تا تعداد سوالات پیش برود و تصاویر را دانلود کند.
But wait!
ما قرار بود به برنامهمان تاریخِ آزمون را بدهیم و برنامه سوالات را دانلود کند، اما این لینکها چه ربطی به تاریخِ آزمون (که 13941109 است) دارند؟
سوالِ جالبی است و لازم است تستهای بیشتری برای پاسخدادن به آن طی شود.
لذا پیج را رفرش میکنیم و دوباره سعی میکنیم لینکِ چند سوال را بررسی کنیم.
بعد از رفرشِ اول:
http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/1/Question/1&dd=X35WmZvhZUE6QjxdMIOLWg==
بعد از رفرشِ دوم:
http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/1/Question/1&dd=n4j3TWaFuMCU3p3KSoCEBQ==
...
هوم... ظاهراً الگویِ مشخص و یکطرفهای بینِ «تاریخِ آزمون» و «آن مقدارِ dd» وجود ندارد و یک مقدار Randomـی چیزی موجود است. (از طرفی اگر سعی کنید مقدارِ dd را base64decode کنید نیز به چیزِ آنچنان واضحی نمیرسید)
خوب. چه میتوان کرد؟
به نظرِ من بیاییم و ببینیم مرورگر این مقدارِ dd را از کجا میآورد، ما هم آنرا از همانجا جستجو کنیم. لینکی که ما برای دیدنِ کلیدِ یک آزمون استفاده میکنیم چیزی مشابهِ این است:
http://www.kanoon.ir/Public/TestKey.aspx?td=13941109&gc=1
یعنی با تاریخِ آزمون یک رابطهی مشخصی دارد. حال بیایید سعی کنیم آن dd را در سورسِ صفحه(اولین جایی که ذهن به سمتش میرود) جستجو کنیم.
خوب. ظاهراً dd را میتوان در سورس یافت. پس یک رگکس به شکلِ زیر کارمان را راه خواهد انداخت:
p = re.compile(ur'id="CPCM_CPC_hdDate"[^\/]+value="([^"]+)"')
(زبان همانطور که گفتم پایتون است)
یعنی به عنوانِ یک گروه، مقداری که به دنبالِ آنهستیم را از سورسِ صفحه جدا میکند.
خوب. جمعبندی میکنیم:
۱- ما لینکِ صفحهی کلیدِ یک آزمون را داریم، چرا که تاریخش را میدانیم:
http://www.kanoon.ir/Public/TestKey.aspx?td=13941109&gc=1
* تنها مقدارِ متغیرِ دیگر غیر از تاریخِ آزمون، gc است که رشته و پایه را مشخص میکند، برای مثال gc=3 یعنی رشتهی تجربی و کلاس چهارم. (این دیگر فرمول ندارد و باید تکتک به دست بیاید)
۲- از طریقِ سورسِ صفحه میتوانیم مقدارِ ddـی که برای مشاهدهی تصویرِ یک سوال لازم است را بیابیم.
http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/3/Question/357&dd=HV45y6ZtIJq4jnLLJGYhNw==
۳- تنها یک for کافیست تا سوالات از ۱ تا فلان دانلود شوند!
* لینکِ پاسخها نیز کاملاً مشابه است و به فرمِ زیر میباشد:
http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/3/Answer/460&dd=HV45y6ZtIJq4jnLLJGYhNw==
کدزنیسم!
import requests import re import shutil import os import sys #1394-10-10 class_code = '1' # 1 is for 4th grade, mathematics and physics, I'm too fat to list all possible scenarios, DIY # eg: class_code = '3' is for 4th grade, practical sciences... date = raw_input("Enter exam date(yyyy-mm-dd): ") lower_bound = int(raw_input("Starting question number: ")) upper_bound = int(raw_input("Ending question number: ")) + 1 delimited = date.strip().split("-") date_str = "" for v in delimited: if len(v) < 2: date_str += "0" date_str += v web_page = requests.get("http://www.kanoon.ir/Public/TestKey.aspx?td=%s&gc=1"%date_str) p = re.compile(ur'id="CPCM_CPC_hdDate"[^\/]+value="([^"]+)"') try: token = re.search(p, web_page.content).groups()[0] except: print "A problem!" exit(0) #lower_bound = 238 #upper_bound = 250 for i in range(lower_bound, upper_bound +1): sys.stdout.write("Downloading question #%s" % i + '\r') link = "http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/%s/Question/%s&dd=%s" %(class_code, i, token) response = requests.get(link, stream=True) if int(response.headers.get('content-length')) < 2 * 1024: # if file is too small (empty) if i == lower_bound: print "Problem with lower bound" exit() upper_bound = i break if not os.path.exists(date_str + "\\" + "Questions"): os.makedirs(date_str + "\\" + "Questions") with open(date_str + "\\" + "Questions" + "\\" + '%s.png'%(i), 'wb') as out_file: shutil.copyfileobj(response.raw, out_file) del response print "Downloaded " + str(upper_bound-lower_bound) + " questions successfully!" for i in range(lower_bound, upper_bound+1): sys.stdout.write("Downloading answer #%s" % i + '\r') link = "http://www.kanoon.ir/Common/Handler/AzmoonTest.ashx?pic=/1/Answer/%s&dd=%s" %(i, token) response = requests.get(link, stream=True) if not os.path.exists(date_str + "\\" + "Answers"): os.makedirs(date_str + "\\" + "Answers") with open(date_str + "\\" + "Answers" + "\\" + '%s.png'%(i), 'wb') as out_file: shutil.copyfileobj(response.raw, out_file) del response print "Downloaded " + str(upper_bound-lower_bound) + " answers successfully!"
تولدت مبارک ابراهیم... 3>
وقت بشه منم یکی با QT و سی ++ مینویسم.
موفق باشی.