Condividi:        

Vba e Selenium doppio ciclo

Vuoi potenziare i tuoi documenti Word? Non sai come si fa una macro in Excel? Devi creare una presentazione in PowerPoint?
Oppure sei passato a OpenOffice e non sei sicuro di come lavorare al meglio?

Moderatori: Anthony47, Flash30005

Vba e Selenium doppio ciclo

Postdi Gianca532011 » 30/01/22 08:24

Ciao , il problema è questo :
ho un blocco di codice fatto con selenium che funziona correttamente MA lo devo applicare su due diversi link dello stesso sito Ilink1 e ilink2 , quindi devo creare un qualche ciclo che finita la ricerca su per es ilink1 passi alla ricerca su iLink2 , spazzolando sempre lo stesso blocco di selenium . Ho provato a mettere dei riferimenti X e Y ma o sbaglio la logica o sbaglio il sistema. Ripeto, la parte di scrping è ok. Tanto per intenderci la stessa procedura con due macro separate, dove cambia solo il link, l'ho già realizzata ed è perfettamente funzionante.
Solo che mi sto intestardendo a voler unificare in un solo codice le due procedure di interrogazione.
Uffa che fatica e sono sicuro di non essere stato chiaro a sufficienza.
Qui un esempio che funziona ma solo per uno dei due link per l'altro nisba .

https://ufile.io/109zldcb

PS in questo file le X accanto agli Isin sono da mettere manualmente , nel progetto completo vengono copiate da un'altra pagina.
e qui il codice .


Codice: Seleziona tutto
Option Explicit
Sub Aggiorna()
   
    Dim driver As New Selenium.ChromeDriver
    Dim iTables As Selenium.WebElements
    Dim Data()
    Dim ur As Long
    Dim myIsin As String
    Dim i As Integer
    Dim n As Integer
    Dim r As Long
    Dim c As Integer
    Dim bln As Boolean, bln1 As Boolean
    Dim Ws1 As Worksheet
    Dim iLink1 As String
    Dim iLink2 As String
   
    Set Ws1 = Sheets("Dati")
    Ws1.Activate
    ur = Ws1.Cells(Rows.Count, 2).End(xlUp).Row
    Range("B1:P1") = Array("Isin", "Denominazione", "Sottostante", "Facoltà", "Strike", "Scadenza", "Prezzo Rif.", "Barriera", "Categoria", _
                           "Prezzo", "Perf.da.INIZIO", "Perf.1gg", "Perf.1M", "Perf.6M", "Perf.1A")
    Ws1.Range("I2:z" & ur).Clear
   
    ' codifica come stringa
    Ws1.Range("I2:z" & ur).Select
    With Selection
        .NumberFormat = "@"
    End With
    Range("a1").Select
   
    With driver
        .Start
        '.AddArgument ("--headless")
        .Window.Maximize
       
        For i = 2 To ur
            bln = False
            myIsin = Range("B" & i)
            iLink1 = "https://www.borsaitaliana.it/borsa/cw-e-certificates/scheda/" & myIsin & ".html?lang=it"""
            iLink2 = "https://www.borsaitaliana.it/borsa/cw-e-certificates/dati-mercato.html?isin=" & myIsin & "&lang=it"

            If Ws1.Range("A" & i) = "X" Then  ' qui ho tentato mettendo degli indicatori X e Y per correlare il bln e bln1
                bln = True
                bln1 = False
               .Get iLink1
               ElseIf Ws1.Range("A" & i) = "Y" Then
               bln = False
                    bln1 = True
          .Get iLink2
End If
                    On Error Resume Next
                    driver.Manage.DeleteAllCookies
                    driver.FindElementByCss(".ccc-notify-button.ccc-tabbable.ccc-accept-button").Click
                    driver.FindElementByCss("#ccc-dismiss-button").Click
                    On Error GoTo 0
                    .Wait 1000
           
                   
                    If bln = True Or bln1 = True Then
                        Set iTables = .FindElementsByCss("table")
                        For n = 1 To iTables.Count
                            Data = iTables(n).AsTable.Data
                            For c = 1 To UBound(Data, 1)
                                For r = 1 To UBound(Data, 1)
                           
                                    If InStr(Data(r, 1), "Barriera") Then  ' link1
                                        Cells(i, 9) = Data(r, 2)
                                    End If
                       
                                    If InStr(Data(r, 1), "Categoria di Borsa") Then   ' link1
                                        Cells(i, 10).Value = Data(r, 2)
                                    End If
                                    If bln = True Then GoTo 20
                                         
                                    If InStr(Data(r, 1), "Prezzo Acquisto") Then   'link2
                                        Cells(i, 11) = Data(r, 2)
                                    End If
                         
                                    If InStr(Data(r, 1), "Performance Inizio") Then
                                        Cells(i, 12).Value = Data(r, 2)
                                    End If
                           
                                    If InStr(Data(r, 1), "Performance 1 Giorno") Then
                                        Cells(i, 13) = Data(r, 2)
                                    End If
                               
                                    If InStr(Data(r, 1), "Performance 1 mese") Then
                                        Cells(i, 14) = Data(r, 2)
                                    End If
                                    If InStr(Data(r, 1), "Performance 6 mesi") Then
                                        Cells(i, 15) = Data(r, 2)
                                    End If
                             
                                    If InStr(Data(r, 1), "Performance 1 anno") Then
                                        Cells(i, 16) = Data(r, 2)
                                    End If
