Forum >> Principianti >> Problemi stampa messaggio formattato con web scraping

Pagina: 1

Salve a tutti,
Premetto che quello che sto pubblicando è un frammento di codice di uno dei miei primi programmi python, quindi abbiate pietà di me se scritto male. Il codice in questione è il seguente:
from bs4 import BeautifulSoup
import requests

url = f"https://mrbs.dmi.unipg.it/day.php?year=2024&month=09&day=04&area=1&room=3"
response = requests.get(url) #invia una richiesta http all'indirizzo link
cont = response.text #codice html della pagina

if(response.status_code == 200): # vuol dire che il server ha risposto con successo alla richiesta http:
    soup = BeautifulSoup(cont, 'html.parser') 

    date = soup.find("div", id="dwm").get_text(strip=True) #restituisce il testo del tag div con id=dwm, cioè giorno, mese e anno
    table = soup.find("table", class_ = "dwm_main") #restituisce il testo html del tag table e dei sotto tag, cioè di tutta la tabella degli orari
    cells = soup.find_all("td") #lista di tutte le celle
    rows = table.find_all("tr") #lista di tutte le righe della tabella

    header = rows[ 0 ]  #testo html della prima riga della tabella, cioè intestazione
    headers = [header.get_text(strip=True) for header in header.find_all("th")] #lista con testo dell'intestazione

    contents = []
    for row in rows[1:]: 
        row_contents = [content.get_text(strip=True) for content in row.find_all("td")] #lista con testo di ogni cella
        if any(row_contents[1:]): #ignora le celle vuote
            contents.append(row_contents) #lista con il testo delle celle non vuote

    rooms = [content[ 0 ] for content in contents] #aule
    times = headers[1:] #ore

    message = ""
    for i in range(len(rooms)):
        message += f"Aula: {rooms}\n"
        for j in range(1, len(times) + 1):  # Partiamo da 1 per saltare la colonna delle aule
            if j < len(contents[ i ]) and contents[ i ][ j ]:
                message += f"🔹 {times[ j-1 ]}: {contents[ i ][ j ]}\n"
        message += "\n"
    print(message)
else:
    print("Errore nella richiesta HTTP:", response.status_code)

Quindi sto accendo ad una pagina (pubblica) della mia università (che potete vedere aprendo il link presente nel codice), la quale contiene l'organizzazione delle lezioni, ossia i vari orari, le varie lezioni (con i prof.) che si tengono in quel giorno e in quale aule e quali orari occupano. Attraverso BeautifulSoup sto cercando di estrarre proprio queste informazioni, cioè orari, lezioni e aule, che mi serviranno poi per creare un messaggio formattato che verrà stampato per mostrare le aule in cui si tengono delle lezioni (ignorando quelle in cui non vi è alcuna lezione), le lezioni che si tengono in quelle aule e a quale ora iniziano. Solo un esempio (da non seguire per forza) di come vorrei venisse è il seguente:
Aula: A0(180)
09:00: Architettura degli elaboratoriAlfredo Navarra
14:00 Esame Programmazione Procedurale con Lab.Francesco Santini

Aula: A2(180)
09:00: Esame Rossi (Discreta - Geometria)F. A. Rossi

Aula: B3(35)
09:00: Esami orali di Fisica Matematica 1 e Mathematical Physics 2Francesca Di Patti

#da quel che ho visto, penso che il nome del prof non si riesca a staccare dalla materia

Bene, il codice che ho pubblicato funziona correttamente senza errori, la difficoltà sta nell'ottenere il messaggio desiderato, perchè non riesco ad allineare correttamente gli orari con le lezioni in modo corretto, infatti alcune lezioni non corrispondono agli orari giusti.

Quindi, se qualche buon anima mi potesse aiutare perchè ci sto veramente perdendo la testa. Naturalmente è ben accetto qualsiasi consiglio di modifica del codice.

Grazie mille in anticipo.
Buonagiornata.


--- Ultima modifica di Martinello in data 2024-08-19 10:09:28 ---
Ciao @Martinello

