Skip to content

Instantly share code, notes, and snippets.

@PhilipTrauner
Created July 4, 2017 13:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PhilipTrauner/8c2436caf738c0841f3e942a6642d824 to your computer and use it in GitHub Desktop.
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)
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>&lt;invoke name="GetData" ' \
'returntype="xml"&gt;&lt;arguments&gt;&lt;null/&gt;&lt;object&gt;&lt;property ' \
'id="TopicTree"&gt;&lt;string&gt;VogelPractice&lt;/string&gt;&lt;/property&gt;&lt;property ' \
'id="Language"&gt;&lt;string&gt;DE&lt;/string&gt;&lt;/property&gt;&lt;/object&gt;&lt;' \
'/arguments&gt;&lt;/invoke&gt;</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>&lt;invoke name="GetData" ' \
'returntype="xml"&gt;&lt;arguments&gt;&lt;null/&gt;&lt;object&gt;&lt;property ' \
'id="Language"&gt;&lt;string&gt;DE&lt;/string&gt;&lt;/property&gt;&lt;property ' \
'id="Topic"&gt;&lt;number&gt;%s&lt;/number&gt;&lt;/property&gt;&lt;/object&gt;&lt;' \
'/arguments&gt;&lt;/invoke&gt;</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