how to get bing api search results in MsOffice VBA

For the loyal VBA fans a quick snippet to grab search results from Bing in Access or Excel. There are few articles on the web about that, and that is a shame. So lets add some content on it to the web : first in MsAccess VBA and then in Excel, with a sample workbook added.

Working with the BING API requires an Application Id you can get at the Bing website.

Accessing the Bing Api in MsAccess VBA

In the the VBA Ide, through the menu Tools References I add a reference to the XML object library that contains the XMLHTTPRequest object, enabling me to make HTTP requests from VBA in the MsAccess database.

The simple part is the http request string :

  1.  
  2.         Dim MyKeyword As String
  3.         MyKeyword = "seo"
  4.        
  5.         Dim requestString As String
  6.         requestString = "http://api.bing.net/xml.aspx?"
  7.  
  8.         Dim AppId As String
  9.         AppId = "(get one at the bing website)"
  10.  
  11.        ' Common request fields (required)
  12.         requestString = requestString & _
  13.         "AppId=" & AppId & "&Query=" & MyKeyword & "&Sources=Web"
  14.  
  15.         ' Common request fields (optional)
  16.         requestString = requestString & _
  17.               "&Version=2.0" _
  18.             & "&Market=en-us" _
  19.             & "&Adult=Moderate" _
  20.             & "&Options="
  21.  
  22.         ' Web-specific request fields (optional)
  23.         requestString = requestString & _
  24.               "&Web.Count=10" _
  25.             & "&Web.Offset=0" _
  26.             & "&Web.Options=DisableHostCollapsing+DisableQueryAlterations"

Then comes the working part, sending the actual request and receiving the XML response (objSvrHTTP.responseText) containing the search data. I use a DomDocument object and XPath to get at the XML data.

First sending the request

  1.     objSvrHTTP.Open "GET", requestString, False
  2.     objSvrHTTP.send requestString

then creating a domdocument and receiving the response in it

  1.     'Create the DomDocument Object
  2.     Dim oDoc As MSXML2.DOMDocument
  3.     Set oDoc = CreateObject("MSXML2.DOMDocument")
  4.     oDoc.async = False
  5.     oDoc.validateOnParse = False
  6.      
  7.     'Load the response in the DomDocument Object
  8.     Dim fSuccess As Boolean
  9.     fSuccess = oDoc.loadXML(objSvrHTTP.responseText)
  10.     If Not fSuccess Then
  11.         MsgBox "failed"
  12.         Exit Sub
  13.     End If

The response uses two namespaces and the data we actually want is in the “web” namespace, so before we start selecting nodes in the xml-tree we first indicate what namespace we want to access :

  1.     oDoc.SetProperty "SelectionNamespaces", "xmlns:web='http://schemas.microsoft.com/LiveSearch/2008/04/XML/web'"

The total search result pages is a top level node in the namespace :

  1.     Set xmlnode = oDoc.selectSingleNode("//web:Total")
  2.     Debug.Print xmlnode.Text

…but the good stuff is in the “WebResult” nodes in the xml tree, I can use an XPath reference //web:Webresult to access that node-collection and with a simple for-next iterate through the collection, selecting the single nodes containing the actual data.

  1.     Set oChildren = oDoc.selectNodes("//web:WebResult")
  2.     For Each oResult In oChildren
  3.         Debug.Print oResult.selectSingleNode("./web:Title").Text
  4.         Debug.Print oResult.selectSingleNode("./web:Description").Text
  5.         Debug.Print oResult.selectSingleNode("./web:Url").Text
  6.         Debug.Print oResult.selectSingleNode("./web:DisplayUrl").Text
  7.         Debug.Print vbCrLf
  8.     Next

I output to the Immediate window aka Debug (under View, Immediate Window or Ctrl+G)

What can we do with it ? Let’s make a table for date, keyword, url, title, description, position

