diff --git a/scraper.py b/scraper.py index a8e74c8..3f7b7b9 100755 --- a/scraper.py +++ b/scraper.py @@ -4,7 +4,6 @@ ''' import argparse import os -import re import subprocess import tempfile from bs4 import BeautifulSoup @@ -22,6 +21,8 @@ help="HTML file of the workflow page") parser.add_argument("-o", dest="output", type=str, help="output file for PNG rendering with mermaid-cli (mmdc in $PATH)") +parser.add_argument("--title", dest="title", action="store_true", + help="include role and type in diagram title") args = parser.parse_args() file = args.file @@ -32,28 +33,42 @@ always = soup.find("div", {"id": "workflow_form_always"}) rows = always.find_all("tr", class_="-table-border-left") +def get_meta(): + ''' + Extracts role and type from the filter selects in the HTML. + + :return: tuple of (role, type) strings + ''' + role_select = soup.find("select", {"name": "role_id"}) + role = role_select.find("option", {"selected": "selected"}).text.strip() + type_select = soup.find("select", {"name": "type_id"}) + type_ = type_select.find("option", {"selected": "selected"}).text.strip() + return role, type_ + def get_status_text(): ''' Extracts a key value pair for each status mentioned in the HTML. As each status does have a unique ID and each row in a table contains a status, the text can be extracted from the row and get paired with the old status ID mentioned in the checkbox ID in one of the checkboxes of the row. - + :return: dictionary with status ID as key and status text as value ''' status_dict = {} for row in rows: - status_raw = row.find("td", class_="workflow-table--current-status -table-border-right") - status_text = re.sub(r'Alle in Zeile an\/abwählen',r'',status_raw.text.strip()).strip() - status_id = re.findall(r'(status_)(.*)(_[0-9]*_)', row.input['id'])[0][1] + status_cell = row.find("th", class_="workflow-table--current-status") + status_text = status_cell.find("span", class_="Truncate-text").text.strip() + # Use data-old-status from the first checkbox in the row as the status ID + first_checkbox = row.find("input", {"data-checkable-target": "checkbox"}) + status_id = first_checkbox["data-old-status"] status_dict[status_id] = status_text return status_dict def get_workflow(): ''' - Creates Mermaid formatted lines for each status change in the workflow. Uses the old and new - status information which is part of the ID string of each checkbox. - + Creates Mermaid formatted lines for each status change in the workflow. Uses data-old-status + and data-new-status attributes from each checkbox. + :return: list of Mermaid formatted strings for each status change in the workflow ''' workflow_list = [] @@ -65,32 +80,35 @@ def get_workflow(): input_field['checked'] except KeyError: continue - regex_groups = re.findall(r'(status_)([0-9]*)(_)([0-9]*)(_)', input_field['id']) - old_status = regex_groups[0][1] - new_status = regex_groups[0][3] + old_status = input_field['data-old-status'] + new_status = input_field['data-new-status'] if old_status == new_status: continue workflow_list.append(old_status + ' --> ' + new_status) return workflow_list -def print_mermaid(status_dict,workflow_list): +def print_mermaid(status_dict,workflow_list,role,type_): ''' Prints out a Mermaid state diagram for the workflow. ''' print('```mermaid') print('stateDiagram-v2') + if role and type_: + print(f' title: {role} - {type_}') for key, value in status_dict.items(): print(' ' + key + ': ' + value) for line in workflow_list: print(' ' + line) print('```') -def generate_svg(status_dict,workflow_list): +def generate_svg(status_dict,workflow_list,role,type_): ''' Output a PNG rendering of the workflow with mermaid-cli (requires mmdc in $PATH). ''' with tempfile.NamedTemporaryFile(delete=False, mode='w') as tmp: tmp.write('stateDiagram-v2\n') + if role and type_: + tmp.write(f' title: {role} - {type_}\n') for key, value in status_dict.items(): tmp.write(f' {key}: {value}\n') for line in workflow_list: @@ -102,9 +120,10 @@ def generate_svg(status_dict,workflow_list): os.remove(tmp.name) if __name__ == "__main__": + role, type_ = get_meta() if args.title else (None, None) status = get_status_text() workflow = get_workflow() if output is not None: - generate_svg(status,workflow) + generate_svg(status,workflow,role,type_) else: - print_mermaid(status,workflow) + print_mermaid(status,workflow,role,type_)