import requests
import json
import time
import random
import os
from lxml import etree

csrftoken = os.environ["csrftoken"]
sessionid = os.environ["sessionid"]


def get_data(zxjxjhh, zc, jxlh, jash, page):
    base_url = "https://aa.bjtu.edu.cn/classroom/timeholdresult/room_view/"
    params = {
        "zxjxjhh": zxjxjhh,
        "zc": zc,
        "jxlh": jxlh,
        "jash": jash,
        "submit": "+%E6%9F%A5+%E8%AF%A2+",
        "has_advance_query": "",
        "page": page,
    }
    headers = {
        "User-Agent": "Mozilla/5.0 (Linux; Android 10; Mi 10 Build/QKQ1.191215.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.106 Mobile Safari/537.36",
    }
    cookies = {
        "csrftoken": csrftoken,
        "sessionid": sessionid,
    }
    r = requests.get(base_url, params=params, headers=headers, cookies=cookies)
    return r


color2status_table = {
    "#e46868": "有课",
    "#d8cc56": "社团",
    "#77bf6d": "实验",
    "#394ed6": "考试",
}


def color2status(style: str):
    color = style.split(":")[1].strip()
    if color in color2status_table:
        return color2status_table[color]
    else:
        return "空闲"


desired_buildings = [
    {"name": "思源", "id": "1"},
    {"name": "思西", "id": "2"},
    {"name": "思东", "id": "3"},
    {"name": "九教", "id": "4"},
    {"name": "逸夫", "id": "11"},
]


if __name__ == "__main__":
    results = []
    for building in desired_buildings:
        building_name = building["name"]
        building_id = building["id"]
        for week in range(26):  # 周次
            for page in range(1, 1000):
                req = get_data("2023-2024-1-2", week + 1, building_id, "", page)
                html = etree.HTML(req.text)
                succ = False
                print(f"fetching {building_name} week {week+1} page {page}")
                for classroom in range(20):
                    for day in range(7):
                        for peroid in range(7):
                            try:
                                classroom_name_path = f"/html/body/div[2]/div[2]/div/div[2]/table/tr[{classroom+3}]/td[1]/text()"
                                classroom_name = html.xpath(classroom_name_path)[
                                    0
                                ].strip()
                            except:
                                break

                            classroom_capacity_path = f"/html/body/div[2]/div[2]/div/div[2]/table/tr[{classroom+3}]/td[1]/span/text()"
                            classroom_capacity = html.xpath(classroom_capacity_path)
                            # remove left and right brackets
                            classroom_capacity = classroom_capacity[0][1:-1]

                            # /html/body/div[2]/div[2]/div/div[2]/table/tr[3]/td[2]
                            # /html/body/div[2]/div[2]/div/div[2]/table/tr[3]/td[2]/@style
                            status_path = f"/html/body/div[2]/div[2]/div/div[2]/table/tr[{classroom+3}]/td[{day*7+peroid+2}]/@style"
                            color = html.xpath(status_path)[0]
                            status = color2status(color)

                            item = {
                                "building": building_name,
                                "classroom": classroom_name,
                                "capacity": classroom_capacity,
                                "week": week + 1,
                                "day": day + 1,
                                "time": peroid + 1,
                                "status": status,
                            }
                            if item not in results:
                                results.append(item)
                                succ = True
                            # sleep for a while
                if succ == False:
                    break

            # time.sleep(random.randint(0, 100) / 1000)

    # save to json file
    with open("data.json", "w") as f:
        json.dump(results, f)
        
    # save to csv file
    with open("data.csv", "w") as f:
        f.write("building,classroom,capacity,week,day,time,status\n")
        for item in results:
            f.write(
                f"{item['building']},{item['classroom']},{item['capacity']},{item['week']},{item['day']},{item['time']},{item['status']}\n"
            )

1.fetch-data.py
GhostCai/bjtu-classroom
from flask import Flask
from flask_restful import Resource, Api
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address


app = Flask(__name__)
api = Api(app)
limiter = Limiter(
    get_remote_address,
    app=app,
    default_limits=["10/minute", "50 per hour"],
    storage_uri="memory://",
)

import json
import time

lookup = {
    '上午1':1,
    '上午2':2,
    '中午':3,
    '下午1':4,
    '下午2':5,
    '晚上1':6,
    '晚上2':7
}
with open("data.json", "r") as f:
    data = json.load(f)

open_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
class Classroom(Resource):
    def get(self, building, week, day, start, end):
        # Read the JSON file
        start = lookup[start]
        end = lookup[end]

        if start > end:
            return ['开始时间不能大于结束时间']  + [''] + ['🚀 caiziqi.com']
        #print(start,end)

        # Filter the data based on the query parameters
        result = []
        vis = []
        cnt = {}
        for item in data:
            if item["building"] == building and item["week"] == week and item["day"] == day and item["time"] >= start and item["time"] <= end and item["status"] == "空闲":
                if item['classroom'] in cnt:
                    cnt[item['classroom']] += 1
                else:
                    cnt[item['classroom']] = 1
                if cnt[item["classroom"]] == end-start+1:
                    vis.append(item['classroom'])
                    result.append(item)

        # Return the filtered data as JSON
        rooms_sorted = sorted(result, key=lambda x: x["classroom"])
        return  [f"{x['classroom']}({x['capacity']})" for x in rooms_sorted] + [''] + [f'Last Updated {open_time}']

api.add_resource(Classroom, "/classroom/<string:building>/<int:week>/<int:day>/<string:start>/<string:end>")

app.run(host='0.0.0.0',port=8888)

2.app.py
GhostCai/bjtu-classroom