Premetto che la programmazione web e lo scraping in se non mi hanno mai interessato, quindi neanche conosco beautifulsoup, perciò prendimi con le molle e perdona eventuali caz...e eventualmente presenti.
Sfruttando il Tuo codice in una sessione idle, e considerando che in una tabella html una cella viene espansa su più colonne tramite la proprietà "colspan" ho ritenuto, per risolvere il problema orari, di manipolare il Tuo codice originale calcolando la colonna della cella con testo interessante e lo span relativo, la soluzione con output nel sottostante blocco di codice mi sembra risolva il quesito :
Python 3.10.12 (main, Jul 29 2024, 16:56:4 8) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license()" for more information.
from bs4 import BeautifulSoup
import requests
url = f"https://mrbs.dmi.unipg.it/day.php?year=2024&month=09&day=04&area=1&room=3"
response = requests.get(url)
cont = response.text
soup = BeautifulSoup(cont, 'html.parser')
table = soup.find("table", class_ = "dwm_main")
rows = table.find_all("tr")
headers = [header.get_text(strip=True) for header in rows0.find_all("th")]
headers
['Sala:', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00']
messages = []
for r in rows[1:]:
    msg = ''
    tds = [x for x in r.find_all('td')]
    room = f'Aula: {tds[0].get_text(strip=True)}\n'
    col = 1
    for cell in tds[1:]:
        if cell.get_text(strip=True):
            stime = headers[col]
            if not msg: msg += room
            if 'colspan' in cell.attrs:
                span = int(cell['colspan'])
                etime = headers[col + span - 1]
                col += span - 1
            else:
                etime = '     '
            msg += f'🔹 {stime} - {etime} : {cell.get_text(strip=True)}\n'
        col += 1
    if msg: messages.append(msg)

    
print(''.join(messages))
Aula: A0(180)
🔹 09:00 - 10:00 : Architettura degli elaboratoriAlfredo Navarra
🔹 14:00 - 18:00 : Esame Programmazione Procedurale con Lab.Francesco Santini
Aula: A2(180)
🔹 09:00 - 12:00 : Esame Rossi (Discreta - Geometria)F. A. Rossi
Aula: B3(35)
🔹 09:00 - 16:00 : Esami orali di Fisica Matematica 1 e Mathematical Physics 2Francesca Di Patti

Le variabili stime ed etime servono per individuare l'indice da leggere negli headers, collspan viene letto dagli attributi dell'oggetto "td" in esame (vedere documentazione "attrs" di beartiful; la logica applicata mi sembra abbastanza semplice ma se hai dubbi, chiedi

Riguardo al nome dell'insegnante appiccicato all'esame, ho estratto il contenuto di una riga con voci valide lette
<td class="I" colspan="2">
<div class="celldiv slots1" data-id="101857">
<a href="view_entry.php?id=101857&amp;area=1&amp;day=4&amp;month=9&amp;year=2024" title="Corso di Laurea Informatica I Anno
E' un esame
Architettura degli elaboratori">Architettura degli elaboratori</a><sub style="color:blue;font-size:xx-small">Alfredo Navarra</sub>
</div>
</td>
<td class="I" colspan="5">
<div class="celldiv slots1" data-id="101642">
<a href="view_entry.php?id=101642&amp;area=1&amp;day=4&amp;month=9&amp;year=2024" title="Corso di Laurea Informatica I Anno
E' un esame
">Esame Programmazione Procedurale con Lab.</a><sub style="color:blue;font-size:xx-small">Francesco Santini</sub>
</div>
</td>

Qualora il formato sia costante si potrebbe separare il titolo dell'esame da quello del docente, analizzando i tags "a" e "sub", un po' troppo macchinoso per una sessione ifle, però.


Fai sapere, ciao

EDIT : corretti artefatti dell'editor




--- Ultima modifica di nuzzopippo in data 2024-08-20 17:11:28 ---
Fatti non foste a viver come bruti...
Ciao @Martinello

Premetto che la programmazione web e lo scraping in se non mi hanno mai interessato, quindi neanche conosco beautifulsoup, perciò prendimi con le molle e perdona eventuali caz...e eventualmente presenti.
Sfruttando il Tuo codice in una sessione idle, e considerando che in una tabella html una cella viene espansa su più colonne tramite la proprietà "colspan" ho ritenuto, per risolvere il problema orari, di manipolare il Tuo codice originale calcolando la colonna della cella con testo interessante e lo span relativo, la soluzione con output nel sottostante blocco di codice mi sembra risolva il quesito :
Python 3.10.12 (main, Jul 29 2024, 16:56:4  8) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license()" for more information.
from bs4 import BeautifulSoup
import requests
url = f"https://mrbs.dmi.unipg.it/day.php?year=2024&month=09&day=04&area=1&room=3"
response = requests.get(url)
cont = response.text
soup = BeautifulSoup(cont, 'html.parser')
table = soup.find("table", class_ = "dwm_main")
rows = table.find_all("tr")
headers = [header.get_text(strip=True) for header in rows0.find_all("th")]
headers
['Sala:', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00']
messages = []
for r in rows[1:]:
    msg = ''
    tds = [x for x in r.find_all('td')]
    room = f'Aula: {tds[0].get_text(strip=True)}\n'
    col = 1
    for cell in tds[1:]:
        if cell.get_text(strip=True):
            stime = headers[col]
            if not msg: msg += room
            if 'colspan' in cell.attrs:
                span = int(cell['colspan'])
                etime = headers[col + span - 1]
                col += span - 1
            else:
                etime = '     '
            msg += f'🔹 {stime} - {etime} : {cell.get_text(strip=True)}\n'
        col += 1
    if msg: messages.append(msg)

    
print(''.join(messages))
Aula: A0(180)
🔹 09:00 - 10:00 : Architettura degli elaboratoriAlfredo Navarra
🔹 14:00 - 18:00 : Esame Programmazione Procedurale con Lab.Francesco Santini
Aula: A2(180)
🔹 09:00 - 12:00 : Esame Rossi (Discreta - Geometria)F. A. Rossi
Aula: B3(35)
🔹 09:00 - 16:00 : Esami orali di Fisica Matematica 1 e Mathematical Physics 2Francesca Di Patti

Le variabili stime ed etime servono per individuare l'indice da leggere negli headers, collspan viene letto dagli attributi dell'oggetto "td" in esame (vedere documentazione "attrs" di beartiful; la logica applicata mi sembra abbastanza semplice ma se hai dubbi, chiedi

Riguardo al nome dell'insegnante appiccicato all'esame, ho estratto il contenuto di una riga con voci valide lette
<td class="I" colspan="2">
<div class="celldiv slots1" data-id="101857">
<a href="view_entry.php?id=101857&amp;area=1&amp;day=4&amp;month=9&amp;year=2024" title="Corso di Laurea Informatica I Anno
E' un esame
Architettura degli elaboratori">Architettura degli elaboratori</a><sub style="color:blue;font-size:xx-small">Alfredo Navarra</sub>
</div>
</td>
<td class="I" colspan="5">
<div class="celldiv slots1" data-id="101642">
<a href="view_entry.php?id=101642&amp;area=1&amp;day=4&amp;month=9&amp;year=2024" title="Corso di Laurea Informatica I Anno
E' un esame
">Esame Programmazione Procedurale con Lab.</a><sub style="color:blue;font-size:xx-small">Francesco Santini</sub>
</div>
</td>

Qualora il formato sia costante si potrebbe separare il titolo dell'esame da quello del docente, analizzando i tags "a" e "sub", un po' troppo macchinoso per una sessione ifle, però.


Fai sapere, ciao

EDIT : corretti artefatti dell'editor




--- Ultima modifica di nuzzopippo in data 2024-08-20 17:11:28 ---
Ti ringrazio veramente tanto per la disponibilità e per l'aiuto, finalmente seguendo la tua logica ho risolto il problema. Grazie mille ancora, veramente.


Pagina: 1



Esegui il login per scrivere una risposta.