20:
                                    Ws1.Range("A" & i) = "Y"
                                Next
                            Next
                        Next n
                    End If
                    Next
           
        .Quit
    End With
               
    Ws1.Range("A1").Select
   
    MsgBox ("Finito")
End Sub
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Sponsor
 

Re: Vba e Selenium doppio ciclo

Postdi Anthony47 » 30/01/22 11:19

Ma la macro l'hai scritta tu?
Se Sì, allora descrivi come lavora, quali dati vuoi prelevare da una pagina e quale dall'altra, come la macro dovrebbe lavorare in modo "anfibio" su due pagine con struttura abbastanza diversa, cosa hai ottenuto e su cosa ti sei arenato.
Se No, allora spiega direttamente quali dati vuoi prelevare dalla pagina A e quali dalla pagina B e vedremo come fare senza dover capire come un terzo ha provato a farlo.

Ciao
Avatar utente
Anthony47
Moderatore
 
Post: 19436
Iscritto il: 21/03/06 16:03
Località: Ivrea

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 30/01/22 16:22

Innanzitutto grazie per la risposta .
Si la macro è quasi tutta opera mia e l'incaglio è il seguente : dal codice vedi che ci sono due links , il primo scarica due dati da un foglio chiamato Scheda e il secondo link che corrisponde alla pagina Dati completi ne scarica altri 4 o 5 . Ora, presi a se ciascuno dei due links funziona , il mio problema è fare una sequenza che faccia due volte questo ciclo di scarico dati, una volta col link1 e una volta attivando il link2 , ma sempre sul codice sotto. Se provassi il file vedi come si comporta e cosa aggiunge e cosa no. Nota una prima parte da A ad H è fissa e viene copiata da un altro foglio.
https://postimg.cc/xcWQ9YKV/8c3c9a9b

Codice: Seleziona tutto
If bln = True Or bln1 = True Then
                        Set iTables = .FindElementsByCss("table")
                        For n = 1 To iTables.Count
                            Data = iTables(n).AsTable.Data
                            For c = 1 To UBound(Data, 1)
                                For r = 1 To UBound(Data, 1)
                           
                                    If InStr(Data(r, 1), "Barriera") Then  ' link1
                                        Cells(i, 9) = Data(r, 2)
                                    End If
                       
                                    If InStr(Data(r, 1), "Categoria di Borsa") Then   ' link1
                                        Cells(i, 10).Value = Data(r, 2)
                                    End If
                                   ' If bln = True Then GoTo 20
                                         
                                    If InStr(Data(r, 1), "Prezzo Acquisto") Then   'link2
                                        Cells(i, 11) = Data(r, 2)
                                    End If
                         
                                    If InStr(Data(r, 1), "Performance Inizio") Then
                                        Cells(i, 12).Value = Data(r, 2)
                                    End If
                           
                                    If InStr(Data(r, 1), "Performance 1 Giorno") Then
                                        Cells(i, 13) = Data(r, 2)
                                    End If
                               
                                    If InStr(Data(r, 1), "Performance 1 mese") Then
                                        Cells(i, 14) = Data(r, 2)
                                    End If
                                    If InStr(Data(r, 1), "Performance 6 mesi") Then
                                        Cells(i, 15) = Data(r, 2)
                                    End If
                             
                                    If InStr(Data(r, 1), "Performance 1 anno") Then
                                        Cells(i, 16) = Data(r, 2)
                                    End If
20:  ' questo è inutile
                                    Ws1.Range("A" & i) = "Y"
                                Next
                            Next
                        Next n
                    End If
                  Next
           
        .Quit
    End With
               
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 30/01/22 18:19

Per maggiore chiarezza segnalo che il blocco di codice sopra è quello che fa lo scraping e contiene sia i riferimenti alla pagina "Scheda" ( i primi due contrassegnati come Ilinks1) e gli altri a seguire sono sul foglio Daticompleti.
Ovviamente se non trova durante la scansione passa oltre senza danno o affanno di debug.
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 30/01/22 18:38

Fatto, ci sono riuscito con un semplice ciclo for da 1 a2 , visto che le schede da interrogare sono due . Quasi mi vergogno del tempo che ci ho dedicato senza vedere la soluzione più semplice comunque alla mia portata . Non sarà elegante ma sembra funzionare.

Codice: Seleziona tutto
Option Explicit

