Excel VBA query external .aspx page and retrieve data - asp.net

I've been struggling with this for about a day. Basically, I want to write an excel macro to loop through a list in excel, query a webpage and retrieve some data. Ideally I just want to retrieve the data I need so I can place it in an adjacent cell, but I'd do whatever it takes at this point.
The page is ASP.net, which I have no experience in; if it was .php I could probably manage, but I’m not even sure how to post to .aspx through javascript.
I can loop through my data just fine, and once I get the data I can write it to excel, so there are two parts I’m struggling with:
Part 1 – querying the webpage
This is the page I want to query. I need to search in Property Address and retrieve data from the results. The address I'll use for the example is 400 W Church St. I thought it may be simple to submit a form like ".../ParcelSearch.aspx?name=...&value=...", but no dice.
Part 2 – grabbing the data
On the results, there is a table DetailsSummary_Master up top, with fieldsets that are defined with <legend> tags. I need the data in <legend>Municipality</legend>:
I can’t figure out what to do, loop through the <td>s? I thought maybe I could GetElementByID or maybe by tag, but I can’t seem to figure it out.
VBA
I used a few SO threads to try to figure it out so far. First, Second and Third, but I can't even seem to get it to POST properly. I'm keeping the subs separate for now.
This is what I have (stolen from the other thread) in regards to my problem:
Sub SubmitForm()
Dim objIE As Object
Dim xmlhttp As Object
Dim ieButton As Object
Dim strResponse As String
Dim strUrl As String
Dim strID As String
Dim strValue As String
Dim strSubmit As String
strID = "?name=ctl00_ctl00_ctl00_ctl00_ContentMain_ContentMain_ContentMain_ContentMain_TabContainer1_Searches_SubTabContainer1_QuickSearches_CompositAddressSearch1_AddressSearch1_ctl00_Address&value="
strValue = "400 W Church St"
strSubmit = strID & strValue
strUrl = "http://www.ocpafl.org/searches/ParcelSearch.aspx"
Set objIE = CreateObject("InternetExplorer.Application")
objIE.navigate "about:blank"
Set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
'~~> Indicates that page that will receive the request and the type of request being submitted
xmlhttp.Open "POST", "http://www.ocpafl.org/searches/ParcelSearch.aspx", False
'~~> Indicate that the body of the request contains form data
xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
'~~> Send the data as name/value pairs
xmlhttp.Send "strSubmit"
strResponse = xmlhttp.responseText
objIE.navigate strUrl
objIE.Visible = True
Do While objIE.readystate <> 4
DoEvents
Loop
objIE.document.Write strResponse
Set xmlhttp = Nothing
End Sub
I don't actually need to run it through IE, I'd like to run it all hidden. I'm running this on Excel 2007 at work, but I have 2010 at home. We also have ridiculous IE8, so the less of that, the better. And I can loop or use an array, but I just can't seem to interface with the query. Any help would be greatly appreciated.

For making the query, given the complexity of the form fields that the ASPX page is expecting on postback, you might find it easier to control the browser when making this call. It will be rather slow, but it should work.
A fairly reliable tool for this is Selenium, and there are plugins to control Selenium from Excel VBA.
Edit: This Excel VBA code snippet should read out "Municipality Orlando". You need to parameterize the below code and add cases for error conditions for your final version to query by any street address to get its municipality. This should get you started though. I used Selenium IDE with Firefox to generate the VBA code based on recording user actions, and then came up with an XPath query to grab the text.
Dim selenium As New SeleniumWrapper.WebDriver
selenium.Start "firefox", "http://www.ocpafl.org/searches/ParcelSearch.aspx"
selenium.setImplicitWait 5000
selenium.setImplicitWait 5000
selenium.Open "/searches/ParcelSearch.aspx"
selenium.Click "id=popup_ok"
selenium.Type "id=ctl00_ctl00_ctl00_ctl00_ContentMain_ContentMain_ContentMain_ContentMain_TabContainer1_Searches_SubTabContainer1_QuickSearches_CompositAddressSearch1_AddressSearch1_ctl00_Address", "400 W Church St"
selenium.Click "id=ctl00_ctl00_ctl00_ctl00_ContentMain_ContentMain_ContentMain_ContentMain_TabContainer1_Searches_SubTabContainer1_QuickSearches_PropertyNameSearch1_ctl00"
selenium.Click "id=ctl00_ctl00_ctl00_ctl00_ContentMain_ContentMain_ContentMain_ContentMain_TabContainer1_Searches_SubTabContainer1_QuickSearches_CompositAddressSearch1_AddressSearch1_ctl00_ActionButton1"
Dim municipalityResult As String
municipalityResult = selenium.getText("//fieldset[contains(legend,'Municipality')]")
selenium.stop

