› Sviluppare funzionalita su Microsoft Office con VBA › Importare dati in tabella excel da una pagina web
-
AutoreArticoli
-
Salve, in questi giorni ho avuto un po di tempo per riprendere sottomano questo codice e rifilarlo per applicarlo appieno all'applicazione che voglio realizzare.
Ho subito aggiustato questo:
For Each tdtd In trtr.Cells Cells(i + 1, j + 1) = tdtd.innertext j = j + 1 Next tdtdin questo:
For Each tdtd In trtr.Cells Cells(i + 1, j + 1) = Trim(tdtd.innertext) j = j + 1 Next tdtdcosì da rimuovere eventuali spazi posti prima e dopo la stringa estratta.
Poi ho diviso la Sub in tante Sub, ognuna che estragga un singolo elemento ad esempio SUB REGIA(), dove sto perfezionando opportunamente l'estrazione del regista, pulendolo da spazi e colonne che non mi interessano; idem per CAST, Musiche, Ecc.
Mi sono però imbattuto in un problema nell'estrazione di Produzione e Distribuzione che si trovano ad un'altra pagina e non sembrano strutturate in TABLE come nella precedente.
Questo il link: https://www.imdb.com/title/tt0227445/companycredits
La struttura sembrerebbe suddivisa in modo diverso da gruppi "tr" e "td" ma in gruppi "li" che non so gestire perché non conosco il codice html. Di seguito quello che ho provato a fare ma sono tentativi a vuoto senza realmente capire ciò che sto facendo:
Sub Produzione() 'dichiarazione delle variabili e loro tipizzazione Dim IE As Object ' un oggetto web browser che punta a un sito Dim i As Long, j As Long, kk As Long ' variabili contatori di supporto Dim myColl As Variant ' contiene il contenuto della pagina internet Dim myItm As Variant ' ogni elemento di sezione dentro la pagina internet Dim myURL As String ' indirizzo internet da raggiungere Dim trtr As Variant, tdtd As Variant ' riferimenti alle righe delle tabelle della pagina internet Dim sections As Variant ' qui sono contenuti i titoli delle diverse sezioni, ' che poi saranno filtrati dalla costante iniziale Const TITLES As String = "Production" 'la costante TITLES serve da filtro per le sezioni da recuperare 'imposta internet l'indirizzo da raggiungere myURL = "https://www.imdb.com/title/tt0227445/companycredits" 'crea l'oggetto internet explorer Set IE = CreateObject("InternetExplorer.Application") 'legge il contenuto della pagina internet 'e lo assegna alla variabile IE '(metodo classico) With IE .Navigate myURL .Visible = True Do While .Busy: DoEvents: Loop 'Attesa not busy Do While .ReadyState <> 4: DoEvents: Loop 'Attesa documento End With 'imposta un riferimento all'insieme degli elementi con tag H4 della pagina internet Set sections = IE.Document.getElementsbyTagName("H4") 'si posiziona sul foglio Excel desiderato per riversarvi i dati 'e cancella la zona usata in precedenza Application.Goto Sheets("Importa_Produzione").Range("A1") ActiveSheet.UsedRange.Clear 'imposta un riferimento all'insieme degli elementi della sezione TABLE del documento 'e scorre ogni elemento per recuperarne il contenuto desiderato 'se il testo della sezione è contenuto nella costante TITLES 'di ogni elemento, poichè è memorizzata come tabella, 'scorre riga per riga e ne ricava il testo, che inserisce nel foglio Excel 'in una riga dedicata, indentando a partire dalla colonna A in avanti i = 0 kk = 0 Set myColl = IE.Document.getElementsbyTagName("UL") For Each myItm In myColl If contains(TITLES, sections(kk).innertext, ",") Then i = i + 1 Cells(i, "A").Value = sections(kk).innertext For Each trtr In myItm.Rows For Each tdtd In trtr.Cells Cells(i + 1, j + 1) = Trim(tdtd.innertext) j = j + 1 Next tdtd i = i + 1: j = 0 Next trtr i = i + 2 End If kk = kk + 1 Next myItm 'operazioni finali Range("A1").Select ActiveSheet.UsedRange.WrapText = False 'esce dall'applicazione internet e distrugge l'oggetto in memoria IE.Quit Set IE = Nothing MsgBox "Finito!" End SubHo provato a cambiare TABLE in UL ma qualcosa ancora non va, e son sicuro che bisogna strutturare opportunamente il ciclo for che dovrebbe diventare da doppio a singolo.
Chiedo quindi nuovamente aiuto a voi. Grazie a tutti per l'attenzione.
I tag li e ul identificano gli elenchi puntati e numerati (vado a memoria). Possono stare dentro una tabella e quindi dentro una cella quindi non toglierei il riferimento nè a table nè a td e tr. Sarebbe il caso di verificare cosa restituisce Trim(tdtd.innertext) ed eventualmente splittare il risultato in corrispondenza dei relativi codici ascii che identificano l'elenco.
In pratica se lascio TABLE, mi restituisce i valori presenti in fondo alla pagina internet, mentre se sostituisco TABLE con UL mi da errore di runtime 438: Proprietà o metodo non supportati dall'oggetto, bloccandosi a
For Each trtr In myItm.RowsQuindi non riesco ad analizzare il Trim, in quanto il codice si blocca prima.
Purtroppo ho carenza di nozioni sia sul html sia sul vba per capire dove sta l'inghippo... sicuramente è una sciocchezza... ma non ci arrivo da solo.
Più sopra hai passato il link, spero di avere un attimo stasera per buttarci un occhio. Spero di poter esserti utile ma devo vedere in pratica cosa abbiamo
Grazie infinite per il tuo tempo... se ci sarà modo di potermi sdebitare, lo faro!
Un aiutino? Non riesco proprio.
Questo funziona sulla pagina indicata, ma su altre?
Option Explicit Sub ProduzioneDistribuzione() 'dichiarazione delle variabili e loro tipizzazione Dim IE As Object ' un oggetto web browser che punta a un sito Dim i As Long, j As Long, kk As Long ' variabili contatori di supporto Dim myColl As Variant ' contiene il contenuto della pagina internet Dim myItm As Variant ' ogni elemento di sezione dentro la pagina internet Dim myURL As String ' indirizzo internet da raggiungere Dim trtr As Variant, tdtd As Variant ' riferimenti alle righe delle tabelle della pagina internet Dim sections As Variant, section As Variant ' qui sono contenuti i titoli delle diverse sezioni, ' che poi saranno filtrati dalla costante iniziale Dim v As Variant Const TITLES As String = "Production,Distributors" 'la costante TITLES serve da filtro per le sezioni da recuperare 'imposta internet l'indirizzo da raggiungere myURL = "https://www.imdb.com/title/tt0227445/companycredits" 'crea l'oggetto internet explorer Set IE = CreateObject("InternetExplorer.Application") With IE .Navigate myURL .Visible = True Do While .Busy: DoEvents: Loop 'Attesa not busy Do While .ReadyState <> 4: DoEvents: Loop 'Attesa documento End With Set sections = IE.Document.getElementsbyTagName("H4") Application.Goto Sheets("Importa_Produzione").Range("A1") ActiveSheet.UsedRange.Clear i = 0 kk = 0 j = 2 Set myColl = IE.Document.getElementsbyTagName("UL") For Each myItm In Array(myColl(14), myColl(15)) For Each section In sections If kk = 0 Or kk = 12 Then Debug.Print kk i = i + 1 Cells(i, "A").Value = section.innertext For Each v In Split(myItm.innertext, vbLf) Cells(i + 1, j) = v i = i + 1 Next j = j + 1 End If kk = kk + 1 Next section Next myItm 'operazioni finali Range("A1").Select ActiveSheet.UsedRange.WrapText = False 'esce dall'applicazione internet e distrugge l'oggetto in memoria IE.Quit Set IE = Nothing MsgBox "Finito!" End SubCiao Vecchio Frac, grazie, funziona alla grande anche su altre pagine del sito relative a Produzione e Distribuzione.
In sostanza la pagina in questione è strutturata diversamente, chissà perché!
Adesso, con qualche piccolo aggiustamento di codice, e una UserForm creata su misura per la cosa, potrò completare il mio "Progettino Filmografia Personale".
Ci tengo a ringraziarti davvero per l'aiuto che mi hai dato, e ringrazio anche il creatore del sito e tutto lo staff che aiuta giornalmente persone come me che si affacciano per le prime volte alla programmazione VBA.
Un grazie di cuore a tutti e alla prossima.
Grazie a te per il feedback.
Vorrei invitarti a studiarti bene il codice per capire cosa fa, riga per riga. Se hai domande, falle senza scrupoli. Il punto è che non ci sarà sempre qualcuno disposto, in futuro, a riprendere in mano del codice scritto da altri (come questo) e quindi per eventuali aggiustamenti o nuove integrazioni dovrai essere in grado di metterci le mani.
Ho iniziato l'anno nuovo dichiarando che avrei fatto più didattica e meno codice, in questa discussione però (iniziata nel 2018) ho voluto comunque terminare il lavoro sia per non lasciarti a piedi 🙂 che perchè effettivamente è stato abbastanza sfidante 😉
Giusto! Fare didattica, come anche i tuoi commenti riga per riga al codice passato, mi hanno aiutato molto.
Sulla vecchia versione del forum, ero registrato con altro nick, ed ho chiesto altre volte il vostro aiuto, per altri piccoli progettini, proponendo sempre o quasi del codice di partenza; ho sempre visto invece molte volte, che la gente non ama applicarsi ed imparare, ma chiede "quasi" che gli venga dato del codice "bello e pronto" per i loro progetti, e questo a mio avviso non è molto bello, soprattutto per voi. Quindi, ti quoto al 100% sul: + didattica e - codice!
Devo studiare il ciclo, e capire bene cosa fa... anche perché vedo un "Array" e un "Split", che non mastico bene ancora (e già qualche lieve spiegazione non mi farebbe male); comunque li cerco sul libro, ci studio un po, mi faccio anche un debug passo-passo per vedere esattamente cosa avviene sul foglio, e se qualcosa non mi è chiara, torno di sicuro a chiedere lumi.
N.b.: Molto probabilmente, separerò la tua sub in due parti, una per la Produzione, e una per la Distribuzione... giusto per comodità di cose nell'ambito in cui la voglio applicare!
ero registrato con altro nick
Ah bene, e chi eri?
For Each myItm In Array(myColl(14), myColl(15))Array crea un insieme di elementi al cui interno poter effettuare operazioni, come nell'esempio in un ciclo For, ad ogni esecuzione del ciclo la variabile contatore assume il valore di ogni elemento nell'array. L'istruzione Array accetta qualsiasi tipo di dato, così Array(1, 3.5, "stringa", #15/01/2019#) raggruppa un intero, un numero con virgola, una stringa di testo e una data. Il primo elemento di un Array ha indice zero.
For Each v In Split(myItm.innertext, vbLf)Split prende una stringa di testo e un delimitatore (se omesso è sottinteso il carattere spazio), e restituisce un array composto da tutti elementi della stringa che sono divisi dal delimitatore. Per esempio,
v = Split("uno per tutti-tutti per uno", " ")restituisce un Array composto da 5 elementi numerati da zero a 4, per cui v(0) è il primo elemento e vale "uno" e v(2) è il terzo elemento e vale "tutti-tutti". Peròv = Split("uno per tutti-tutti per uno", "-")ora separa la stringa al trattino per cui la variabile avrà solo due elementi: v(0) = "uno per tutti" e v(1) = "tutti per uno".Nell'esempio di cui sopra, il testo di myItm.innertext viene suddiviso in tanti pezzettini in corrispondenza dei ritorni a capo (vbLf = Linefeed) e ognuno viene assegnato alla variabile del ciclo v.
Il contrario di Split, che serve invece ad unire gli elementi di un Array, è Join.
Grazie per le tue spiegazioni, chiare ed esaustive. Per la tua prima domanda, e chi legge mi scuserà, ma ti rispondo in privato
.Per la tua prima domanda
Per carità, rispetto la tua privacy e se non vuoi fa niente 😀
-
AutoreArticoli