Sub Aggiorna()
   
    Dim driver As New Selenium.ChromeDriver
    Dim iTables As Selenium.WebElements
    Dim Data()
    Dim ur As Long
    Dim myIsin As String
    Dim i As Integer
    Dim n As Integer
    Dim r As Long
    Dim c As Integer
    Dim bln As Boolean, bln1 As Boolean
    Dim Ws1 As Worksheet
    Dim iLink1 As String
    Dim iLink2 As String
   
    Set Ws1 = Sheets("Dati")
    Ws1.Activate
    ur = Ws1.Cells(Rows.Count, 2).End(xlUp).Row
    Range("B1:P1") = Array("Isin", "Denominazione", "Sottostante", "Facoltà", "Strike", "Scadenza", "Prezzo Rif.", "Barriera", "Categoria", _
                           "Prezzo", "Perf.da.INIZIO", "Perf.1gg", "Perf.1M", "Perf.6M", "Perf.1A")
    Ws1.Range("I2:z" & ur).Clear
   
    ' codifica come stringa
    Ws1.Range("I2:z" & ur).Select
    With Selection
        .NumberFormat = "@"
    End With
    Range("a1").Select
   
    With driver
        .Start
        '.AddArgument ("--headless")
        .Window.Maximize
       Dim Z As Integer
       
       For Z = 1 To 2   '  visto che 2 sono le schede da interrogare ( ilinks1 e iLinks2)
        For i = 2 To ur
            bln = False: bln1 = False
            myIsin = Range("B" & i)
            iLink1 = "https://www.borsaitaliana.it/borsa/cw-e-certificates/scheda/" & myIsin & ".html?lang=it"""
            iLink2 = "https://www.borsaitaliana.it/borsa/cw-e-certificates/dati-mercato.html?isin=" & myIsin & "&lang=it"

            If Ws1.Range("A" & i) = "X" Then  ' qui ho tentato mettendo degli indicatori X e Y per correlare il bln e bln1
                bln = True
                bln1 = False
                .Get iLink1
            ElseIf Ws1.Range("A" & i) = "Y" Then
                bln = False
                bln1 = True
                .Get iLink2
            End If
           
            On Error Resume Next
            driver.Manage.DeleteAllCookies
            driver.FindElementByCss(".ccc-notify-button.ccc-tabbable.ccc-accept-button").Click
            driver.FindElementByCss("#ccc-dismiss-button").Click
            On Error GoTo 0
            .Wait 1000
           
                   
            If bln = True Or bln1 = True Then
                Set iTables = .FindElementsByCss("table")
                For n = 1 To iTables.Count
                    Data = iTables(n).AsTable.Data
                    For c = 1 To UBound(Data, 1)
                        For r = 1 To UBound(Data, 1)
                           
                            If InStr(Data(r, 1), "Barriera") Then  ' link1
                                Cells(i, 9) = Data(r, 2)
                            End If
                       
                            If InStr(Data(r, 1), "Categoria di Borsa") Then   ' link1
                                Cells(i, 10).Value = Data(r, 2)
                            End If
                           
                            If InStr(Data(r, 1), "Prezzo Acquisto") Then   'link2
                                Cells(i, 11) = Data(r, 2)
                            End If
                         
                            If InStr(Data(r, 1), "Performance Inizio") Then
                                Cells(i, 12).Value = Data(r, 2)
                            End If
                           
                            If InStr(Data(r, 1), "Performance 1 Giorno") Then
                                Cells(i, 13) = Data(r, 2)
                            End If
                               
                            If InStr(Data(r, 1), "Performance 1 mese") Then
                                Cells(i, 14) = Data(r, 2)
                            End If
                            If InStr(Data(r, 1), "Performance 6 mesi") Then
                                Cells(i, 15) = Data(r, 2)
                            End If
                             
                            If InStr(Data(r, 1), "Performance 1 anno") Then
                                Cells(i, 16) = Data(r, 2)
                            End If

                            Ws1.Range("A" & i) = "Y"
                        Next
                    Next
                Next n
            End If
                           
        Next
      Next
        .Quit
    End With
               
    Ws1.Range("A1").Select
   
    MsgBox ("Finito")
End Sub
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Anthony47 » 30/01/22 19:11

Bravo!
Io invece avevo pensato che il codice fosse stato pubblicato in qualche forum di finanza (so che mi perdonerai per questo pensiero), quindi "mi ero portato avanti" con una mia soluzione derivata dal tuo lavoro; oramai che ci sono la pubblico e vediamo se puoi farne qualche uso per le tue esigenze.

Vedi questo file: https://www.dropbox.com/s/39fd68rg3eckw ... .xlsm?dl=0

Nel foglio Dati e nel Modulo vba Aggiorna2 c'e' quanto tu avevi pubblicato.

Nel foglio AllTables e nel Modulo Modulo1 c'e' un mio lavoro che consente di estrarre tutte le tabelle presenti in una pagina web e posizionarle nel foglio
La prestazione e' ottenuta tramite una Sub GetAllTablesArr che necessita dei seguenti parametri:
-l'Url della pagina
-Riga e Colonna dove posizionare i dati

Questa Sub deve essere "chiamata" da una Sub superiore; visto che il tuo problema parlava di 2 pagine web questa Sub e' così composta:

Codice: Seleziona tutto
Dim WPage As Object

Sub PrintTables()
Dim myIsin As String, myUrl As String
'
'Crea Driver:
If WPage Is Nothing Then
    Set WPage = CreateObject("Selenium.EdgeDriver")
End If
Sheets("AllTables").Select
Range("A:M").ClearContents
'
myIsin = "CH0508208748"
myUrl = "https://www.borsaitaliana.it/borsa/cw-e-certificates/scheda/" & myIsin & ".html?lang=it"""
'
'Prima pagina:
WPage.Start "edge"
Call GetAllTablesArr(myUrl)         'Posiziona in colonna A
'
'Seconda pagina:
myUrl = "https://www.borsaitaliana.it/borsa/cw-e-certificates/dati-mercato.html?isin=" & myIsin & "&lang=it"
Call GetAllTablesArr(myUrl, 1, 5)   'Posiziona in colonna E
'
'Quit Selenium
WPage.Quit
Set WPage = Nothing
MsgBox ("Informazioni raccolte...")
End Sub

Il codice della Sub GetAllTablesArr, nello stesso Modulo della Sub Caller:
Codice: Seleziona tutto
Sub GetAllTablesArr(myUrl As String, Optional rNum0 As Long = 1, Optional cNum0 As Long = 1)
Dim TBColl As Object
Dim I As Long, J As Long, myTim As Single
Dim RNum As Long, CNum As Long
   
Dim TArr

If WPage Is Nothing Then
    Set WPage = CreateObject("Selenium.EdgeDriver")
End If
WPage.Get myUrl
'
myTim = Timer
'
Set TBColl = WPage.FindElementsByTag("table")
RNum = rNum0: CNum = cNum0
'
For I = 1 To TBColl.Count               'Scan delle Tabelle presenti
    TArr = TBColl(I).AsTable.Data
    RNum = RNum + 1
    Cells(RNum, CNum).Value = "## Table " & I
    If (UBound(TArr) * UBound(TArr, 2)) > 0 Then
        Cells(RNum + 1, CNum).Resize(UBound(TArr), UBound(TArr, 2)).Value = TArr
    End If
    RNum = RNum + UBound(TArr) + 1
    DoEvents
Next I
Debug.Print "FINE", RNum, Format(Timer - myTim, "0.00"), myUrl
End Sub


Lanciando la Sub PrintTables potremo quindi vedere nel foglio AllTables quali informazioni le varie tabelle contengono per un singolo ISIN

Sul foglio DataColl ho creato una situazione simile alla tua, con una serie di isin in colonna A e una serie di colonne la cui intestazione e' l'inizio di una delle etichette visibili nel foglio AllTables.
Questa tabella viene popolata tramite la Sub Caller presente in Modulo2, che si appoggia sulla Function GimmeTablesArr (derivata dalla Sub GetAllTablesArr, ma che si limita a restituire alla chiamante "una matrice con tutte le matrici, cioe' le tabelle") presenti sull'url chiamato.

Il codice di questo secondo ambiente, presente su Modulo2:
Codice: Seleziona tutto
Dim WPage As Object

Sub Caller()
Dim myIsin As String, myUrl As String, LastA As Long, I As Long, Last1 As Long
Dim AllTabs, J As Long, K As Long, L As Long, myHead As String, P As Long
'
'Crea Driver:
If WPage Is Nothing Then
    Set WPage = CreateObject("Selenium.EdgeDriver")
    WPage.Start "edge"
End If
Sheets("dataColl").Select
'
LastA = Cells(Rows.Count, "A").End(xlUp).Row            'Quanti Isin?
Last1 = Cells(1, Columns.Count).End(xlToLeft).Column    'Quante colonne?
'
Range("B2").Resize(LastA + 10, Last1 + 5).ClearContents
For P = 1 To 2                                      'Cerca su ambedue le pagine web
    For I = 2 To LastA                              ' per ogni Isin
        myIsin = Cells(I, 1)
        If P = 1 Then
            myUrl = "https://www.borsaitaliana.it/borsa/cw-e-certificates/scheda/" & myIsin & ".html?lang=it"""
        Else
            myUrl = "https://www.borsaitaliana.it/borsa/cw-e-certificates/dati-mercato.html?isin=" & myIsin & "&lang=it"
        End If
        AllTabs = GimmeTablesArr(WPage, myUrl)      'Ottieni la matrice delle tabelle
        For J = 2 To Last1                          'Cerca l'intestazione di ogni colonna...
            myHead = Cells(1, J).Value
            For K = 1 To UBound(AllTabs)            '... in tutte le tabelle della pagina...
                For L = 1 To UBound(AllTabs(K))     '.... in tutte le righe di ogni tabella
                    'Se "Trovato" allora scrivi il valore:
                    If InStr(1, AllTabs(K)(L, 1), myHead, vbTextCompare) = 1 Then
                        If Cells(I, J) = "" Then Cells(I, J) = AllTabs(K)(L, 2)
                    End If
                Next L
            Next K
        Next J
    Next I
Next P
'
'Quit Selenium
WPage.Quit
Set WPage = Nothing
MsgBox ("Informazioni raccolte...")
End Sub



Function GimmeTablesArr(lDriver As Object, myUrl As String) As Variant
'Dim PColl As WebElements, myItm As Object, TBColl As Object, pCount As Long
Dim I As Long, myTim As Single
'Dim RNum As Long, CNum As Long, TdtD As Object, TrtR As Object
Dim TArr()
'
lDriver.Get myUrl
myTim = Timer
'
Set TBColl = lDriver.FindElementsByTag("table")
ReDim TArr(1 To TBColl.Count)
'
For I = 1 To TBColl.Count
    TArr(I) = TBColl(I).AsTable.Data
Next I
GimmeTablesArr = TArr
Debug.Print "GTArr:", "Tables: " & I - 1, Format(Timer - myTim, "0.00"), myUrl
End Function

Tieni presenti che le intestazioni di colonna devono corrispondere "all'inizio" di una etichetta presenti su una delle pagine web, e viene presa in considerazione solo la prima occorrenza; quindi ad esempio una ipotetica intestazione "Volume" sara' popolato dalla riga Volume Ultimo.

Se ti serve allora "bene", altrimenti lo tengo per me :lol: :lol:

Ciao

PS: ricordo che per interagire in questo modo con i browser Edge oppure Chrome oppure Firefox e' necessario installare i driver Selenium, come descritto qui: viewtopic.php?f=26&t=112225
Avatar utente
Anthony47
Moderatore
 
Post: 19436
Iscritto il: 21/03/06 16:03
Località: Ivrea

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 30/01/22 21:09

Grazie Anthony, anche troppo complesso per me.
Ma come oggetto di studio è ottimo ho visto che hai usato una logica diversa rispetto allo scraping puntuale che avevo adottato io. Converto il file a chrome e poi lo provo. Grazie ancora .

