呂紹榕 Louie Lu
一些故事
使用的資源與技術
Q&A
http://ilearning.kuas.edu.tw
http://mail.kuas.edu.tw
http://ap.kuas.edu.tw
http://selcourse.kuas.edu.tw
http://leave.kuas.edu.tw
http://bus.kuas.edu.tw
我們才使用到新的校務系統?
- Google模式 p30
遺憾的是,跟羅森柏格那個失敗的關卡式(Gate-based)產品開發架構一樣,現今許多公司採行的管理流程設計原理跟不上時代的趨勢變化 ...... ,這種方式旨在減緩速度,而它也的確非常有效地減緩速度,但這意味的是,當企業必須永久加速時,它們的架構卻會絆住它們,讓它們快不起來。
- Google模式 p31
以海報為例
以海報為例
HTML (with only IE)
JSON
HTML5
那時候不會寫 APP,
就用 GreaseMonkey 解決這個問題
畢竟我的繳費單印完了,我也能不用 IE 就查成績
import requests
AP_LOGIN_URL = "http://140.127.113.227/kuas/perchk.jsp"
def login(username, password):
s = requests.session()
data = {"uid": username, "pwd": password}
r = s.post(AP_LOGIN_URL, data=data)
return s
使用者人數?
@Google Play & App Store
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
requests.get("http://tao.kuas.cc")
requests.post("http://ap.kuas.edu.tw",
data={"uid": "123",
"pwd": "123"}
)
session = requests.Session()
session.get()
session.post()
session.cookies
def login(session, username, password):
data = {"uid": username, "pwd": password}
r = session.post(AP_LOGIN_URL, data=data, timeout=LOGIN_TIMEOUT)
root = etree.HTML(r.text)
try:
is_login = not root.xpath("//script")[-1].text.startswith("alert")
except:
is_login = False
return is_login
def login(session, username, password):
data = {"uid": username, "pwd": password}
r = session.post(AP_LOGIN_URL, data=data, timeout=LOGIN_TIMEOUT)
root = etree.HTML(r.text)
try:
is_login = not root.xpath("//script")[-1].text.startswith("alert")
except:
is_login = False
return is_login
<script language='javascript'>
alert('[11] 無此帳號或密碼不正確,請重新輸入。');
top.location.href='index.html';
</script>
@app.route('/ap/login', methods=['POST'])
@cross_origin(supports_credentials=True)
def login_post():
if request.method == "POST":
session.permanent = True
# Start login
username = request.form['username']
password = request.form['password']
s = requests.Session()
is_login = function.login(s, username, password)
if is_login:
# Serialize cookies with domain
session['c'] = dump_cookies(s.cookies)
session['username'] = username
return "true"
else:
return "false"
return render_template("login.html")
def dump_cookies(cookies_list):
cookies = []
for c in cookies_list:
cookies.append({
'name': c.name,
'domain': c.domain,
'value': c.value
})
return cookies
def set_cookies(s, cookies):
for c in cookies:
s.cookies.set(
c['name'],
c['value'],
domain=c['domain']
)
def dump_cookies(cookies_list):
cookies = []
for c in cookies_list:
cookies.append({
'name': c.name,
'domain': c.domain,
'value': c.value
})
return cookies
def authenticate(func):
@wraps(func)
def call(*args, **kwargs):
if 'c' in session:
return func(*args, **kwargs)
else:
return "false"
return call
@app.route("/ap/login_test")
def login_test():
if 'c' not in session:
return "false"
return "You are login."
@app.route("/ap/login_test")
@authenticate
def login_test():
return "You are login."
>>> import requests
>>> s = requests.Session()
>>> r = s.post("http://localhost:5000/ap/login",
... data={"username": "1102108133", "password": "111"}
... )
>>> r.text
'true'
query_url = "http://140.127.113.227/kuas/%s_pro/%s.jsp?"
def query(session, qid=None, args=None):
ls_random = random_number(session, RANDOM_ID)
data = {"arg01": "", "arg02": "", "arg03": "",
"fncid": "", "uid": "", "ls_randnum": ""}
data['ls_randnum'] = ls_random
data['fncid'] = qid
for key in args:
data[key] = args[key]
try:
content = session.post(
query_url % (qid[:2], qid),
data=data,
timeout=QUERY_TIMEOUT
).content
except requests.exceptions.ReadTimeout:
content = ""
return content
>>> r.text
'true'
>>> r = s.post("http://localhost:5000/ap/query",
... data={"fncid": "ag222", "arg01": "103", "arg02": "01"}
... )
>>> r.text
<input type="button" class=button value="回上一頁" style="cursor:hand;height:20px"
onclick="vbscript:history.go(-1)"><font style=\'font-style: normal; font-variant:
normal; font-weight: normal; font-size: 9pt; font-family: 細明體\'> 學生:『<font
color=\'blue\'>呂紹榕</font>』課表資料如下:</font><form name=thisform method=post ><
div align=center><font style="font-size: 9pt; font-family: 細明體" color="#000000">
【選 課 清 單】</font></div><table border="1" align="center" cellspacing="0" cellpa
dding="4" width="100%" bgcolor="#cccccc" bordercolor="#999999" bordercolordark="w
hite"><tr align=center bgcolor=\'#ebebeb\'><td align=\'left\' nowrap><font style=\
'font-style: normal; font-variant: normal; font-weight: normal; font-size: 9pt; font-family: 細明體\'>選課代號:</font></td><td
def course(cont):
"""Parse raw kuas ap course data
Return:
parse data: json
have_saturday: bool
have_sunday: bool
except_text: string
"""
root = etree.HTML(cont)
try:
center = root.xpath("//center")[0]
center_text = list(center.itertext())[0]
except:
center = ""
center_text = ""
# Return if no course data
if center_text.startswith(u'學生目前無選課資料!'):
return [[], False, False, center_text]
tbody = root.xpath("//table")[-1]
course_table = {}
for r_index, r in enumerate(tbody[1:]):
row = {}
for index, c in enumerate(r.xpath("td")):
r = list(filter(lambda x: x != u"\xa0", c.itertext()))
if index == 0:
row['time'] = r[0].replace(" ", "")
else:
row[index] = {
"course_name": "",
"course_teacher": "",
"course_classroom": ""
}
if r:
while len(r) < 3:
r.append("")
row[index]["course_name_simple"] = r[0][:2]
row[index]["course_name"] = r[0]
row[index]["course_teacher"] = r[1]
row[index]["course_classroom"] = r[2]
course_table[r_index] = row
# Check if over 8th didn't have class
token_b = False
token_night = False
for r in course_table:
for c in course_table[r]:
if r > 9 and c != "time" and course_table[r][c]['course_name']:
if r == 10:
token_b = True
else:
#print(course_table[r][c]['course_name'])
token_night = True
#print(token_b, token_night)
if token_night:
pass
elif token_b:
for i in [11, 12, 13, 14]:
del course_table[i]
else:
for i in [10, 11, 12, 13, 14]:
del course_table[i]
# Check Saturday and Sunday class
have_saturday = False
have_sunday = False
for r in course_table:
if not isinstance(course_table[r], bool) and course_table[r][6]["course_name"]:
have_saturday = True
if not isinstance(course_table[r], bool) and course_table[r][7]["course_name"]:
have_sunday = True
return [course_table, have_saturday, have_sunday, False]
>>> r = s.post("http://localhost:5000/ap/query",
... data={"fncid": "ag222", "arg01": "103", "arg02": "01"}
... )
>>> r.text
'[{"0": {"1": {"course_name": "", "course_teacher": "", "course_c...
e.g. Submit Leave or Submit Bus?
session.post('http://bus.kuas.edu.tw/API/Reserves/add',
data="{busId:"+ kid +"}",
headers=headers,
proxies=proxies
)
def init(session):
global js
#session.get('http://bus.kuas.edu.tw/', headers=headers, proxies=proxies)
session.head("http://bus.kuas.edu.tw")
js = execjs.compile(
js_function + session.get('http://bus.kuas.edu.tw/API/Scripts/a1',
headers=headers,
proxies=proxies
).content
)
data['n'] = js.call('loginEncryption', str(uid), str(pwd))
ap_query_key = qid +
hashlib.sha512(
str(username) +
str(args) +
SERECT_KEY
).hexdigest()
ag2221b8d45dd7722324855941fe59dc8c29c74f7a83a22518
f54bea2d2b2cdcd61251121b7cb252d5d960b105757ec
4a2d855a3906e0698e003a54080f5b628d1bd5
if not red.exists(ap_query_key):
ap_query_content = parse.parse(qid, ap.query(session, qid, args))
red.set(ap_query_key, json.dumps(ap_query_content))
red.expire(ap_query_key, AP_QUERY_EXPIRE)
else:
ap_query_content = json.loads(red.get(ap_query_key))
轉換到 Ionic UI framework
Meda Queries
.course-table button {
@extend .button-light;
border: 0px;
width: 100%;
}
.course-prompt-saturday, .course-prompt-sunday {
margin-bottom: -13px;
}
@media screen and (max-width: 360px) {
.course-table button {
height: 40px;
min-width: 40px;
}
.course-table-saturday {
display: none;
}
}
@media screen and (max-width: 430px) {
.course-table-sunday {
display: none;
}
}
css with superpowers
$link-color-blue: #0f0fff
$link-font-size: 16px
.header a
color: $link-color-black
font-size: $link-font-size
.menu a
color: $link-color-blue
font-size: $link-font-size
$link-color-blue: #0f0fff
$link-font-size: 16px
.header a
color: $link-color-black
font-size: $link-font-size * 2
.menu a
color: $link-color-blue
font-size: $link-font-size * 0.8
.base-table {
border-collapse: separate;
border-spacing: 0;
border: 2px solid #CCC;
border-radius: 5px;
-moz-border-radius: 5px;
margin: 0px auto;
margin-top: 20px;
width: 90%;
}
.course-table {
@extend .base-table
width: 100%;
font-size: 20px;
}
打造一個受歡迎的成功 app,最關鍵的三大部分是:
- Perfectly executing the wrong plan Tomer Sharon
http://www.inside.com.tw/2014/07/29/googles-6-reasons-why-people-do-not-use-your-app
Louie Lu
grapherd@gmail.com