Created
July 4, 2017 13:36
-
-
Save PhilipTrauner/8c2436caf738c0841f3e942a6642d824 to your computer and use it in GitHub Desktop.
Dump all questions from http://www.steigein-online.at/ (driving license training platform)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
from xml.sax.saxutils import unescape as xml_unescape | |
from urllib.parse import unquote as url_unescape | |
import xml.etree.ElementTree as ET | |
import json | |
from os import mkdir | |
from os.path import exists | |
from sys import argv | |
ANSWERS = {1 : [1], 2 : [2], 3 : [1, 2], 4 : [3], 5 : [1, 3], 6 : [2, 3], 7 : [1, 2, 3], 8 : [4], 9 : [1, 4], | |
10 : [2, 4], 11 : [1, 2, 3], 12 : [3, 4], 13 : [1, 3, 4], 14 : [2, 3, 4], 15: [1, 2, 3, 4]} | |
username = "" | |
password = "" | |
# Receive encrypted password from http://www.ruff.at/ (modify for you driving school) | |
def receive_encrypted_password(username, password): | |
headers = {"Content-Type" : "application/x-www-form-urlencoded"} | |
data = {"kennung" : username, "passwort" : password, | |
"domain" : "FS Ruff", "benutzertyp" : "Kunde", | |
"w" : "600", "h" : "150", "idsessionkey" : ""} | |
r = requests.post("http://weblearning.ruff.at/fcgi-bin/fast_kundenportal.fcgi", | |
headers=headers, data=data) | |
anchor_start_password = 'EncryptedPassword=' | |
start_password = r.text.find(anchor_start_password, 0) | |
encrypted_password = url_unescape(r.text[start_password + | |
len(anchor_start_password):r.text.find(",", start_password + | |
len(anchor_start_password)) - 1]) | |
return encrypted_password | |
def receive_raw_xml_elearning(data): | |
# Only required header | |
headers = {"Content-Type" : "text/xml; charset=utf-8"} | |
# Returns everything if the right content is posted | |
url = "http://www.steigein-online.at/INetService/Service.asmx" | |
# Junk at the start of every response | |
request_junk_front = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope ' \ | |
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ' \ | |
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' \ | |
'xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><RequestResponse ' \ | |
'xmlns="http://tempuri.org/"><RequestResult> ' | |
# Junk at the end of every response | |
request_junk_back = '</RequestResult></RequestResponse></soap:Body></soap:Envelope>' | |
mangled_xml = requests.post(url, headers=headers, data=data).text | |
raw_xml = xml_unescape(mangled_xml.lstrip(request_junk_front).rstrip(request_junk_back)).replace("utf-16", "utf-8") | |
return raw_xml | |
class ELearning: | |
def __init__(self, username, password): | |
self.username = username | |
self.password = receive_encrypted_password(username, password) | |
self._topics = None | |
@property | |
def topics(self): | |
if not self._topics: | |
topics = {} | |
data = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' \ | |
'xmlns:s="http://www.w3.org/2001/XMLSchema" ' \ | |
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' \ | |
'<SOAP-ENV:Body><tns:Request xmlns:tns="http://tempuri.org/">' \ | |
'<tns:pLogin>%s</tns:pLogin><tns:pPassword>%s</tns:pPassword>' \ | |
'<tns:pRequest><invoke name="GetData" ' \ | |
'returntype="xml"><arguments><null/><object><property ' \ | |
'id="TopicTree"><string>VogelPractice</string></property><property ' \ | |
'id="Language"><string>DE</string></property></object><' \ | |
'/arguments></invoke></tns:pRequest></tns:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>' % (self.username, self.password) | |
topics_xml = ET.fromstring(receive_raw_xml_elearning(data)).find("TopicTexts") | |
for topic in topics_xml: | |
topics[topic.get("TopicId")] = topic.get("Name") | |
self._topics = topics | |
return self._topics | |
def receive_topic(self, topic): | |
questions = {} | |
data = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' \ | |
'xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' \ | |
'<SOAP-ENV:Body><tns:Request xmlns:tns="http://tempuri.org/"><tns:pLogin>%s</tns:pLogin>' \ | |
'<tns:pPassword>%s</tns:pPassword><tns:pRequest><invoke name="GetData" ' \ | |
'returntype="xml"><arguments><null/><object><property ' \ | |
'id="Language"><string>DE</string></property><property ' \ | |
'id="Topic"><number>%s</number></property></object><' \ | |
'/arguments></invoke></tns:pRequest></tns:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>' % (self.username, self.password, str(topic)) | |
questions_xml = ET.fromstring(receive_raw_xml_elearning(data)) | |
for question in questions_xml.find("QuestionList"): | |
questions[question.get("QuestionId")] = {"official_question_id" : question.get("OfficialQuestionNr"), | |
"points" : question.get("Points"), "answer_count" : question.get("AnswerCount"), | |
"main_question_id" : question.get("MainQuestionId"), "level" : question.get("Level"), | |
"license_classes_text" : question.get("LicenseClassesText"), "solution" : ANSWERS[int(question.get("MultipleChoiceAnswers"))], | |
"picture_name" : question.get("PictureName"), "help_text_info_page" : question.get("HelpTextInfoPageId")} | |
for question in questions_xml.find("QuestionTextList"): | |
questions[question.get("QuestionId")]["question_text"] = question.get("QuestionText") | |
questions[question.get("QuestionId")]["answers"] = {1 : question.get("Answer1"), 2 : question.get("Answer2"), | |
3 : question.get("Answer3"), 4 : question.get("Answer4")} | |
return questions | |
def dump(self, folder): | |
if not folder.endswith("/"): | |
folder += "/" | |
for topic_id in self.topics: | |
topic = self.receive_topic(topic_id) | |
real_topic_name = self.topics[topic_id] | |
topic_name = self.topics[topic_id].replace(" ", "_").lower() | |
topic_path = folder + topic_name + "/" | |
if not exists(topic_path): | |
mkdir(topic_path) | |
topic_picture_path = topic_path + "images/" | |
open(topic_path + "meta.json", "w").write(json.dumps({"name" : real_topic_name, "count" : len(topic)})) | |
open(topic_path + "questions.json", "w").write(json.dumps(topic, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)) | |
if not exists(topic_picture_path): | |
mkdir(topic_picture_path) | |
for question in topic: | |
picture_name = topic[question]["picture_name"] | |
if picture_name != None: | |
picture_path = topic_picture_path + picture_name | |
if not exists(picture_path): | |
with open(picture_path, 'wb') as handle: | |
response = requests.get('http://seolive.blob.core.windows.net/image-5/720x480/%s' % picture_name, stream=True) | |
if not response.ok: | |
print("Error downloading %s" % picture_name) | |
break | |
for block in response.iter_content(1024): | |
handle.write(block) | |
e = ELearning(username, password) | |
if len(argv) == 2: | |
if not exists(argv[1]): | |
mkdir(argv[1]) | |
e.dump(argv[1]) | |
else: | |
print("Supply folder as argument.") | |
# This is the scheme used to resolve which answers are correct | |
# 1: 1 | |
# 2: 2 | |
# 3: 1, 2 | |
# 4: 3 | |
# 5: 1, 3 | |
# 6: 2, 3 | |
# 7: 1, 2, 3 | |
# 8: 4 | |
# 9: 1, 4 | |
# 10: 2, 4 | |
# 11: 1, 2, 4 | |
# 12: 3, 4 | |
# 13: 1, 3, 4 | |
# 14: 2, 3, 4 | |
# 15: 1, 2, 3, 4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment