1

Thanks to Qharr, I have successfully performed auto search on the website.(My previous question: Excel VBA: Cannot perform auto search on website) I have another question concerning the next step: I would always like to click the first link that appears after clicking the search button, and open the file in order to extract certain data. Is there any ways to do that? Thanks!

Codes that I have at present:

Option Explicit
Sub Searchstockcode()

    Dim SearchString As String, SearchBox As Object, SearchButton As Object, ie As Object

    SearchString = "2828"

    Set ie = CreateObject("InternetExplorer.Application")

    ie.Visible = True

    ie.navigate "http://www.hkexnews.hk/listedco/listconews/advancedsearch/search_active_main.aspx"

    While ie.Busy Or ie.readyState < 4: DoEvents: Wend

    Set SearchBox = ie.document.getElementById("ctl00_txt_stock_code")
    SearchBox.Value = SearchString

    Set SearchButton = ie.document.querySelector("[src*='/image/search.gif']")
    SearchButton.Click

    While ie.Busy Or ie.readyState < 4: DoEvents: Wend

    'Click the first result
    Set TargetFile = ie.document.getElementById("ctl00_gvMain_ctl02_hlTitle") 
    TargetFile.Click

    'Here I would like to open the file in excel, but I am stuck at the "save as" pop up.
    'As long as the file can be opened, I should be able to complete the data extraction with my own codes.

ie.Quit
End Sub
QHarr
  • 83,427
  • 12
  • 54
  • 101
LLC
  • 15
  • 1
  • 4

1 Answers1

2

You can extract the URL for the file download and binary file download. In the example below, the file is stored in a variable wb for later use.

In the following the filedownload link is extracted via TargetFile.href and passed to a function to perform ADODB binary download. You could also pass the URL for download to URLMon as shown in my answer here.