Comunque il metodo da te usato qui è quello che in sostanza serviva a me anzi, proverò a riapplicarlo al mio codice in modo da ripulirlo da tutti i "percorsi strani " che avevo inserito inutilmente :

Codice: Seleziona tutto
For P = 1 To 2                                      'Cerca su ambedue le pagine web
    For I = 2 To LastA                              ' per ogni Isin
        myIsin = Cells(I, 1)
        If P = 1 Then
            myUrl = "https://www.borsaitaliana.it/borsa/cw-e-certificates/scheda/" & myIsin & ".html?lang=it"""
        Else
            myUrl = "https://www.borsaitaliana.it/borsa/cw-e-certificates/dati-mercato.html?isin=" & myIsin & "&lang=it"
        End If
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 31/01/22 10:58

Ecco qua , è il mio codice ripulito e aggiornato con lo spunto copiato dalla tua macro.

Codice: Seleziona tutto
Option Explicit

Sub Aggiorna()
   
    Dim driver As New Selenium.ChromeDriver
    Dim iTables As Selenium.WebElements
    Dim Data()
    Dim ur As Long
    Dim myIsin As String
    Dim i As Integer
    Dim n As Integer
    Dim r As Long
    Dim c As Integer
    Dim bln As Boolean, bln1 As Boolean
    Dim Ws1 As Worksheet
    Dim iLink1 As String
    Dim iLink2 As String
   
    Set Ws1 = Sheets("Dati")
    Ws1.Activate
    ur = Ws1.Cells(Rows.Count, 2).End(xlUp).Row
    Range("B1:P1") = Array("Isin", "Denominazione", "Sottostante", "Facoltà", "Strike", "Scadenza", "Prezzo Rif.", "Barriera", "Categoria", _
                           "Prezzo", "Perf.da.INIZIO", "Perf.1gg", "Perf.1M", "Perf.6M", "Perf.1A")
    Ws1.Range("I2:z" & ur).Clear
   
    ' codifica come stringa
    Ws1.Range("I2:z" & ur).Select
    With Selection
        .NumberFormat = "@"
    End With
    Range("a1").Select
   
    With driver
        .Start
        '.AddArgument ("--headless")
        .Window.Maximize
       Dim Z As Integer
       
       For Z = 1 To 2   '  visto che 2 sono le schede da interrogare ( ilinks1 e iLinks2)
        For i = 2 To ur
            myIsin = Range("B" & i)
            iLink1 = "https://www.borsaitaliana.it/borsa/cw-e-certificates/scheda/" & myIsin & ".html?lang=it"""
            iLink2 = "https://www.borsaitaliana.it/borsa/cw-e-certificates/dati-mercato.html?isin=" & myIsin & "&lang=it"

            If Z = 1 Then
                  .Get iLink1
            ElseIf Z = 2 Then
                   .Get iLink2
            End If
           
            On Error Resume Next
            driver.Manage.DeleteAllCookies
            driver.FindElementByCss(".ccc-notify-button.ccc-tabbable.ccc-accept-button").Click
            driver.FindElementByCss("#ccc-dismiss-button").Click
            On Error GoTo 0
            .Wait 1000
           
                   
               Set iTables = .FindElementsByCss("table")
                For n = 1 To iTables.Count
                    Data = iTables(n).AsTable.Data
                    For c = 1 To UBound(Data, 1)
                        For r = 1 To UBound(Data, 1)
                           
                            If InStr(Data(r, 1), "Barriera") Then  ' link1
                                Cells(i, 9) = Data(r, 2)
                            End If
                       
                            If InStr(Data(r, 1), "Categoria di Borsa") Then   ' link1
                                Cells(i, 10).Value = Data(r, 2)
                            End If
                           
                            If InStr(Data(r, 1), "Prezzo Acquisto") Then   'link2
                                Cells(i, 11) = Data(r, 2)
                            End If
                         
                            If InStr(Data(r, 1), "Performance Inizio") Then
                                Cells(i, 12).Value = Data(r, 2)
                            End If
                           
                            If InStr(Data(r, 1), "Performance 1 Giorno") Then
                                Cells(i, 13) = Data(r, 2)
                            End If
                               
                            If InStr(Data(r, 1), "Performance 1 mese") Then
                                Cells(i, 14) = Data(r, 2)
                            End If
                            If InStr(Data(r, 1), "Performance 6 mesi") Then
                                Cells(i, 15) = Data(r, 2)
                            End If
                             
                            If InStr(Data(r, 1), "Performance 1 anno") Then
                                Cells(i, 16) = Data(r, 2)
                            End If

                            Ws1.Range("A" & i) = "Y"
                        Next
                    Next
                Next n
                             
        Next
      Next
        .Quit
    End With
               
    Ws1.Range("A1").Select
   
    MsgBox ("Finito")
End Sub
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 01/02/22 17:59

Anthony , rinnovo i complimenti ! Ho installato i driver di Edge e ho quindi provato il tuo file . Rispetto al mio è una scheggia , probabilmente perchè scarica tutte le tabelle in un array e NON come ho fatto io che ho realizzato un codice che fa lo scraping puntuale e ad ogni richiesta deve scorrere l'intero foglio HTML

Ma, come fai a prelevare ciò che interessa e a riportarlo nel foglio DataColl questo non l'ho capito . :D , tra le altre cose .
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 01/02/22 20:59

Capito , è ciò che metti nel rigo 1 che determina la ricerca dei dati .
Perchè non lo vai a insegnare su siti americani che se la tirano ... :lol: come se fossero i soli a conoscere il VBA. Bah