Related

Access request after upload (ASP classic)

So, as I figured out, when I have a form with enctype="multipart/form-data" and I upload a file, I can no longer access the object request. The following error is shown:
Cannot use the generic Request collection after calling BinaryRead.
After checking some resources, I stumpled upon a statement, which says: "This is by design". Well, okay, not here to judge about design-decisions.
To give you a quick overview, let me walk you through the code:
if request("todo") = "add" then
Set Form = New ASPForm
category = request("category")
title = request("title")
if len(Form("upload_file").FileName) > 0 then
filename = Form("upload_file").FileName
DestinationPath = Server.mapPath("personal/allrounder/dokumente/")
Form.Files.Save DestinationPath
end if
end if
Nothing too special here so far. Later however, when I try to access my request object, the error mentioned above occures:
<% if request("todo") = "new" then %>
...
My question now, how to get rid of it or fix this. I don't want to open the upload in a popup if there is another way around. This is the only solution I could think off.
Perfectly would be an object, which checks Form and request. Alternatively maybe a check at the top of the file, which object I have to use?
Thanks for any suggestions.
There used to be a very popular ASP class/component that solved ASP file uploads. The site for that component has been taken down, but the code is mirrored here:
https://github.com/romuloalves/free-asp-upload
You can include this ASP page on your own page, and on your page instantiate the class to get access to the files in your form, but also to the form variables. Here is a piece of example code (Upload.Form accesses the form fields):
Dim uploadsDir : uploadsDir = server.mapPath(".") ' whatever you want
Dim Upload, ks, fileKey, mailto
Set Upload = New FreeASPUpload
call Upload.Save(uploadsDir)
ks = Upload.UploadedFiles.keys
for each fileKey in ks
Response.write(fileKey & " : " & Upload.UploadedFiles(fileKey).FileName & "<br/>")
next
mailto = Upload.form("mailTo")
Set Upload = Nothing
If you want to stick to your own implementation, you can probably figure out how to get to the form variables in a multipart/form-data encoded data stream by having a look at the code they use to do so.

ASP.NET Export - Response not ending?

I'm trying to export some text to a text file, and that part works fine. The trouble is that the text files get a bunch of HTML/.NET output at the bottom of them... In other words, it's like the response isn't ending and the page is trying to write the rest of the page. Here's the code:
Private Sub WriteData(ByRef Context As System.Web.HttpContext, Data As List(of String), fileName as String)
With Context.Response
.Clear()
.ClearHeaders()
.ClearContent()
.AddHeader("content-disposition", String.Format("attachment; filename={0}", fileName))
.ContentType = contentType
End With
For Each curValue in Data
Context.Response.Write(curValue)
Context.Response.Write(Environment.NewLine)
Next
Context.ApplicationInstance.CompleteRequest()
Context.Response.End()
End Sub
To call this, I just pass the HttpContext.Current and a list of data.
Does anybody know why this might happen? I'm not sure how to interpret it, and I've looked all over without much luck. My assumption was that the response wasn't actually ending with "Response.End()"...
Thanks,
Mike
My assumption is that you're using an .aspx to do this.
This would be a perfect scenario for a Generic Handler. Try using .ashx instead.
Here is a pretty simple tutorial if you need more info:
http://www.brainbell.com/tutorials/ASP/Generic_Handlers_%28ASHX_Files%29.html

QueryString not accepting & - Needs to