and add some code to store the results we retrieve

  1.     Dim table1 As DAO.Recordset
  2.     Set table1 = CurrentDb.OpenRecordset("Table1", dbOpenTable)
  3.     'counter for position    
  4.     i = 0
  5.    
  6.     Set oChildren = oDoc.selectNodes("//web:WebResult")
  7.     For Each oStruct In oChildren
  8.  
  9.        i = i + 1
  10.        With table1
  11.             .AddNew
  12.             'data from bing
  13.             !TITLE = oStruct.selectSingleNode("./web:Title").Text
  14.             !Description = oStruct.selectSingleNode("./web:Description").Text
  15.             !url = oStruct.selectSingleNode("./web:Url").Text
  16.             'and some additional data
  17.             !MYDATE = Now()
  18.             !POSITION = i
  19.             !KEYWORD = MyKeyword
  20.             'store the record
  21.             .Update
  22.         End With
  23.  
  24.     Next
  25.  
  26.     table1.Close

There now that scratches the seo itch :

MsAccess stuff is a bit hard to put on the web as sample, so I’ll make a quick one in Excel and put it up for download.

Accessing the Bing Api in Excel VBA

there you go : on sheet 1 you can fill in your AppID and keyword, click the butt(on…

…and on sheet 2 you get the top 10 search results

It uses the cells B1 and B2 as named ranges for MyKeyword and AppID, and has the code in the enclosed module. It also contains one of my AppId’s so no querying nasty shit, please.

integrating ms office and wordpress with vba and xml-rpc

Okay.

Yesterday I made some basic stuff to grab my WordPress blog data with visual basic for applicationsn cos I don’t feel like programming php admin pages for tables.

So let’s make a basic xml-rpc crud plugin and put my agenda on vba remote control.

The basic xml-rpc plugin is simple, plug extra methods into the xml-rpc method array, and write a function per crud-method.

  1.  
  2. add_filter( 'xmlrpc_methods', 'add_agenda_xmlrpc_methods' );
  3.  
  4. function add_agenda_xmlrpc_methods( $methods ) {
  5.     $methods['agenda.addAgendaItem'] = 'addAgendaItem';
  6.     $methods['agenda.updateAgendaItem'] = 'updateAgendaItem';
  7.     $methods['agenda.deleteAgendaItem'] = 'deleteAgendaItem';
  8.     $methods['agenda.reportAgendaItem'] = 'reportAgendaItem';
  9.     return $methods;
  10. }
  11.  
  12. function addAgendaItem($args) { }
  13.  
  14. function updateAgendaItem($args) { }
  15.  
  16. function deleteAgendaItem($args) { }
  17.  
  18. function reportAgendaItem($args) { }
  19.  
  20. //basic login helper function
  21. function CheckLogin($user, $pwd) {}

There now, if I call on the xmlrpc.php file, the extra methods are added to the callback array and I can use the table CRUD functions from my vba desktop.

  1. function addAgendaItem($args) {
  2.  
  3.         $blog_id = (int) $args[0];
  4.         $username = $args[1];
  5.         $password = $args[2];
  6.         $AgendaItem     = $args[3];
  7.  
  8. //remember : add a login check
  9. //(for the example it is irrelevant)
  10.  
  11.         global $wpdb;
  12.         $sql = "INSERT INTO ".$wpdb->prefix."Agenda (
  13.                `userid`, `tags`, `description`, `firstdate`, `enddate`, `link`, `price`, `location`
  14.                ) VALUES (
  15.                '".$AgendaItem[0]['userid']."',
  16.                '".$AgendaItem[0]['tags']."',
  17.                '".$AgendaItem[0]['description']."',
  18.                '".$AgendaItem[0]['firstdate']."',
  19.                '".$AgendaItem[0]['enddate']."',
  20.                '".$AgendaItem[0]['link']."',
  21.                '".$AgendaItem[0]['price']."',
  22.                '".$AgendaItem[0]['location']."'                
  23.                )";
  24.         $wpdb->query($wpdb->prepare($sql));
  25.  
  26.         return $wpdb->insert_id;
  27. }