Comunque se ho capito bene hai usato i dati presi dalla AllTables per individuare correttamente le scritte da riportare poi in DataColl, giusto ?
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Anthony47 » 02/02/22 16:54

Ovviamente ho usato la prima macro per avere una vista delle tabelle che mi servivano e usarle nelle intestazioni.
Alla prossima...

Edit:
Dimenticavo di dire che non sarebbe stato necessario installare la parte Edge, sarebbe bastato sostituire le righe iniziali:
Codice: Seleziona tutto
'    Set WPage = CreateObject("Selenium.EdgeDriver")            'Per Edge
'    WPage.Start "edge"
    Set WPage = CreateObject("Selenium.chromedriver")    'Per Chrome
    WPage.Start "chrome"

E (pensandoci bene) non ho capito perche' io avevo testato con Edge e non con Chrome.
Avatar utente
Anthony47
Moderatore
 
Post: 19436
Iscritto il: 21/03/06 16:03
Località: Ivrea

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 02/02/22 21:42

Codice: Seleziona tutto
Ciao Anthony,
Problemino, visto la velocità del tuo codice ho tentato la replica su un'altra applicazione per lo scarico delle obbligazioni, ma qui le pagine sono un poco diverse . Sono riuscito a modificare la macro AllTasbles con un secondo myIsin2 , e funziona bene, ma nella Funcion della caller va in debug per indice non trovato su questa riga con questo messaggio. Non ho capito dove sbaglio a correggere la macro, ammesso che sia possibile correggerla.

Codice: Seleziona tutto
ReDim TArr(1 To TBColl.Count)


Questa funziona
Codice: Seleziona tutto
Option Explicit
Dim WPage As Object

Sub PrintTables()
Dim myIsin As String, myIsin2 As String, myUrl As String
 Const S1 = "obbligazioni/mot/euro-obbligazioni"
    Const S2 = "obbligazioni/eurotlx/dati-completi.html?isin="


'
'Crea Driver:
If WPage Is Nothing Then
    Set WPage = CreateObject("Selenium.EdgeDriver")
End If
Sheets("AllTables").Select
Range("A:M").ClearContents
'
myIsin = "XS0074838300"  ' Mot

myIsin2 = "XS0461366832"  'Tlx
myUrl = "https://www.borsaitaliana.it/borsa/" & S1 & "/dati-completi.html?isin=" & myIsin & "&lang=it"
           
'
'Prima pagina:
WPage.Start "edge"
Call GetAllTablesArr(myUrl)         'Posiziona in colonna A
'
'Seconda pagina:
myUrl = "https://www.borsaitaliana.it/borsa/" & S2 & myIsin2 & "&lang=it"
'
Call GetAllTablesArr(myUrl, 1, 5)   'Posiziona in colonna E
'
'Quit Selenium
WPage.Quit
Set WPage = Nothing
MsgBox ("Informazioni raccolte...")
End Sub


Sub GetAllTablesArr(myUrl As String, Optional rNum0 As Long = 1, Optional cNum0 As Long = 1)
Dim TBColl As Object
Dim I As Long, J As Long, myTim As Single
Dim RNum As Long, CNum As Long
   
Dim TArr

If WPage Is Nothing Then
    Set WPage = CreateObject("Selenium.EdgeDriver")
End If
WPage.Get myUrl
'
myTim = Timer
'
Set TBColl = WPage.FindElementsByTag("table")
RNum = rNum0: CNum = cNum0
'
For I = 1 To TBColl.Count               'Scan delle Tabelle presenti
    TArr = TBColl(I).AsTable.Data
    RNum = RNum + 1
    Cells(RNum, CNum).Value = "## Table " & I
    If (UBound(TArr) * UBound(TArr, 2)) > 0 Then
        Cells(RNum + 1, CNum).Resize(UBound(TArr), UBound(TArr, 2)).Value = TArr
    End If
    RNum = RNum + UBound(TArr) + 1
    DoEvents
Next I
Debug.Print "FINE", RNum, Format(Timer - myTim, "0.00"), myUrl
End Sub


Quesat si grippa
Codice: Seleziona tutto
Option Explicit
Dim WPage As Object

Sub Caller()
'http://www.pc-facile.com/forum/viewtopic.php?f=26&t=112311&p=660077#p660077
Dim myIsin As String, myIsin2 As String, myUrl As String, LastA As Long, I As Long, Last1 As Long
Dim AllTabs, J As Long, K As Long, L As Long, myHead As String, P As Long

Const S1 = "obbligazioni/mot/euro-obbligazioni"
    Const S2 = "obbligazioni/eurotlx/dati-completi.html?isin="

'Crea Driver:
If WPage Is Nothing Then
    Set WPage = CreateObject("Selenium.EdgeDriver")
    WPage.Start "edge"
