Unofficial Python API for alerts (updates) in ZJU Blackboard (c.zju.edu.cn).
This repo is consist of two parts: ZJU Blackboard API (zju_blackboard.py) and a full demo program of fetching alerts and convert them into Things (an macOS to-do app) entries (blackboard2things.py).
This API is not official. Use at your own risk. MIT License.
This demo fetches alerts and convert them into Things (an macOS to-do app) entries. To use it directly, macOS and Things 3 is required.
Change config.py before your use (See below for login parameters ENCODED_PW
, ENCODED_PW_UNICODE
, LOGIN_UID_UNICODE
, LOGIN_PWD_UNICODE
, and you may want to change DOWNLOAD_PATH
and COURSE_CODE_TO_NAME
as well.)
pip3 install -r requirements.txt
python3 blackboard2things.py
Download zju_blackboard.py. See requirements.txt for dependencies (py_applescript is not required, only for blackboard2things.py).
from zju_blackboard import *
s = ZJUBlackboardSession()
s.login(ENCODED_PW, ENCODED_PW_UNICODE, LOGIN_UID_UNICODE, LOGIN_PWD_UNICODE) # see below for these parameters
entries = s.get_raw_entries() # fetch all alerts (updates) in list of JSON objects
alerts = s.process_raw_entries(entries) # process raw JSON objects into alert objects
for alert in alerts:
# Do something
These parameters come from post request at login page (c.zju.edu.cn). Use your favourite tool to extract them. For example, in Safari:
For all event types, the following fields are available:
alert["title"]
: title of alertalert["course_id"]
: id of course, such as_4069_1
alert["url"]
: content url without base_url (https://c.zju.edu.cn). Maybe empty for some type of alertalert["event"]
: one of the following"content:available"
"course:available"
"announcement:available"
"grade:update"
"grade:manual_update"
"grade:overdue"
"assignment:available"
"assignment:due_available"
(showing "due" on blackboard, but I think it means due time available)"test:available"
"test:due_available"
"unknwon"
(unhandled type)
alert["dismiss_id"]
: ID to be fed todismiss_alert()
alert["exception"]
:None
if the alert is processed normally. String of exception if error happenedalert["raw"]
: original JSON entry
For specific event types:
- For
alert["event"] == "content:available"
alert["content_type"]
: one of the following"file"
: a single file. For this type of content, there is an additional field:alert["file_url"]
: url to the file, which can be fed todownload_file()
"document"
: a document with content and possibly attachments. For this type of content, there is an additional field:alert["doc_inner_url"]
: url for the document, which can be fed tointerpret_document()
.
"blank"
: blank page (but actually may not). Please view the original page on BB."media"
: media page. Please view the original page on BB."forum_link"
: formu link. Please view the original page on BB."video"
: BB video. Please view the original page on BB."unknown"
: unhandled content type.
- For
alert["event"] == "announcement:available"
- (Possibly, or
None
)alert["announcement"]
: content of announcement (text of unescaped HTML).
- (Possibly, or
- For
alert["event"] == "assignment:due_available"
alert["assignment"]
: name of assignment
- For
alert["event"] == "assignment:available"
alert["assignment"]
: name of assignmentalert["assignment_inner_url"]
: url to the assignment page, which can be fed tointerpret_assignment_page()
- For
alert["event"] == "grade:update"
alert["grade"]
: name of graded item
s.dismiss_alert(alert["dismiss_id"])
The alert will no longer shown on the website either.
downloaded, filename, size = s.download_file(alert["file_url"], DOWNLOAD_PATH, MAXIMAL_DOWNLOAD_SIZE)
# filename may not be the finalized one (thorugh redirecting) if download is canceled due to oversize
interpret_document()
further looks into content of document and return a directory (or None
if failed) with the following two fields:
doc_data["text"]
: content of the document page (text of unescaped HTML)doc_data["attachments"]
: list of attachment urls if any, which can be fed todownload_file()
if alert["content_type"] == "document":
doc_data = s.interpret_document(alert["doc_inner_url"])
if doc_data is not None:
document_content = doc_data["text"]
for download_url in doc_data["attachments"]:
s.download_file(download_url, DOWNLOAD_PATH)
interpret_assignment_page()
furthers look into content and return a directory (or None
if failed) with the following two fields:
assignment_data["text"]
: content of the assignment page (text of unescaped HTML)assignment_data["attachments"]
: list of attachment urls if any, which can be fed todownload_file()
if alert["event"] == "assignment:available":
assignment_data = p.interpret_assignment_page(alert["assignment_inner_url"])
if assignment_data is not None:
assignment_content = assignment_data["content"]
for attachment in assignment_data["attachments"]:
s.download_file(attachment, DOWNLOAD_PATH)
- Both py program output debug message to STDERR.