Java - operazioni su un campionato

di il
6 risposte

Java - operazioni su un campionato

Salve a tutti, è la prima volta che posto, spero non ci siano altre discussioni simili a questa (nel caso chiedo perdono).

Mi piacerebbe sviluppare un programma in Java (è il linguaggio con cui me la cavo meglio) che, prese in input una serie di partite con relativi risultati di un campionato di calcio, faccia dei semplici calcoli come i gol fatti/subiti da una determinata squadra, l'andamento, le medie gol e altre statistiche correlate.

A questo punto mi sorge un dubbio: come gestisco la memorizzazione delle partite?
Mi spiego: potrei memorizzare i dati in un db, o anche su semplici file excel essendo dati poco complessi, soluzione che ho testato e che funziona, ma che comunque è fastidiosa perché mi obbliga ad aggiornare manualmente i file di volta in volta. Mi domandavo se esistesse un modo per averli in maniera automatica, evitandomi di fare l'amanuense, magari scaricandoli da qualche sito (ad esempio diretta.it) che come attività gestisce questi dati. Come potrei fare?

Grazie in anticipo a chi mi aiuterà!

6 Risposte

  • Re: Java - operazioni su un campionato

    Se vuoi un modo per memorizzare i dati in maniera da poter poi leggerli e rielaborarli da un programma io sconsiglierei un file excel, che è relativamente difficile da trattare (anche se esistono librerie per interagire con excel, JExcel e Apache POI ad esempio).

    Un database dovrebbe andare bene, io personalmente non li ho ancora mai usati con Java, ma penso vadano bene anche file più semplici (anche csv o semplici file di testo), eventualmente dividendo le diverse statistiche su più file, che andranno poi rielaborati.

    Un'altra cosa è come vuoi presentare in seguito i dati, un file excel è comodo da vedere e da modificare a mano, un po' meno con Java (ma si può fare tranquillamente penso), potresti usare anche un'interfaccia grafica, una pagina web o un'altra soluzione.

    E' importante però trovare un modo per reperire i dati in rete senza dover aggiornarli continuamente, questo di sicuro.
    Sostanzialmente hai bisogno di un programma che scarichi una pagina web, o un altro tipo di risorsa con i dati, vada a prendere le informazioni interessanti, e successivamente le elabori.

    Scaricare una pagina web di base è una cosa molto semplice, bastano poche righe di codice, la cosa ovviamente si complica se la risorsa non è direttamente accessibile da tutti ma serve effettuare prima un login, immettere una password o altro.

    Prendere le informazioni interessanti può essere la parte più difficile: ci sono vari modi (tra cui l'uso delle espressioni regolari), ma se trovi una pagina web abbastanza incasinata non è affatto immediato venirne a capo, e soprattutto non hai la certezza che il programma funzioni sempre, perché non sai se la pagina cambierà il modo di esporre i dati in futuro.
    Per fare un esempio, scaricando la pagina dei risultati di diretta.it, ti trovi di fronte a qualcosa del genere:
    
    A000¬ZCC÷0¬ZAF÷Italia¬~AA÷djl6NmRO¬AD÷1503859500¬ADE÷1503859500¬AB÷3¬CR÷3¬AC÷3¬CX÷Chievo¬ER÷Giornata 2¬RW÷0¬AX÷1¬BX÷-1¬WQ÷¬WM÷CHI¬AE÷Chievo¬WU÷chievo¬AG÷1¬BA÷1¬BC÷0¬WN÷LAZ¬AF÷Lazio¬WV÷lazio¬AS÷2¬AZ÷2¬AH÷2¬BB÷1¬BD÷1¬AW÷1¬AN÷n¬~AA÷beSlnX3P¬AD÷1503859500¬ADE÷1503859500¬AB÷3¬CR÷3¬AC÷3¬CX÷Crotone¬ER÷Giornata 2¬RW÷0¬AX÷1¬BX÷-1¬WQ÷¬WN÷VER¬AF÷Verona¬WV÷verona¬AS÷0¬AZ÷0¬AH÷0¬BB÷0¬BD÷0¬WM÷CRO¬AE÷Crotone¬WU÷crotone¬AS÷0¬AZ÷0¬AG÷0¬BA÷0¬BC÷0¬AW÷1¬AN÷n¬~AA÷04EGsiCt¬AD÷1503859500¬ADE÷1503859500¬AB÷3¬CR÷3¬AC÷3¬CX÷Fiorentina¬ER÷Giornata 2¬RW÷0¬AX÷1¬BX÷-1¬WQ÷¬WM÷FIO¬AE÷Fiorentina¬WU÷fiorentina¬AG÷1¬BA÷0¬BC÷1¬WN÷SAM¬AF÷Sampdoria¬WV÷sampdoria¬AS÷2¬AZ÷2¬AH÷2¬BB÷2¬BD÷0¬AW÷1¬AN÷n¬~AA÷8UHOuVtg¬AD÷1503859500¬ADE÷1503859500¬AB÷3¬CR÷3¬AC÷3¬CX÷Milan¬ER÷Giornata 2¬RW÷0¬AX÷1¬BX÷-1¬WQ÷¬WN÷CAG¬AF÷Cagliari¬WV÷cagliari¬AH÷1¬BB÷0¬BD÷1¬WM÷ACM¬AE÷Milan¬WU÷ac-milan¬AS÷1¬AZ÷1¬AG÷2¬BA÷1¬BC÷1¬AW÷1¬AN÷n¬~AA÷jg7Tvkda¬AD÷1503859500¬ADE÷1503859500¬AB÷3¬CR÷3¬AC÷3¬CX÷Napoli¬ER÷Giornata 2¬RW÷0¬AX÷1¬BX÷-1¬WQ÷¬WM÷NAP¬AE÷Napoli¬WU÷napoli¬AS÷1¬AZ÷1¬AG÷3¬BA÷0¬BC÷3¬WN÷ATA¬AF÷Atalanta¬WV÷atalanta¬AH÷1¬BB÷1¬BD÷0¬AW÷1¬AN÷n¬~AA÷djAywTQB¬AD÷1503859500¬ADE÷1503859500¬AB÷3¬CR÷3¬AC÷3¬CX÷Spal¬ER÷Giornata 
    
    Ho cercato per un po' di riconoscere il formato, all'inizio pensavo che il numero di gol fatti fosse il primo numero dopo il nome della squadra scritto in minuscolo, ma non è così.

    Non ho cercato molto in giro, ma ho trovato un sito che permette invece di scaricare un file csv che è tanto più facile da trattare (vedi il codice sotto).
    Ogni volta però devi stare attento al formato, e soprattutto essere consapevole che può cambiare o che qualcosa può andare storto.

    Ecco il codice:
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.URL;
    import java.util.ArrayList;
    public class TestRisultati
    {
    	public static void main (String [] args) {
    		try (BufferedReader reader = new BufferedReader (new InputStreamReader (new URL ("http://www.football-data.co.uk/mmz4281/1718/I1.csv").openStream ()))) {
    			ArrayList <String> list = new ArrayList <String> ();
    			String output = "", line, newLine = System.lineSeparator ();
    			while ((line = reader.readLine ()) != null) list.add (line);
    			for (int i = 0; i < (list.size () - 1)/ 10; i ++) {
    				output += (i + 1) + "a Giornata:" + newLine;
    				for (int j = 0; j < 10; j ++) {
    					String [] data = list.get (i * 10 + 1 + j).split (",");
    					output += newLine + data [2] + " - " + data [3] + "\t" + data [4] + ":" + data [5];
    				}
    				output += newLine + newLine;
    			}
    			System.out.println (output);
    		}
    		catch (Exception e) {
    			e.printStackTrace ();
    		}
    	}
    }
    
    Se compili ed esegui questo programma dovresti avere il seguente output:
    
    1a Giornata:
    
    Juventus - Cagliari     3:0
    Verona - Napoli 1:3
    Atalanta - Roma 0:1
    Bologna - Torino        1:1
    Crotone - Milan 0:3
    Inter - Fiorentina      3:0
    Lazio - Spal    0:0
    Sampdoria - Benevento   2:1
    Sassuolo - Genoa        0:0
    Udinese - Chievo        1:2
    
    2a Giornata:
    
    Benevento - Bologna     0:1
    Genoa - Juventus        2:4
    Roma - Inter    1:3
    Chievo - Lazio  1:2
    Crotone - Verona        0:0
    Fiorentina - Sampdoria  1:2
    Milan - Cagliari        2:1
    Napoli - Atalanta       3:1
    Spal - Udinese  3:2
    Torino - Sassuolo       3:0
    
    Come vedi dipende tutto dal tipo di risorsa che trovi, in questo caso i dati sono separati da virgole e facilmente recuperabili, ma nel codice faccio alcune assunzioni che, se non rispettate, mandano tutto all'aria: ad esempio se dovesse mancare una partita (ad esempio se venisse rinviata) non potresti più prendere le righe a blocchi di dieci, e nel file non è nemmeno presente l'indicazione della giornata, quindi non sapresti come procedere.
    Se invece il file fosse malformato, se mancassero le colonne fondamentali o peggio ci fosse una riga con meno di 6 colonne, il programma darebbe proprio errore.

    Ti consiglio quindi prima di tutto di cercare le risorse più utili, con tutte le informazioni che cerchi e che siano facili da trattare, e poi di controllare sempre il risultato, senza dare per scontato che vada tutto a buon fine
  • Re: Java - operazioni su un campionato

    Ok grazie, domani testo e ti faccio sapere.

    Però non so se ho letto di corsa e non ci ho fatto caso, ma avrei bisogno (se puoi) anche della fonte da dove prendere i csv per i dati.

    Comunque si per trattare gli excel ho usato JExcel e mi ci son trovato benissimo, ha metodi per fare qualsiasi operazione di base in modo molto semplice (lettura, scrittura ecc).
  • Re: Java - operazioni su un campionato

    Nel codice c'è l'URL del file csv, se provi ad aprirlo con un browser ti chiede direttamente se vuoi salvare il file, se lanci il programma si legge lui i dati in automatico.
    La pagina da dove l'ho trovato è invece questa.

    Come detto non ho cercato troppo in giro, se hai tempo e voglia e trovi qualcosa di meglio ben venga.

    Fammi sapere
  • Re: Java - operazioni su un campionato

    Potresti spiegarmi un po più dettagliatamente come operano i due cicli for?
  • Re: Java - operazioni su un campionato

    dome96 ha scritto:


    Potresti spiegarmi un po più dettagliatamente come operano i due cicli for?
    Certamente, riposto solo il codice coinvolto, così ce l'hai sott'occhio:
    
    for (int i = 0; i < (list.size () - 1)/ 10; i ++) {
                output += (i + 1) + "a Giornata:" + newLine;
                for (int j = 0; j < 10; j ++) {
                   String [] data = list.get (i * 10 + 1 + j).split (",");
                   output += newLine + data [2] + " - " + data [3] + "\t" + data [4] + ":" + data [5];
                }
                output += newLine + newLine;
             }
    
    Prima di tutto ricorda che list è l'ArrayList che contiene tutte le righe del file csv letto tramite BufferedReader.

    Già nella condizione del primo ciclo sto facendo una delle assunzioni di cui parlavo in precedenza: assumo che tutte le giornate siano complete, ovvero abbiano dieci partite ciascuna, quindi trovo il numero di giornate contando il numero di righe del file, sottraendo uno (la prima riga è l'intestazione) e dividendo per 10.
    Nel caso in esame quindi (21 - 1) / 10 = 2, il numero di giornate. Cosa succederebbe se mancasse una partita e quindi una riga ? Avrei (20 - 1) / 10 = 1 (sto facendo la divisione intera, non ci sono i decimali), quindi il programma già non funzionerebbe, salterei del tutto le ultime nove partite ...

    Il ciclo esterno infatti è pensato per considerare la giornata, nel ciclo annidato invece prendo le righe a blocchi di dieci, corrispondenti alle partite. Non è obbligatorio ovviamente: potrebbe esserci un unico ciclo che analizza ogni riga, e sceglie in base ai dati, o all'indice della riga, quale sia la giornata, io invece ho scelto di stampare separatamente ogni giornata dalle altre.

    Infatti la prima riga del ciclo esterno non fa altro che aggiungere alla stringa che poi stamperò a video questa informazione (ovviamente nel tuo codice "vero" non ti limiterai a stampare a video una stringa, con tutti i dati che leggi creerai i tuoi oggetti Squadra, Partita, Giornata o tutto quello che vuoi per fare le tue analisi).

    Poi inizia il ciclo interno, dove non faccio altro che prendere le dieci righe successive una per una per analizzarle.

    L'indice è i * 10 + 1 + j per un motivo molto semplice: alla prima giornata (i=0) per la prima partita (j=0) l'indice varrà 1 (ricorda sempre che la riga 0 è l'intestazione), ad ogni partita successiva si incrementa solo j, quindi vado man mano a prendere la riga dopo, appena termina il primo ciclo interno invece si passa alla seconda giornata (i=1) e inizierò a leggere dalla riga 11.

    Uso poi il metodo split della classe String, che prende in ingresso il delimitatore con il quale si vuole dividere la stringa (in questo caso la virgola) e restituisce un vettore che contiene ogni "spezzone" di stringa divisa (il delimitatore viene consumato, non resta traccia della virgola quindi).
    Quindi in data ci sarà ad ogni posizione un diverso dato della singola linea: in posizione 0 quell'I1 (nel file la prima colonna è relativa alla lega, quindi penso stia per prima serie italiana), in posizione 1 la data e così via.
    Io nell'output inserisco solo le informazioni successive, ovvero il nome delle squadre e il numero di gol segnati da ciascuna squadra, concatenando la stringa con "-" e ":" e con il carattere di a capo solo per avere una formattazione più gradevole.

    Ovviamente questo codice è pensato per estrarre le informazioni SOLO da questo tipo di file, se cambia il formato inevitabilmente cambia tutto.
    Da quella schifezza di righe che ho postato in precedenza, quelle che mi restituiva quella particolare pagina web, era ben più difficile estrarre i dati: dovevi cercare l'inizio della sequenza di partite (cerchi il tag html corrispondente, o un qualcosa che ti assicuri che stai leggendo i dati giusti) e cercare man mano le informazioni successive.
    Io ad esempio avevo scritto un'espressione regolare che cercava il nome di una squadra e una cifra che indicasse il numero di gol fatti a un dato numero di caratteri di distanza, e andava avanti finché non prendeva tutte le occorrenze.
    Quella era molto difficile da gestire, e ancora più esposta a eventuali errori.

    Quindi cerca bene quello che ti serve prima di iniziare a scrivere codice, se ti serve aiuto siamo qua
  • Re: Java - operazioni su un campionato

    Io ho sviluppato la stessa cosa.
    Non faccio altro che scaricarmi il file HTML da legaserieA.it e poi me lo lavoro con Jsoup

    Ti lascio uno stralcio di codice commentato
    
    	
     protected void storeResultAutomatically(Risultato _filmpartita){
     	LinkDB _db=new LinkDB();
     	String _linkcode=_db.getLinkCodeForUpdatingMatch(_filmpartita.getIdPartita());
     	StringBuffer htmlPage=new StringBuffer(4096);
     	Match mmat=(Match)_db.getMatch(_filmpartita.getIdPartita()).get(0);  
     	String pathFileJustCreated="";
      	boolean go=false;
    	//Provo a vedere se la pagina è già memorizzata
    	htmlPage.append(_db.getContentFromBinaryHTML(mmat.getIdmatch(), _linkcode));
    	//Se è presente
    	if(htmlPage.toString().length()>0){
    	//prendo il testo del buffer e il linkcode e creo il file temporaneo
    		pathFileJustCreated = Netlink.openStreamInFile(htmlPage.toString(), _linkcode);
    		//se il path è diverso da null
    		if(pathFileJustCreated!=null)
    	 			//Creo l'oggetto Estrattore HTML 
    			callHTMLPage(pathFileJustCreated);
    		else {
    			JOptionPane.showMessageDialog(league, "Errore nel caricamento File", "Serie A", JOptionPane.ERROR_MESSAGE);
    			return;
    		}
    	}
    	//altrimenti
    	else{
    		//pulisco il buffer da spurie
    		htmlPage.delete(0, htmlPage.length());
    		//chiamo il file INI dove c'è parte di path
    		ReadIni ini=new ReadIni();
    		//mi ricavo la giornata
    		Item itg=_db.getDayForMatch(_filmpartita.getIdPartita());
    		//creo la stringa totale URL
    		String totalUrl=ini.getLinkUploading()+itg.getGiornata()+"/"+mmat.getDenomSquadra1()+mmat.getDenomSquadra2();
    		
    		//Procedo al salvataggio/aggiornamento della pagina web scaricata(dall'interno)
    		_db.saveHTMLPageIntoDBAsFile(mmat.getIdmatch(),_linkcode,totalUrl);
    		
    		//memorizzo su buffer ciò che è stato scaricato
    		htmlPage.append(_db.getContentFromBinaryHTML(mmat.getIdmatch(), _linkcode));
    	
    		//mi ricavo l'url
    		pathFileJustCreated = Netlink.openStreamInFile(htmlPage.toString(), _linkcode);
    		//Creo l'oggetto Estrattore HTML
    		callHTMLPage(pathFileJustCreated);
    			
    	}
    	//controllo se è la pagina giusta
    	go=ext.checkPage();
    	if(go){
    		String[] tmp = ext.getScoreMatch();
    		if((!(tmp[0].equals("-"))) && (!(tmp[1].equals("-")))){
    			_filmpartita.setGol1(Integer.parseInt(tmp[0]));
    			_filmpartita.setGol2(Integer.parseInt(tmp[1]));  				
    				// cancello eventuali spurie nella tabella marcatori
    			_db.DeleteScoreMatch(_filmpartita.getIdPartita());
    			
    			UploadingResultFromHTML urf= new UploadingResultFromHTML(league, ext, _filmpartita.getIdPartita(), _filmpartita);
    			if(urf.getEndOK()){
    				frame.setRisultatoA(_row,Integer.parseInt(tmp[0]));
    				frame.setRisultatoB(_row, Integer.parseInt(tmp[1]));
    				frame.setCellRendererNumber();
    				if(pathFileJustCreated!=null){
    					try{
    						Netlink.deleteFile(_linkcode);
    					}
    					catch(java.io.IOException ioex){
    						ioex.printStackTrace();
    					}
    				}
    			}
    		}
    		//Altrimenti cancello la pagina dal DB
    		else{
    			_db.deleteHTMLPageIntoDB(mmat.getIdmatch());
    			JOptionPane.showMessageDialog(league, "Partita non ancora giocata o sospesa o altro problema", "Serie A", JOptioPane.ERROR_MESSAGE);
    		}
    	}
    	//Altrimenti cancello la pagina dal DB
    	else{
    		_db.deleteHTMLPageIntoDB(mmat.getIdmatch());
    		JOptionPane.showMessageDialog(league, "Connettivà o Pagina assente o altro problema", "Serie A", JOptionPane.ERROR_MESSAGE);
    	}
    		
    	_db.closeConnection();
      }
    
    
    

    Ovviamente questa è una piccola parte di codice (ho circa poco meno di un centinaio di classi) ma è uno dei punti centrali delle cose preliminari da fare, inoltre credo sia di facile lettura, ma mi chiedo a che livello sei per poter affrontare un lavoro del genere.
    Poi bisogna studiare come estrarre le info un documento xml perché JSoup utilizza queste impostazioni.
    Ciao
Devi accedere o registrarti per scrivere nel forum
6 risposte