End If
Sheets("dataColl").Select
'
LastA = Cells(Rows.Count, "A").End(xlUp).Row            'Quanti Isin?
Last1 = Cells(1, Columns.Count).End(xlToLeft).Column    'Quante colonne?
'
Range("B2").Resize(LastA + 10, Last1 + 5).ClearContents
For P = 1 To 2                                      'Cerca su ambedue le pagine web
    For I = 2 To LastA                              ' per ogni Isin
        myIsin = Cells(I, 1)
        myIsin2 = Cells(I, 5)       ' mia  aggiunta con ricerca in col. E
        If P = 1 Then
            myUrl = "https://www.borsaitaliana.it/borsa/" & S1 & "/dati-completi.html?isin=" & myIsin & "&lang=it"  ' MOT
        Else
            myUrl = "https://www.borsaitaliana.it/borsa/" & S2 & myIsin2 & "&lang=it"    'TLX
        End If
        AllTabs = GimmeTablesArr(WPage, myUrl)      'Ottieni la matrice delle tabelle
        For J = 2 To Last1                          'Cerca l'intestazione di ogni colonna...
            myHead = Cells(1, J).Value
            For K = 1 To UBound(AllTabs)            '... in tutte le tabelle della pagina...
                For L = 1 To UBound(AllTabs(K))     '.... in tutte le righe di ogni tabella
                    'Se "Trovato" allora scrivi il valore:
                    If InStr(1, AllTabs(K)(L, 1), myHead, vbTextCompare) = 1 Then
                        If Cells(I, J) = "" Then Cells(I, J) = AllTabs(K)(L, 2)
                    End If
                Next L
            Next K
        Next J
    Next I
Next P
'
'Quit Selenium
WPage.Quit
Set WPage = Nothing
MsgBox ("Informazioni raccolte...")
End Sub

Function GimmeTablesArr(lDriver As Object, myUrl As String) As Variant
Dim PColl As WebElements, myItm As Object, TBColl As Object, pCount As Long
Dim I As Long, myTim As Single
'Dim RNum As Long, CNum As Long, TdtD As Object, TrtR As Object
Dim TArr()
'
lDriver.Get myUrl
myTim = Timer
'
Set TBColl = lDriver.FindElementsByTag("table")
ReDim TArr(1 To TBColl.Count)     ' si blocca qui
'
For I = 1 To TBColl.Count
    TArr(I) = TBColl(I).AsTable.Data
Next I
GimmeTablesArr = TArr
Debug.Print "GTArr:", "Tables: " & I - 1, Format(Timer - myTim, "0.00"), myUrl
End Function

Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Anthony47 » 03/02/22 00:07

Pero' ora non capisco cosa vuoi fare...

Nel precedente caso avevamo un elenco di Isin (su foglio DataColl) ed eravamo interessati a estrarre un tot di informazioni che si trovavano su due pagine web diverse. Avendo creato con la Sub PrintTables l'elenco dei campi disponibili nelle tabelle di quelle due pagine web potevamo creare le intestazioni del tabellone che in DataColl andavamo a compilare, cercando (per ogni isin) sia nella pagina 1 che nella pagina 2.

Ora invece hai estratto da due pagine diverse i dati di due titoli diversi trattati su mercati diversi, che quindi hanno tabelle con tracciato diverso. Come pensi di usare pagine web destinate a mercati diversi su titoli che su quel mercato non sono presenti?
Insomma se usi la pagina per tlx e gli chiedi di un titolo del mot cosa pensi che ti risponda?

Quindi il dubbio: ora cosa stai cercando di ottenere?
Avatar utente
Anthony47
Moderatore
 
Post: 19436
Iscritto il: 21/03/06 16:03
Località: Ivrea

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 03/02/22 09:02

Ciao, l'hai già detto tu : in un solo elenco di Isin avere i risultati di entrambi i mercati, ecco perchè avevo provato a raddoppiare gli isin (myIsin e MyIsin2) utilizzandoli separatamente nei due diversi Url . Ma giustamente non funzia . L'alternativa è fare un doppio ciclo di ricerca: prima l'uno e poi l'altro, ma anche qui c'è il problema dell'intestazione di rigo 1 che cambia, per es. nel MOT ho "Valuta" nel TLX ho " Valuta di negoziazione", oppure nel Mot "Prezzo di Acquisto" nel Tlx ho " Prezzo Ultimo contratto " etc.
A meno che : fare le ricerche con la tua macro e mettere i dati su due fogli separati e poi riunirli in un foglio finale di sintesi .
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Anthony47 » 03/02/22 12:47

Il problema e' che per ogni mercato il tracciato delle tabelle e' diverso, e idem per le pagine web da coslultare. E ovviamente devi sapere per ogni isin in quale mercato (pagine web) cercare.

Ora non e' impossibile creare in DataColl un tabellone con in col A gli Isin, in colonna B il mercato, nelle colonne residue i valori da cercare; poi si usera' la colonna B per determinare quali pagine web vanno consultare per quel titolo.
Pero' e' probabile che informazioni simili (es ultimo prezzo di vendita) abbiano una intestazione sul mercato A e una intestazione diversa su mercato B.
Quindi o crei su foglio DataColl un tabellone con (per la stessa informazione, es ultimo prezzo di vendita) piu' colonne con piu' intestazioni (e quando cerchi un titolo sul mercato A le colonne che sono relative al mercato B rimarranno vuote); oppure crei un unico tabellone con intestazioni "convenzionali" e poi una tabella di conversione dall'intestazione convenzionale all'intestazione del mercato del titolo in esame, e usi l'intestazione di mercato per compilare quella colonna.

Oppure ti crei tanti fogli DataColl, uno per mercato, e tante Sub Caller (dove cambiano le pagine web da consultare, in funzione del mercato). Al momento questo e il suggerimento che raccomando di piu'.

Mi chiedo anche se non esistono gia' in giro tools specifici per tenere sotto controllo un elenco di titoli

Ciao
Avatar utente
Anthony47
Moderatore
 
Post: 19436
Iscritto il: 21/03/06 16:03
Località: Ivrea

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 03/02/22 15:35

