【问题标题】:Why is this Python code not catching KeyboardInterrupts?为什么这个 Python 代码没有捕捉到 KeyboardInterrupts?
【发布时间】:2018-09-09 01:27:50
【问题描述】:

首先,我查看了所有其他解决方案。我已经确保我的 IDE/Editor (Atom) 没有捕获输入。我查看了是否有任何代码笨拙地阻止了 Ctrl-C。我用过 time.sleep、signal、threads,随你便。我无法弄清楚为什么发送 Ctrl-C 不会停止我的 Python 程序(但通过 Activity Monitor 将其杀死)。这是代码

from user_data_manager import DataManager
from get_data import SkywardDataManager
from getpass import getpass
from typing import Dict, List, Any
import time
def get_diff(new_grades: Dict[str, Any], old_grades: Dict[str, Any]) -> Dict[str, Any]:
    difference = {} #type: Dict[str, List[Dict[str, str]]]

    for class_name in new_grades.keys():
        if class_name in old_grades.keys():
            new_grade_list = new_grades[class_name]
            old_grade_list = old_grades[class_name]
            diff = [
                item
                for item in new_grade_list if item not in old_grade_list
            ]
            difference[class_name] = diff
    return difference

def print_grade_diff(grades: SkywardDataManager, student: DataManager) -> None:
    new_grades = grades.get_grades()
    old_grades = student.load()
    diff = get_diff(new_grades, old_grades)
    student.write(new_grades)
    print(diff)

def main() -> None:
    default_conf = {
        "username": "",
        "password": ""
    }
    dm = DataManager("./conf.json", def_obj=default_conf)
    data = dm.load()

    username = data["username"]
    password = data["password"]

    GDM = None
    while True:
        try:
            if username == "" or password == "":
                username = input("Skyward username: ")
                password = getpass("Skyward password: ")
            GDM = SkywardDataManager(username, password)
            break
        except ValueError:
            print("Incorrect username or password, please try again.")
            username = input("Skyward username: ")
            password = getpass("Skyward password: ")
        except KeyboardInterrupt:
            print("Hellow")

    sdm = DataManager("./grades/{0}.json".format(username))
    print_grade_diff(GDM, sdm)


old_time = 0
while True:
    try:
        new_time = time.time()
        if new_time - old_time > 5*60:
            print("running")
            old_time = time.time()
            main()
    except KeyboardInterrupt:
        print("Hello")
        still_going = False
        exit

user_data_manager 只是我用来与 JSON 文件交互的一段代码,get_data.py 看起来像这样

from requests_html import HTMLSession, HTML
import getpass
import os
from user_data_manager import DataManager
from typing import Dict, List, Any

session = HTMLSession()

base_url = "https://skyward.iscorp.com/scripts/wsisa.dll/WService=wseduoakparkrfil"
login_url = base_url + "/skyporthttp.w"

def parse_login_text(text: str) -> Dict[str, Any]:
    text = text.replace("<li>", "").replace("</li>", "")

    values = text.split("^")

    new_url = base_url + "/" + values[7]
    encses = values[14]
    data = {
        "params": {
            "dwd": values[0],
            "web-data-recid": values[1],
            "wfaacl-recid": values[2],
            "wfaacl": values[3],
            "nameid": values[4],
            "duserid": values[5],
            "User-Type": values[6],
            "enc": values[13],
            "encses": encses
        },
        "new_url": new_url,
        "encses": values[14]
    }
    return data

