1

My end goal is to dynamically get music playing. I figured that navigating to youtube, searching for the string, and playing the first video suggested is a good way of getting this done. Pandora and Spotify both have hoops that you need to jump through before playing.

Sub YouTube()

So we open up IE, and navigate to the website

    Set objIE = CreateObject("InternetExplorer.Application")
    WebSite = "www.youtube.com"
    With objIE
        .Visible = True
        .navigate WebSite
        Do While .Busy Or .readyState <> 4
            DoEvents
        Loop

So far, so good. Next we find the search box, and make a search. Dummy text entered for the sake of easy coding, it'll eventually be an argument passed to the function.

        Set Element = .document.getelementsbyname("search_query")
        Element.Item(0).Value = "portal 2 walkthrough video"
        .document.forms(1).submit

        Do While .Busy Or .readyState <> 4
            DoEvents
        Loop

Great, we made it! Now for the part I'm struggling on - clicking on the first video.

I've tried a few different things - I can't seem to find a name, and I keep getting a "Permission denied" when I try to do something like this, as suggested by other users. See: How do I click a link on a web page using Excel VBA?

I've decided not to programatically control the mouse and click, since the location I need to click on keeps dynamically changing.

I'm not very good at interfacing with IE while using VBA, so at this point I'm stumped.

        Set Element2 = .document.getelementsbytagname("a")
        For Each i In Element2
            If i.classname = "yt-lockup-content" Then
                i.Click
                Exit For
            Else
                'do nothing
            End If
        Next i


        End With

End Sub

I've also tried:

  .document.getelementsbyclassname("yt-lockup-content").Click

But that's not a supported method

        .document.querySelector("a[href=javascript:browserPrint();]").Click

Gets a permission denied

Selkie
  • 1,215
  • 1
  • 17
  • 34
  • 1
    Your line `.document.getelementsbyclassname("yt-lockup-content").Click`. Notice how it says `getElements`. Look closely, and you will see that there is an `s` at the end of element. This is its way of telling you that it returns a collection of elements, therefore it requires an index. `.getElementsByClassName(...)(0)`, where `(0)` (or `.Item(0)`) is the index of the collection item you want. – K.Dᴀᴠɪs Jul 25 '19 at 18:28
  • Great! Now I have new errors - it gives a "Permission denied" the first time - I hit debug, I hit run again, and it works. Gotta dig into this new error...Edit: Adding a 3 second wait fixed the issue – Selkie Jul 25 '19 at 18:36
  • @K.Dᴀᴠɪs if you make your post an answer I'll accept it, since it's what worked for me – Selkie Jul 26 '19 at 11:21
  • I adjusted by answer to include that as well. Glad you were able to fix it, thanks! – K.Dᴀᴠɪs Jul 26 '19 at 16:07

3 Answers3

3

The following using a loop to wait until results are present. I try to keep much of the selectors used to target elements fairly loose to allow for changes in html

Option Explicit
Public Sub test()
    Dim ie As InternetExplorer

    Set ie = New InternetExplorer
    With ie
        .Visible = True

        .Navigate2 "https://www.youtube.com/"
        While .Busy Or .readyState <> 4: DoEvents: Wend

        .document.querySelector("[title=Search]").Value = "portal 2 walkthrough video"
        .document.querySelectorAll("form").item(1).submit
        While .Busy Or .readyState <> 4: DoEvents: Wend

        Do
        Loop While .document.querySelectorAll("#results").Length = 0
        .document.querySelector("#results h3 a").Click
        While .Busy Or .readyState <> 4: DoEvents: Wend

        Stop    '<Delete me later
    End With

End Sub
QHarr
  • 83,427
  • 12
  • 54
  • 101
  • Thanks a lot. When inspecting the element of search in chrome I noticed there is no attribute `title` but found alternative `placeholder`. Is there a difference? What if I used the `placeholder` attribute instead of `title`? – YasserKhalil Jul 26 '19 at 02:25
  • 1
    chome has different html attributes throughout You could potentially use css Or syntax to handle this. Depends whether first match in each case is the desired. – QHarr Jul 26 '19 at 02:29
  • `You could potentially use css Or syntax to handle this`.Can you give me example or spot a little on this part? – YasserKhalil Jul 26 '19 at 02:38
  • .document.querySelector("[title=Search], otherSelector").Value = "portal 2 walkthrough video" – QHarr Jul 26 '19 at 02:55
2

Another method is to use the querySelector() method. You know you want the element with the tag a, because the a tag means that it contains a link.

Then combine the above with the class name that you're looking for, yt-lockup-title, and you get this single line:

.querySelector("h3.yt-lockup-title").Click

Take note that this is a method of the document object. So objIE.Document.querySelector()


Don't want to use the .Click method? You can also grab the url from the href attribute and just perform a navigation:

Dim vidURL As String
vidURL = objIE.document.querySelector("h3.yt-lockup-title > a").getAttribute("href")
objIE.navigate "https://www.youtube.com" & vidURL 

However, in the method you attempted with using

.document.getelementsbyclassname("yt-lockup-content").Click

the getElementsByClassName() function returns a collection of elements. Because of this, you would need to append the index number of the element you are wanting, which would very likely be the first element (since you want the first video).

One of the two lines would be what you're looking for:

.document.getelementsbyclassname("yt-lockup-content")(0).Click

'                           - OR -

.document.getelementsbyclassname("yt-lockup-content").Item(0).Click

They both do and mean the same thing.

K.Dᴀᴠɪs
  • 9,945
  • 11
  • 33
  • 43
1

I have changed a element to span element and it worked. Code below:

Sub YouTube()

    Set objIE = CreateObject("InternetExplorer.Application")
    WebSite = "www.youtube.com"


    With objIE
        .Visible = True
        .navigate WebSite
        Do While .Busy Or .ReadyState <> 4
            DoEvents
        Loop

        Set Element = .document.getelementsbyname("search_query")
        Element.Item(0).Value = "portal 2 walkthrough video"
        .document.forms(1).submit

        Do While .Busy Or .ReadyState <> 4
            DoEvents
        Loop

        Set Element2 = .document.getelementsbytagname("span")
        For Each i In Element2
            Do While .Busy Or .ReadyState <> 4
            DoEvents
            Loop
            If i.classname = "yt-thumb-simple" Then
                i.Click
                Exit For
            Else
                'do nothing
            End If
        Next i


        End With

End Sub
Pawel Czyz
  • 1,651
  • 4
  • 17
  • 21