"Mi chiedo anche se non esistono gia' in giro tools specifici per tenere sotto controllo un elenco di titoli "
Si , esistevano , ma erano quasi tutti basati su IE e ... per completare l'opera anche Borsa Italiana ha cambiato non so che, ma di fatto non funzionano più.

"Oppure ti crei tanti fogli DataColl, uno per mercato, e tante Sub Caller (dove cambiano le pagine web da consultare, in funzione del mercato). Al momento questo e il suggerimento che raccomando di piu'. "
Mi sa che farò cosi , provo e ritorno. Ciao
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 03/02/22 21:54

Interrogazione completata . Ora devo imbastire una macro che copia sulla base degli Isin di colonna 1, le righe mancanti .
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 04/02/22 21:18

Ecco la macro che confronta gli Isin di colonna 1 ( su entrambi i fogli) e copia le sole righe con i dati dal foglio origine (DataCall2) al foglio di destinazione (DataCall1).

Codice: Seleziona tutto
Option Explicit

Sub CercaEcopia()
   
    Dim DestRiga As Long  ' Dest x Destinazione
    Dim OrgRiga As Long    'Org per Origine dati
    Dim col As Long
    Dim OrgCol As Long
    Dim shDest As Worksheet 'foglio in cui copiare previa scansione = destinazione
    Dim shOrg As Worksheet ' foglio da cui copiare = Origine
     
    Set shDest = Worksheets("DataColl1")
    Set shOrg = Worksheets("DataColl2")
             
    shDest.Activate
    DestRiga = 2
    Do While shDest.Cells(DestRiga, 1) <> ""       'colonna del fo  base di ricerca
       
        OrgRiga = fnCerca(shOrg, shDest.Cells(DestRiga, 1).Text)
        If OrgRiga > 0 Then
                'copia celle
                OrgCol = 2
                For col = 2 To 5
                    shDest.Cells(DestRiga, col) = shOrg.Cells(OrgRiga, OrgCol)
                    OrgCol = OrgCol + 1
                Next col
            End If
                       DestRiga = DestRiga + 1
                Loop
    End Sub

Public Function fnCerca(shOrg As Worksheet, txt As String) As Long
    Dim riga As Long
    riga = 2
    Do While shOrg.Cells(riga, 1) <> ""
       
        If shOrg.Cells(riga, 1) = txt And shOrg.Cells(riga, 1).Offset(0, 1) <> "" Then  ' se non vuota
            fnCerca = riga
            Exit Do
        End If
        riga = riga + 1
    Loop
   
End Function



due cose ho notato : 1) inizialmente avevo agganciato le due macro, la prima scaricava i dati dal Mot e dopo dal TLX. Purtroppo però il browser (Edge ma anche Crome ) veniva bruscamente " interrotto " circa ametà del secondo scarico dati. Non ho capito se bisognava rallentare il download oppure è proprio il sito Borsa Italiana a fare questi scherzetti. 2) un bug del metodo ovvero se sulla prima riga si va ad occupare una cella, magari con una data o altro, il codice scarica altri dati non richiesti.
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Re: Vba e Selenium doppio ciclo

Postdi Anthony47 » 05/02/22 12:38

due cose ho notato : 1) inizialmente avevo agganciato le due macro, la prima scaricava i dati dal Mot e dopo dal TLX. Purtroppo però il browser (Edge ma anche Crome ) veniva bruscamente " interrotto " circa ametà del secondo scarico dati. Non ho capito se bisognava rallentare il download oppure è proprio il sito Borsa Italiana a fare questi scherzetti. 2) un bug del metodo ovvero se sulla prima riga si va ad occupare una cella, magari con una data o altro, il codice scarica altri dati non richiesti.

Per il punto 1, bisognerebbe sapere alla fine quali macro hai utilizzato; inoltre se l'interruzione e' legata al numero di scaricamenti da fare o ti sembra che non sia legato a cio'.
Per il punto 2, le intestazioni (come avevo impostato io la macro) dicono che cosa va scaricato; vale il principio "shit in - shit out"

Ciao
Avatar utente
Anthony47
Moderatore
 
Post: 19436
Iscritto il: 21/03/06 16:03
Località: Ivrea

Re: Vba e Selenium doppio ciclo

Postdi Gianca532011 » 05/02/22 21:18

Per il punto 1, bisognerebbe sapere alla fine quali macro hai utilizzato; inoltre se l'interruzione e' legata al numero di scaricamenti da fare o ti sembra che non sia legato a cio'.

Capita sempre sulla seconda macro, quale che sia, se utilizzata di seguito all'altra. Va tutto bene se le eseguo separatamente .

Per il punto 2, le intestazioni (come avevo impostato io la macro) dicono che cosa va scaricato; vale il principio "shit in - shit out"

Appunto, se metti qualcosa d'altro vagamente riconducibile alla pagina scaricata, ottengo dei dati aggiuntivi . E' giusto cosi, basta saperlo che in rigo 1 non ci si deve scrivere altro se non quanto interessa .


Come faccio a mettere il file conclusivo in modo che resti perenne a (mia) memoria futura ?
Giancarlo
win 10 - Office 2016 Ita
Gianca532011
Utente Senior
 
Post: 348
Iscritto il: 27/05/11 10:18

Prossimo

Torna a Applicazioni Office Windows


Topic correlati a "Vba e Selenium doppio ciclo":


Chi c’è in linea

Visitano il forum: Nessuno e 6 ospiti

cron