I need to be able to handle an HTML encoded ampersand in my .Net code.
So the Url is
http://myite.com/index.aspx?language=en&Refresh=true
There is no way of changing this as it has been generated by something else so this is out of my control.
How can I read the Refresh parameter?
I have tried
HttpUtility.UrlDecode(Request.QueryString("Refresh"))
but my Request.QueryString("Refresh") is actually empty, so this is pointless, as is Uri.EscapeDataString.
This can't be the first time this has happened, but I'm struggling to find a solution, as most people would say use UrlEncoding, but as I said, the Url is out of my control.
& in your query string should be %26.
Since you can't correct the url.
You can read the refresh value as:
Request.QueryString("amp;Refresh");
Note that the developer of the service you are using may correct this in future.
It would be good to be ready for that already.
var refresh = Request.QueryString("amp;Refresh");
if(String.IsNullOrEmpty(refresh))
refresh = Request.QueryString("Refresh");
nunespascal answer pretty much solves your problem. There are some alternate methods.
If its guaranteed that your Refresh parameter is the second key in the QueryStringCollection then you can use Request.QueryString(1)
Another method is to do a Contains on the QueryStringCollection.
If Request.QueryString IsNot Nothing AndAlso Request.QueryString.AllKeys.Count() > 0 Then
Dim refreshKey = Request.QueryString.AllKeys.FirstOrDefault(Function(nv) nv.Contains("Refresh"))
If refreshKey IsNot Nothing Then
Dim refreshValue = Request.QueryString(refreshKey)
End If
End If

.Net Streamwriter putting exclamation mark in XML feed

When using HttpWebRequest to submit xml post data to a remote server, it inserts exclamation marks throughout the xml data when it sends it, causing the SOAP server to reject it and abort the connection. I have a HTML form submitter and it submits the xml in a textarea just fine without errors.
Here is my basic page logic for submitting the xml data, I have tried using the byte array as well but got the same errors.
Dim submitPage As HttpWebRequest = WebRequest.Create(requestUrl)
submitPage.Method = "POST"
Dim postData As StringBuilder = New StringBuilder()
postData.Append("Submit+XML=Submit&xmldata=" & System.Web.HttpUtility.UrlEncode(CompiledXML))
Dim writer As StreamWriter = Nothing
submitPage.ContentLength = postData.ToString().Length
writer = New StreamWriter(submitPage.GetRequestStream())
writer.Write(postData.ToString())
writer.Close()
So what happens here is is takes my XML string and puts it in the post but it also puts in exclamation marks about every 10 lines.
I have been working on this problem a couple days with no luck.
This was a bug in PHP on the remote server, where if you had a string over a certain length and you stuff it into the email function without line breaks it puts in exclamation points for you. Very odd behaviour but that was what was happening here.

Emulate Excel Web Query in .net

I need to emulate an Excel Web Query in .net Below is the sample code. I get an Error500 when I attempt to do this in .net, however in Excel it works fine. Any ideas on what I am doing wrong? When I change the URI to a normal website it works fine, and returns the html from the page, which i what i am after. I wonder if the problem lies from the fact that I am trying to return a datatable
Dim oHttpWebRequest As System.Net.HttpWebRequest
Dim oStream As System.IO.Stream
Dim sChunk As String
oHttpWebRequest = (System.Net.HttpWebRequest.Create("http://somesite/foo.jsp"))
Dim oHttpWebResponse As System.Net.WebResponse = oHttpWebRequest.GetResponse()
oStream = oHttpWebResponse.GetResponseStream
sChunk = New System.IO.StreamReader(oStream).ReadToEnd()
oStream.Close()
oHttpWebResponse.Close()
Here is the Query from Excel
WEB
1
http:/somesite/foo.jsp
Selection=DataTable
Formatting=None
PreFormattedTextToColumns=True
ConsecutiveDelimitersAsOne=True
SingleBlockTextImport=False
DisableDateRecognition=False
DisableRedirections=False
Edit
I am getting the error when I getReponse from the server
I found the problem I was having.
I used fiddler to figure out the headers that were being sent via excel and compared those with the headers .net was sending
http://www.fiddler2.com/Fiddler2/version.asp
I had to add the following lines of code to add these two headers in order for it to work
oHttpWebRequest.Headers.Add(HttpRequestHeader.Pragma, "no-cache")
oHttpWebRequest.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-us")

Resources