note : the agendaitem is a struct in an array (see below), I use [0] to get the first struct (which is the actual array with field-value pairs, my record with agenda info).

Activate the plugin, and write a simple test

  1.  
  2. 'Type to hold an agenda info record
  3. Type AgendaItem
  4.     userid As String
  5.     tags As String
  6.     Description As String
  7.     firstdate As String
  8.     enddate As String
  9.     link As String
  10.     price As String
  11.     location As String
  12. End Type
  13.  
  14.  
  15. Function AddAgendaItem()
  16.  
  17. txtURL = "http://wwwblog.com/xmlrpc.php"
  18. txtUserName = "MyUsername"
  19. txtPassword = "MyPassword"
  20.  
  21.   Dim objSvrHTTP As ServerXMLHTTP
  22.   Dim strT As String
  23.   Set objSvrHTTP = New ServerXMLHTTP
  24.  
  25.   objSvrHTTP.Open "POST", txtURL, False, CStr(txtUserName), _
  26.    CStr(txtPassword)
  27.  
  28.   objSvrHTTP.setRequestHeader "Accept", "application/xml"
  29.   objSvrHTTP.setRequestHeader "Content-Type", "application/xml"
  30.  
  31.     strT = ""
  32.     strT = strT & "<methodcall>"
  33.     strT = strT & "<methodname>agenda.addAgendaItem</methodname>"
  34.    
  35.     strT = strT & "<params>"
  36.     strT = strT & "<param><value><string>" & txtBlogId & "</string></value></param>"
  37.     strT = strT & "<param><value><string>" & txtUserName & "</string></value></param>"
  38.     strT = strT & "<param><value><string>" & txtPassword & "</string></value></param>"
  39.  
  40. 'now we go make the struct, I use a Type (stdobject), normally
  41. 'you'd use a recordset
  42.  
  43. Dim a As AgendaItem
  44.  
  45. With a
  46.     .userid = 1
  47.     .Description = "rpc testing"
  48.     .firstdate = "2009/10/14"
  49.     .enddate = "2009/10/14"
  50.     .link = "http://www.juust.org/"
  51.     .price = "rpc testing"
  52.     .location = "limmen"
  53.     .tags = "php, xml-rpc"
  54. End With
  55.  
  56.     strT = strT & "<param><value><array>"
  57.     strT = strT & "<data>"
  58.    
  59.     strT = strT & "<value><struct>"
  60.  
  61.     strT = strT & "<member><name>userid</name><value><string>" & a.userid & "</string></value></member>"
  62.     strT = strT & "<member><name>tags</name><value><string>" & a.tags & "</string></value></member>"
  63.     strT = strT & "<member><name>description</name><value><string>" & a.Description & "</string></value></member>"
  64.     strT = strT & "<member><name>firstdate</name><value><string>" & a.firstdate & "</string></value></member>"
  65.     strT = strT & "<member><name>enddate</name><value><string>" & a.enddate & "</string></value></member>"
  66.     strT = strT & "<member><name>link</name><value><string>" & a.link & "</string></value></member>"
  67.     strT = strT & "<member><name>price</name><value><string>" & a.price & "</string></value></member>"
  68.     strT = strT & "<member><name>location</name><value><string>" & a.location & "</string></value></member>"
  69.  
  70. 'close the struct    
  71.     strT = strT & "</struct></value>"
  72.     strT = strT & "</data>"
  73.  
  74. 'close the struct array
  75.     strT = strT & "</array></value></param>"
  76.  
  77. 'end parameters
  78.     strT = strT & "</params>"
  79.  
  80. 'end method
  81.     strT = strT & "</methodcall>"
  82.  
  83. 'send the lot to the blog  
  84.   objSvrHTTP.send strT
  85.  
  86. 'print the response to debug
  87.   Debug.Print  objSvrHTTP.responseText
  88.  
  89. End function

Et voila :

agenda rpc

That’s yer basic Office-Wordpress XML-RPC integration.