class SkywardDataManager():
    def __init__(self, usern: str, passw: str) -> None:
        self.username = usern
        self.password = passw
        data = self.login()
        self.login_data = data

    def login(self) -> Dict[str, Any]:
        req_dm = DataManager("./default_request_conf.json")
        params = req_dm.load()
        params["codeValue"] = self.username
        params["login"] = self.username
        params["password"] = self.password
        req = session.post(login_url, data=params)
        text = req.text
        if "Invalid" in text:
            raise ValueError("Incorrect username or password")
        return parse_login_text(text)

    def get_session_params(self) -> Dict[str, str]:
        ldata = self.login_data

        req2 = session.post(ldata["new_url"], data=ldata["params"])
        page = req2.html

        sessid = page.find("#sessionid", first=True).attrs["value"]

        encses = page.find("#encses", first=True).attrs["value"]

        return {
            "sessid": sessid,
            "encses": encses
        }

    def get_grades(self) -> Dict[str, List[Dict[str, str]]]:
        grade_url = base_url + "/sfgradebook001.w"
        sessionp = self.get_session_params()
        req3 = session.post(grade_url, data={
            "encses": sessionp["encses"],
            "sessionid": sessionp["sessid"]
        })
        new_text = req3.text
        new_text = new_text.replace(
            "src='",
            "src='{0}/".format(base_url)
        ).replace(
            "href='",
            "href='{0}/".format(base_url)
        )
        '''
            Replacing values here to make sure that all requests
            are being made to the skyward site and not the local
            computer.
        '''

        new_html = HTML(html=new_text)
        with open("./page.html", "w") as f:
            f.write(new_html.html)
        new_html.render()
        i = 1

        grades = {} # type: Dict[str, List[Dict[str, str]]]
        tr_with_rownum = list(
            filter(
                lambda elem: "data-rownum" in elem.attrs.keys(),
                new_html.find("tr")
            )
        )
        current_class = ""

        while True:
            elems = list(
                filter(
                    lambda elem: elem.attrs["data-rownum"] == str(i),
                    tr_with_rownum
                )
            )
            if elems == []:
                break # No more assignments/classes
            i += 1
            elems_text = list(
                map(
                    lambda elem: elem.text,
                    elems
                )
            )
            if "Period" in elems_text[1] and "Due:" not in elems_text[1]:
                # This represents a class row
                current_class = elems_text[1].split("\n")[0]
                overall_grades = elems_text[0].split("\n")
                grades[current_class] = []
                semester1_grades = overall_grades[0:4]
                # Semester 1 is the first 4 Grades
                # Q1, Q2, EX1, SM1
                semester2_grades = overall_grades[4:]
                #Semester 2 is the last 4 Grades
                # Q3, Q4, EX2, SM2
                quarter_grades = [] # type: List[str]
                exam_grades = [] # type: List[str]
                semester_grades = [] # type: List[str]
                if len(semester1_grades) == 4:
                    quarter_grades += semester1_grades[:-2]
                    exam_grades += semester1_grades[-2]
                    semester1_grades += semester1_grades[-1]
                else:
                    quarter_grades += semester1_grades[:-1]
                    exam_grades = None
                    semester_grades += semester1_grades[-1]
                if len(semester2_grades) == 4:
                    quarter_grades += semester2_grades[:-2]
                    exam_grades += semester2_grades[-2]
                    semester1_grades += semester2_grades[-1]
                elif len(semester2_grades) > 0:
                    quarter_grades += semester2_grades[:-1]
                    semester_grades += semester2_grades[-1]
                for num, grade in enumerate(quarter_grades):
                    grades[current_class].append({
                        "Quarter {0}".format(num+1): grade
                    })
                for num, grade in enumerate(semester_grades):
                    grades[current_class].append({
                        "Semester {0}".format(num+1): grade
                    })
                if exam_grades != None:
                    for num, grade in enumerate(exam_grades):
                        grades[current_class].append({
                            "Exam {0}".format(num+1): grade
                        })

            else:
                # This represents an assignment
                assignment_name = elems_text[1].split("\n")[0]
                grade = elems_text[0]
                if assignment_name != "Next 4...":
                    grades[current_class].append({
                        assignment_name: grade
                    })

        return grades

我不明白为什么 get_data 或 main 中的某些内容会干扰捕获 SIGINT,但我不是专家。为什么我不能退出我的代码?

编辑:如果有帮助,我可以在 main() 打印之前完美退出,但在我无法退出之后。

【问题讨论】:

  • 也许exit 应该是exit(),所以它实际上做了什么?
  • @jasonharper 是的,但即使替换它,过程仍然没有退出。
  • 另一个except KeyboardInterrupt: 在一个无限循环中,所以如果这就是Ctrl-C 被抓住的地方,它就无处可去。如果您真的希望它结束​​程序,为什么还要捕获此异常?
  • 如果你必须在一个内部循环中捕获KeyboardInterrupt,那么你需要再次raise它,而不是扔掉它!但我怀疑这实际上是解决潜在问题的方法,不管它可能是什么。

标签: python python-3.x python-requests web-crawler sigint


【解决方案1】:

我尝试在 IDLE 中使用 KeyboardInterrput 进行测试,它完美地引发了 KeyboardInterrupt。如果真的不适合你,我建议你使用其他管理热键的方式。

编辑:KeyboardInterrpu 出现时出现,但无法被 except 语句检测到。最可能的原因可能是 KeyboardInterrupt 不是从 BaseException 继承的,BaseException 具有允许捕获错误的编码。希望这可以帮助!

【讨论】:

  • 你怎么能运行它?如果我能正确分析我自己的代码,应该没有足够的代码让它运行......
  • 我刚刚明白你的意思。我想我试图在没有尝试的情况下检测 KeyboardInterrupt 并且 KeyboardInterrupt 出现了。
猜你喜欢
  • 2021-07-25
  • 1970-01-01
  • 2019-05-16
  • 2021-08-08
  • 2017-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
相关资源
最近更新 更多