Option Explicit
Public Sub Searchstockcode()

    Dim SearchString As String, SearchBox As Object, SearchButton As Object, ie As Object

    SearchString = "2828"

    Set ie = CreateObject("InternetExplorer.Application")

    ie.Visible = True

    ie.navigate "http://www.hkexnews.hk/listedco/listconews/advancedsearch/search_active_main.aspx"

    While ie.Busy Or ie.readyState < 4: DoEvents: Wend

    Set SearchBox = ie.document.getElementById("ctl00_txt_stock_code")
    SearchBox.Value = SearchString

    Set SearchButton = ie.document.querySelector("[src*='/image/search.gif']")
    SearchButton.Click

    While ie.Busy Or ie.readyState < 4: DoEvents: Wend

    Dim TargetFile As Object
    Set TargetFile = ie.document.getElementById("ctl00_gvMain_ctl02_hlTitle")

    On Error Resume Next

    Dim wb As Workbook
    Set wb = Workbooks.Open(DownloadFile("C:\Users\User\Desktop\", TargetFile.href)) '< Replace with your download path here ending in "\" 

    On Error GoTo 0

    'Other stuff
    ie.Quit
End Sub

Public Function DownloadFile(ByVal downloadFolder As String, ByVal downloadURL As String) As String
    Dim http As Object , tempArr As Variant
    Set http =  CreateObject("WinHttp.WinHttpRequest.5.1")
    http.Open "GET", downloadURL, False
    http.send
    On Error GoTo errhand
    With CreateObject("ADODB.Stream")
        .Open
        .Type = 1
        .write http.responseBody
        tempArr = Split(downloadURL, "/")
        tempArr = tempArr(UBound(tempArr))
        .SaveToFile downloadFolder & tempArr, 2  '< "/" on enter of downloadFolder. 2 for overwrite which is Ok if no file modifications.
        .Close
    End With
    DownloadFile = downloadFolder & tempArr
    Exit Function
errhand:
    If Err.Number <> 0 Then
        Debug.Print Err.Number, Err.Description
        MsgBox "Download failed"
    End If
    DownloadFile = vbNullString
End Function

URLMon version:

Option Explicit

Public Const BINDF_GETNEWESTVERSION As Long = &H10

#If VBA7 And Win64 Then
    Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" _
    Alias "URLDownloadToFileA" ( _
    ByVal pCaller As LongPtr, _
    ByVal szURL As String, _
    ByVal szFileName As String, _
    ByVal dwReserved As LongPtr, _
    ByVal lpfnCB As LongPtr _
    ) As Long

#Else
    Private Declare Function URLDownloadToFile Lib "urlmon" _
                             Alias "URLDownloadToFileA" ( _
                             ByVal pCaller As Long, _
                             ByVal szURL As String, _
                             ByVal szFileName As String, _
                             ByVal dwReserved As Long, _
                             ByVal lpfnCB As Long _
                             ) As Long

#End If



Public Sub Searchstockcode()

    Dim SearchString As String, SearchBox As Object, SearchButton As Object, ie As Object

    SearchString = "2828"

    Set ie = CreateObject("InternetExplorer.Application")

    ie.Visible = True

    ie.navigate "http://www.hkexnews.hk/listedco/listconews/advancedsearch/search_active_main.aspx"

    While ie.Busy Or ie.readyState < 4: DoEvents: Wend

    Set SearchBox = ie.document.getElementById("ctl00_txt_stock_code")
    SearchBox.Value = SearchString

    Set SearchButton = ie.document.querySelector("[src*='/image/search.gif']")
    SearchButton.Click

    While ie.Busy Or ie.readyState < 4: DoEvents: Wend

    Dim TargetFile As Object
    Set TargetFile = ie.document.getElementById("ctl00_gvMain_ctl02_hlTitle")

    On Error Resume Next

    Dim wb As Workbook
    Set wb = Workbooks.Open(downloadFile("C:\Users\User\Desktop\", TargetFile.href)) '< Replace with your download path here ending in "\"

    On Error GoTo 0

    'Other stuff
    ie.Quit
End Sub


Public Function downloadFile(ByVal downloadFolder As String, ByVal URL As String) As String
    Dim tempArr As Variant, ret As Long
    tempArr = Split(URL, "/")
    tempArr = tempArr(UBound(tempArr))
    ret = URLDownloadToFile(0, URL, downloadFolder & tempArr, BINDF_GETNEWESTVERSION, 0)
    downloadFile = downloadFolder & tempArr
End Function
QHarr
  • 83,427
  • 12
  • 54
  • 101
  • 1
    Thanks QHarr! But I encountered an error at "Dim http As New WinHttp.WinHttpRequest". (Compile error: User-defined type not defined). Any chance I can solve this problem? – LLC Sep 09 '18 at 14:22
  • 1
    Yes. Sorry. One of two ways VBE > Tools > References and add reference for WinHTTP or use late bound. Try the edited version which is late bound. – QHarr Sep 09 '18 at 14:23
  • I was unable to reach the remaining codes after running "http.send". Any reason behind that? On top of that, I found that I was unable to perform the "TargetFile.click" function as pop-up is blocked (It's weird coz it is not blocked if I clicked it manually. It only happens if I click via macro). Yet I am using my computer at office, so I am not able to change the browser settings :( – LLC Sep 09 '18 at 14:31
  • 1
    Couple of things....1) There is no click involved 2) Are you running my code exactly as above EXCEPT adding your own download folder path? 3) Press Ctrl + G to open the immediate window... is there any error information printed there? Did you get a message box saying file download failed? – QHarr Sep 09 '18 at 14:34
  • 1+2) Sorry that I wasn't using your exact code above, but I am right now. Yet the code-skipping problem still exists. 3) Nth showed up there :( – LLC Sep 09 '18 at 14:38
  • Stil skips the lines after "http.send"..... Perhaps its the problem of my computer? Sometimes it skips codes without reason. Perhaps we can merge the codes instead of using function? Sometimes it works... – LLC Sep 09 '18 at 14:45
  • Nothing showed up in the immediate window, nor a messagebox. After the line "http.send", it jumped to "On error GoTo 0". – LLC Sep 09 '18 at 14:54
  • The code there seems to be the same as what I have right now? Anyways, I successfully used this code to generate a "download failed" message box on another laptop, which means my office laptop cannot run complicated functions. Therefore, I put those codes into the original sub and it can now give the "download failed" message box as well. The error happens at ".write http.responseBody". – LLC Sep 09 '18 at 15:06
  • Yes it is there :) – LLC Sep 09 '18 at 15:09
  • How should I split the file name like you did above "tempArr" using the URLMon? As my filename is always changing. Thanks – LLC Sep 09 '18 at 15:19
  • one more question: can I save it as a temporary file so that I can kill it right after extracting the data? How can it be done? – LLC Sep 09 '18 at 15:29
  • 1
    You have the folderpath to the file so you can use the kill command probably. E.g. https://stackoverflow.com/questions/67835/deleting-a-file-in-vba – QHarr Sep 09 '18 at 15:33
  • 1
    Thank you so much! You saved my life! – LLC Sep 09 '18 at 15:53