Implemented washinsa parser in python
This commit is contained in:
		
							parent
							
								
									4cbc13dd01
								
							
						
					
					
						commit
						6a072cb4e2
					
				
					 8 changed files with 321 additions and 181 deletions
				
			
		
							
								
								
									
										102
									
								
								__examples__/washinsa.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								__examples__/washinsa.json
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,102 @@ | ||||||
|  | { | ||||||
|  |   "dryers": [ | ||||||
|  |     { | ||||||
|  |       "number": "1", | ||||||
|  |       "state": "DISPONIBLE", | ||||||
|  |       "startTime": "", | ||||||
|  |       "endTime": "", | ||||||
|  |       "donePercent": "", | ||||||
|  |       "remainingTime": "" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "2", | ||||||
|  |       "state": "EN COURS", | ||||||
|  |       "startTime": "15:24", | ||||||
|  |       "endTime": "15:59", | ||||||
|  |       "donePercent": "62.9", | ||||||
|  |       "remainingTime": "13" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "3", | ||||||
|  |       "state": "TERMINE", | ||||||
|  |       "startTime": "", | ||||||
|  |       "endTime": "", | ||||||
|  |       "donePercent": "", | ||||||
|  |       "remainingTime": "" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "washers": [ | ||||||
|  |     { | ||||||
|  |       "number": "4", | ||||||
|  |       "state": "EN COURS", | ||||||
|  |       "startTime": "\u00a0", | ||||||
|  |       "endTime": "\u00a0", | ||||||
|  |       "donePercent": "", | ||||||
|  |       "remainingTime": "0" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "5", | ||||||
|  |       "state": "EN COURS", | ||||||
|  |       "startTime": "15:35", | ||||||
|  |       "endTime": "16:15", | ||||||
|  |       "donePercent": "26.9", | ||||||
|  |       "remainingTime": "29" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "6", | ||||||
|  |       "state": "DISPONIBLE", | ||||||
|  |       "startTime": "", | ||||||
|  |       "endTime": "", | ||||||
|  |       "donePercent": "", | ||||||
|  |       "remainingTime": "" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "7", | ||||||
|  |       "state": "EN COURS", | ||||||
|  |       "startTime": "15:34", | ||||||
|  |       "endTime": "16:19", | ||||||
|  |       "donePercent": "26", | ||||||
|  |       "remainingTime": "33" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "8", | ||||||
|  |       "state": "DISPONIBLE", | ||||||
|  |       "startTime": "", | ||||||
|  |       "endTime": "", | ||||||
|  |       "donePercent": "", | ||||||
|  |       "remainingTime": "" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "9", | ||||||
|  |       "state": "DISPONIBLE", | ||||||
|  |       "startTime": "", | ||||||
|  |       "endTime": "", | ||||||
|  |       "donePercent": "", | ||||||
|  |       "remainingTime": "" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "10", | ||||||
|  |       "state": "DISPONIBLE", | ||||||
|  |       "startTime": "", | ||||||
|  |       "endTime": "", | ||||||
|  |       "donePercent": "", | ||||||
|  |       "remainingTime": "" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "11", | ||||||
|  |       "state": "DISPONIBLE", | ||||||
|  |       "startTime": "", | ||||||
|  |       "endTime": "", | ||||||
|  |       "donePercent": "", | ||||||
|  |       "remainingTime": "" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "number": "12", | ||||||
|  |       "state": "EN COURS", | ||||||
|  |       "startTime": "15:02", | ||||||
|  |       "endTime": "15:47", | ||||||
|  |       "donePercent": "97.7", | ||||||
|  |       "remainingTime": "1" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
|  | @ -1 +0,0 @@ | ||||||
| {"dryers":[{"number":"1","state":"DISPONIBLE","startTime":"","endTime":"","donePercent":"","remainingTime":""},{"number":"2","state":"EN COURS","startTime":"15:24","endTime":"15:59","donePercent":"62.9","remainingTime":"13"},{"number":"3","state":"TERMINE","startTime":"","endTime":"","donePercent":"","remainingTime":""}],"washers":[{"number":"4","state":"EN COURS","startTime":"\u00a0","endTime":"\u00a0","donePercent":"","remainingTime":"0"},{"number":"5","state":"EN COURS","startTime":"15:35","endTime":"16:15","donePercent":"26.9","remainingTime":"29"},{"number":"6","state":"DISPONIBLE","startTime":"","endTime":"","donePercent":"","remainingTime":""},{"number":"7","state":"EN COURS","startTime":"15:34","endTime":"16:19","donePercent":"26","remainingTime":"33"},{"number":"8","state":"DISPONIBLE","startTime":"","endTime":"","donePercent":"","remainingTime":""},{"number":"9","state":"DISPONIBLE","startTime":"","endTime":"","donePercent":"","remainingTime":""},{"number":"10","state":"DISPONIBLE","startTime":"","endTime":"","donePercent":"","remainingTime":""},{"number":"11","state":"DISPONIBLE","startTime":"","endTime":"","donePercent":"","remainingTime":""},{"number":"12","state":"EN COURS","startTime":"15:02","endTime":"15:47","donePercent":"97.7","remainingTime":"1"}]} |  | ||||||
|  | @ -1,179 +0,0 @@ | ||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * Wash-INSA PARSER |  | ||||||
|  * This program get all information about the laundry |  | ||||||
|  * Author : Gabin NOBLET (Promo 55) |  | ||||||
|  * Date : 07/2019 |  | ||||||
|  * Version 1.0 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /**Get Type of machines (1 for dryers, 2 for washers, 0 else) |  | ||||||
|  * @param $str (string) |  | ||||||
|  * @return int |  | ||||||
|  */ |  | ||||||
| function mType($str) |  | ||||||
| { |  | ||||||
|     $a = explode(' ', $str); |  | ||||||
|     if (substr($a[0], -5) == "SECHE") { |  | ||||||
|         return 1; |  | ||||||
|     } elseif (substr($a[0], -4) == "LAVE") { |  | ||||||
|         return 2; |  | ||||||
|     } else { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**Get Status of machines (1 for available, 2 for current, 3 for finished, 0 for out of order) |  | ||||||
|  * @param $node (DOMNode) |  | ||||||
|  * @return int |  | ||||||
|  */ |  | ||||||
| function mStatus($node) |  | ||||||
| { |  | ||||||
|     $a = explode(' ', $node[2]->nodeValue); |  | ||||||
|     if (substr($a[0], -10) == "DISPONIBLE") { |  | ||||||
|         return 1; |  | ||||||
|     } elseif (substr($a[0], -7) == "TERMINE") { |  | ||||||
|         return 3; |  | ||||||
|     } elseif (isset($node[4])) {   //If there is time information, it is current
 |  | ||||||
|         return 2; |  | ||||||
|     } else { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Clean strings (removes spaces, tabs end return before and behind the string) |  | ||||||
|  * @param $str (string) |  | ||||||
|  * @return string |  | ||||||
|  */ |  | ||||||
| function clean($str) |  | ||||||
| { |  | ||||||
|     return rtrim(ltrim(htmlspecialchars_decode($str))); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function generateJson() |  | ||||||
| { |  | ||||||
|     $page = new DOMDocument(); |  | ||||||
|     $page->loadHTMLFile("https://www.proxiwash.com/weblaverie/ma-laverie-2?s=cf4f39&16d33a57b3fb9a05d4da88969c71de74=1"); //Get page
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     $division = $page->getElementById("liste-machines"); |  | ||||||
|     $liste_machines = $division->childNodes[0]->childNodes; |  | ||||||
| 
 |  | ||||||
| //Remove titles
 |  | ||||||
|     $titles = $liste_machines->item(0); |  | ||||||
|     $titles->parentNode->removeChild($titles); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     $return = array( |  | ||||||
|         'dryers' => array(), |  | ||||||
|         'washers' => array() |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     foreach ($liste_machines as $machines) { |  | ||||||
| 
 |  | ||||||
|         $specs = $machines->childNodes; |  | ||||||
| 
 |  | ||||||
|         //Format array
 |  | ||||||
|         $template = array( |  | ||||||
|             'number' => "", |  | ||||||
|             'state' => "", |  | ||||||
|             'startTime' => "", |  | ||||||
|             'endTime' => "", |  | ||||||
|             'donePercent' => "", |  | ||||||
|             'remainingTime' => "" |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         //Get info from HTML
 |  | ||||||
|         $specsArray = array(); |  | ||||||
|         foreach ($specs as $info) { |  | ||||||
|             if (isset($info->tagName)) { |  | ||||||
|                 if ($info->tagName == "td") { |  | ||||||
|                     array_push($specsArray, $info); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         //Get Type
 |  | ||||||
|         $type = mType(clean($specsArray[0]->nodeValue)); |  | ||||||
| 
 |  | ||||||
|         //Get Number
 |  | ||||||
|         preg_match('/\d{1,2}/', $specsArray[1]->nodeValue, $number); |  | ||||||
|         $template['number'] = $number[0]; |  | ||||||
| 
 |  | ||||||
|         //Get Status and DonePercent
 |  | ||||||
|         $status = mStatus($specsArray); |  | ||||||
|         switch ($status) { |  | ||||||
|             case 1: |  | ||||||
|                 $template['state'] = "DISPONIBLE"; |  | ||||||
|                 break; |  | ||||||
|             case 2: |  | ||||||
|                 $template['state'] = "EN COURS"; |  | ||||||
|                 foreach ($specsArray[2]->childNodes as $child) { |  | ||||||
|                     if (isset($child->tagName)) { |  | ||||||
|                         if ($child->tagName == "table") { |  | ||||||
|                             $progressBar = $child->childNodes[0]->childNodes[0]; |  | ||||||
|                             if ($progressBar->getAttribute('bgcolor') == "Green") { |  | ||||||
|                                 $template['donePercent'] = substr($progressBar->getAttribute('width'), 0, -1); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
|             case 3: |  | ||||||
|                 $template['state'] = "TERMINE"; |  | ||||||
|                 break; |  | ||||||
|             default : |  | ||||||
|                 $template['state'] = "HORS SERVICE"; |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if ($template['state'] === "EN COURS") { // We set Times only when they could exist
 |  | ||||||
|             //Get StartTime
 |  | ||||||
|             $template['startTime'] = $specsArray[4]->nodeValue; |  | ||||||
|             //Get EndTime
 |  | ||||||
|             $template['endTime'] = $specsArray[5]->nodeValue; |  | ||||||
|             $template['remainingTime'] = get_remaining_time($template['startTime'], $template['endTime'], $template['donePercent']); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if ($type == 1) { |  | ||||||
|             array_push($return['dryers'], $template); |  | ||||||
|         } elseif ($type == 2) { |  | ||||||
|             array_push($return['washers'], $template); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
| //    echo "<pre>";
 |  | ||||||
| //    echo "Type : ".$type."\n" ;
 |  | ||||||
| //    print_r($template);
 |  | ||||||
| //    echo "</pre>";
 |  | ||||||
|     } |  | ||||||
|     $jsonData = json_encode($return); |  | ||||||
|     file_put_contents('washinsa.json', $jsonData); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Get remaining time for the current machine |  | ||||||
|  * |  | ||||||
|  * @param $startTime |  | ||||||
|  * @param $endTime |  | ||||||
|  * @return string |  | ||||||
|  */ |  | ||||||
| function get_remaining_time($startTime, $endTime, $percentDone) |  | ||||||
| { |  | ||||||
|     $startArray = explode(':', $startTime); |  | ||||||
|     $endArray = explode(':', $endTime); |  | ||||||
| 
 |  | ||||||
|     $unixStart = mktime($startArray[0], $startArray[1], 0, 1, 0); |  | ||||||
|     $unixEnd = mktime($endArray[0], $endArray[1], 0, 1, 0); |  | ||||||
| 
 |  | ||||||
|     if ($unixStart > $unixEnd) { // Machine ends the following day
 |  | ||||||
|         $unixEnd = mktime($endArray[0], $endArray[1], 0, 1, 1); |  | ||||||
|     } |  | ||||||
|     $deltaMinutes = ($unixEnd - $unixStart)/60; |  | ||||||
|     $remainingTime = $deltaMinutes * (1 - $percentDone/100); |  | ||||||
|     return strval(round($remainingTime, 0)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| generateJson(); |  | ||||||
							
								
								
									
										218
									
								
								washinsa/washinsa_handler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								washinsa/washinsa_handler.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,218 @@ | ||||||
|  | # Parser made with BeautifulSoup4 | ||||||
|  | # https://www.crummy.com/software/BeautifulSoup/bs4/doc | ||||||
|  | 
 | ||||||
|  | from bs4 import BeautifulSoup | ||||||
|  | import urllib.request | ||||||
|  | from enum import Enum, auto | ||||||
|  | import pprint | ||||||
|  | import re | ||||||
|  | import json | ||||||
|  | 
 | ||||||
|  | ''' | ||||||
|  | PAGE STRUCTURE | ||||||
|  | as of june 2020 | ||||||
|  | 
 | ||||||
|  | A table with a row (tr html tag) for each machine | ||||||
|  | Each machine row is composed of 6 columns | ||||||
|  |  - 1 - Type ("SECHE LINGE 14 KG" or "LAVE LINGE 6 KG") | ||||||
|  |  - 2 - Number ("No X" with X the current number) | ||||||
|  |  - 3 - Status (A string showing the status or a table showing the progress) | ||||||
|  |  - 4 - Program (Name of the program or empty) | ||||||
|  |  - 5 - Start time (The start time in format HH:MM or empty) | ||||||
|  |  - 6 - End time (The end time in format HH:MM or empty) | ||||||
|  | ''' | ||||||
|  | 
 | ||||||
|  | DUMP_FILE = "washinsa_data.json" | ||||||
|  | WASHINSA_URL = "https://www.proxiwash.com/weblaverie/component/weblaverie/?view=instancesfiche&format=raw&s=cf4f39" | ||||||
|  | DRYER_STRING = "SECHE LINGE" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class State(Enum): | ||||||
|  |     AVAILABLE = 0 | ||||||
|  |     RUNNING = 1 | ||||||
|  |     RUNNING_NOT_STARTED = 2 | ||||||
|  |     FINISHED = 3 | ||||||
|  |     UNAVAILABLE = 4 | ||||||
|  |     ERROR = 5 | ||||||
|  |     UNKNOWN = 6 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Table used to convert state string given by the page into State enum | ||||||
|  | STATE_CONVERSION_TABLE = { | ||||||
|  |     "DISPONIBLE": State.AVAILABLE, | ||||||
|  |     "TERMINE": State.FINISHED, | ||||||
|  |     "HORS SERVICE": State.UNAVAILABLE, | ||||||
|  |     "ERREUR": State.ERROR, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TIME_RE = re.compile("^\d\d:\d\d$") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def download_page(): | ||||||
|  |     """ | ||||||
|  |     Downloads the page from proxiwash website | ||||||
|  |     """ | ||||||
|  |     try: | ||||||
|  |         with urllib.request.urlopen(WASHINSA_URL) as response: | ||||||
|  |             return response.read().decode() | ||||||
|  |     except: | ||||||
|  |         print("Error processing following url: " + WASHINSA_URL) | ||||||
|  |         return "" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_rows(soup): | ||||||
|  |     """ | ||||||
|  |     Gets rows corresponding to machines on the page | ||||||
|  |     """ | ||||||
|  |     rows = soup.table.contents | ||||||
|  |     del rows[0] | ||||||
|  |     return rows | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def is_machine_dryer(row): | ||||||
|  |     """ | ||||||
|  |     Checks if the given machine is a dryer. If it is not, it means it is a washer. | ||||||
|  | 
 | ||||||
|  |     To check this, we look if the test string is included in the state string | ||||||
|  |     """ | ||||||
|  |     return DRYER_STRING in row.contents[0].text | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_machine_number(row): | ||||||
|  |     """ | ||||||
|  |     Gets the current machine number. | ||||||
|  | 
 | ||||||
|  |     To find it, we look in the Number cell and remove the "No" prefix to keep only the number. | ||||||
|  |     We do not rely on the index in the list as it could get lost in parsing. | ||||||
|  |     Plus, this method allows for non numeric machine identifiers. | ||||||
|  |     """ | ||||||
|  |     return row.contents[1].text.split()[1] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_machine_state(row): | ||||||
|  |     """ | ||||||
|  |     Gets the current machine state. | ||||||
|  | 
 | ||||||
|  |     The state is usually written in plain text inside the State cell. | ||||||
|  |     In this case, we simply check it against the state translation table, | ||||||
|  |     to turn it into a State Enum, which is easier to manipulate. | ||||||
|  | 
 | ||||||
|  |     In some cases, this plain text is replace by a progress bar. | ||||||
|  |     This the machine is running. | ||||||
|  | 
 | ||||||
|  |     If the state string cannot be recognized, this returns the unknown state. | ||||||
|  |     """ | ||||||
|  |     content = row.contents[2].contents[0] | ||||||
|  |     state = State.UNKNOWN | ||||||
|  |     if content.name == "table": | ||||||
|  |         state = State.RUNNING | ||||||
|  |     else: | ||||||
|  |         for key in STATE_CONVERSION_TABLE: | ||||||
|  |             if key in content.text: | ||||||
|  |                 state = STATE_CONVERSION_TABLE[key] | ||||||
|  |                 break | ||||||
|  |     return state | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_machine_program(row): | ||||||
|  |     """ | ||||||
|  |     Gets the machine program as written in plain text in the Program cell | ||||||
|  |     """ | ||||||
|  |     return row.contents[3].text.strip() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_machine_times(row): | ||||||
|  |     """ | ||||||
|  |     Gets the start and end time for the machine. | ||||||
|  | 
 | ||||||
|  |     If one of these times is invalid (does not respect the HH:MM format), an empty string is returned | ||||||
|  |     """ | ||||||
|  |     start_time = row.contents[4].text | ||||||
|  |     end_time = row.contents[5].text | ||||||
|  |     if TIME_RE.match(start_time) and TIME_RE.match(end_time): | ||||||
|  |         return start_time, end_time | ||||||
|  |     else: | ||||||
|  |         return "", "" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_machine_done_percent(row): | ||||||
|  |     """ | ||||||
|  |     Gets the machine done percentage. | ||||||
|  | 
 | ||||||
|  |     This percent is given in the width property of the first column, in the table inside the State cell. | ||||||
|  |     This only applies if the machine is running. | ||||||
|  |     """ | ||||||
|  |     content = row.contents[2].contents[0] | ||||||
|  |     percent = "" | ||||||
|  |     if content.name == "table": | ||||||
|  |         percent = content.td["width"].replace("%", "") | ||||||
|  |         if float(percent) > 100:  # because the website is not doing this check... | ||||||
|  |             percent = '100' | ||||||
|  |     return percent | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_machine_remaining_time(row): | ||||||
|  |     """ | ||||||
|  |     Gets the remaining time in minutes. | ||||||
|  | 
 | ||||||
|  |     The time is written in the title property of the table inside the State cell. | ||||||
|  |     It is written inside a phrase, so we need to extract it. | ||||||
|  |     This only applies if the machine is running. | ||||||
|  |     """ | ||||||
|  |     content = row.contents[2].contents[0] | ||||||
|  |     time = 0 | ||||||
|  |     if content.name == "table": | ||||||
|  |         time = content["title"].split("=")[1].split()[0] | ||||||
|  |     return time | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_parsed_data(rows): | ||||||
|  |     """ | ||||||
|  |     Gets the parsed data from the web page, farmatting it in a easy to use object | ||||||
|  |     """ | ||||||
|  |     dryers = [] | ||||||
|  |     washers = [] | ||||||
|  |     for row in rows: | ||||||
|  |         state = get_machine_state(row) | ||||||
|  |         machine = { | ||||||
|  |             "number": get_machine_number(row), | ||||||
|  |             "state": state.value, | ||||||
|  |             "startTime": "", | ||||||
|  |             "endTime": "", | ||||||
|  |             "donePercent": "", | ||||||
|  |             "remainingTime": "", | ||||||
|  |             "program": "", | ||||||
|  |         } | ||||||
|  |         if state == State.RUNNING: | ||||||
|  |             machine_times = get_machine_times(row) | ||||||
|  |             machine["startTime"] = machine_times[0] | ||||||
|  |             machine["endTime"] = machine_times[1] | ||||||
|  |             if len(machine_times[0]) == 0: | ||||||
|  |                 state = State.RUNNING_NOT_STARTED | ||||||
|  |                 machine["state"] = state.value | ||||||
|  |             machine["program"] = get_machine_program(row) | ||||||
|  |             machine["donePercent"] = get_machine_done_percent(row) | ||||||
|  |             machine["remainingTime"] = get_machine_remaining_time(row) | ||||||
|  | 
 | ||||||
|  |         if is_machine_dryer(row): | ||||||
|  |             dryers.append(machine) | ||||||
|  |         else: | ||||||
|  |             washers.append(machine) | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |         "dryers": dryers, | ||||||
|  |         "washers": washers | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def main(): | ||||||
|  |     soup = BeautifulSoup(download_page(), 'html.parser') | ||||||
|  |     rows = get_rows(soup) | ||||||
|  |     with open(DUMP_FILE, 'w') as f: | ||||||
|  |         json.dump(get_parsed_data(rows), f) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | main() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| #!/bin/bash | #!/bin/bash | ||||||
| 
 | 
 | ||||||
| touch lock | touch lock | ||||||
| php index.php | python3 washinsa_handler.py > log 2> err | ||||||
| rm lock | rm lock | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue