<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tim laqua dot com &#187; vbscript</title>
	<atom:link href="http://timlaqua.com/tag/vbscript/feed/" rel="self" type="application/rss+xml" />
	<link>http://timlaqua.com</link>
	<description>Thoughts and Code from Tim Laqua</description>
	<lastBuildDate>Sun, 09 May 2010 15:25:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Monitoring, Starting, and Stopping Perfmon Performance Counter Logs using VBScript</title>
		<link>http://timlaqua.com/2008/11/monitoring-starting-and-stopping-perfmon-performance-counter-logs-using-vbscript/</link>
		<comments>http://timlaqua.com/2008/11/monitoring-starting-and-stopping-perfmon-performance-counter-logs-using-vbscript/#comments</comments>
		<pubDate>Wed, 26 Nov 2008 20:52:09 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Scripts & Code]]></category>
		<category><![CDATA[counter log]]></category>
		<category><![CDATA[counters]]></category>
		<category><![CDATA[logman]]></category>
		<category><![CDATA[perfmon]]></category>
		<category><![CDATA[performance counters]]></category>
		<category><![CDATA[registry]]></category>
		<category><![CDATA[syslog]]></category>
		<category><![CDATA[vbs]]></category>
		<category><![CDATA[vbscript]]></category>

		<guid isPermaLink="false">http://timlaqua.com/?p=53</guid>
		<description><![CDATA[Performance counters are great - unless they're not running. So this script illustrates one approach to monitoring the Performance Counter Logs on a given machine, starting them when they stop (for whatever reason) and letting someone know about it. I check the registry to determine the current state of a counter log, and use the [...]]]></description>
			<content:encoded><![CDATA[<p>Performance counters are great - unless they're not running.  <img src='http://timlaqua.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />   So this script illustrates one approach to monitoring the Performance Counter Logs on a given machine, starting them when they stop (for whatever reason) and letting someone know about it.</p>
<p>I check the registry to determine the current state of a counter log, and use the <strong>logman</strong> command line utility to start the log when needed.  Logman can also tell you the state of the counters, but it's crazy slow.  I've been unable to locate a way to do all of this using WMI and the interweb has been less helpful than usual on this issue.  So here's my solution:<br />
<span id="more-53"></span></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
</pre></td><td class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #000080;">Const</span> HKLM = &amp;H80000002
<span style="color: #000080;">Set</span> arrRunningCounterLogs = CreateObject( &quot;System.Collections.ArrayList&quot; )
<span style="color: #000080;">Set</span> arrStoppedCounterLogs = CreateObject( &quot;System.Collections.ArrayList&quot; )
<span style="color: #000080;">Set</span> dictCounterLogs = CreateObject( &quot;Scripting.Dictionary&quot; )
&nbsp;
<span style="color: #008000;">' ================= START Configuration Settings
</span>
strComputer = &quot;.&quot;
arrCounterLogExclusionList = Array(&quot;System Overview&quot;,&quot;PerfWiz&quot;)
strExchangeServer = &quot;smtpServer&quot;
strScriptEmailIdentity = &quot;&quot;&quot;PerfMonMon.vbs&quot;&quot; &lt;tim@timlaqua.com&gt;&quot;
strLogStartEmailRecipients = &quot;tim@timlaqua.com&quot;
&nbsp;
<span style="color: #008000;">' ================= END Configuration Settings
</span>
strBasePath =&quot;SYSTEM\CurrentControlSet\Services\SysmonLog\Log Queries&quot;
<span style="color: #000080;">Set</span> oReg=GetObject(&quot;winmgmts:{impersonationLevel=impersonate}!\\&quot; &amp; _ 
    strComputer &amp; &quot;\root\default:StdRegProv&quot;)
&nbsp;
oReg.EnumKey HKLM, strBasePath, arrSubKeys
<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> subkey <span style="color: #000080;">In</span> arrSubKeys
	strLogKeyPath = strBasePath &amp; &quot;\&quot; &amp; subkey
	oReg.GetStringValue HKLM, strLogKeyPath, &quot;Collection Name&quot;, strCollectionName
&nbsp;
	<span style="color: #000080;">If</span> <span style="color: #000080;">Not</span> InArray(strCollectionName, arrCounterLogExclusionList) <span style="color: #000080;">Then</span>
		dictCounterLogs.Add strCollectionName, strLogKeyPath
		<span style="color: #000080;">If</span> IsLogRunning(strCollectionName) <span style="color: #000080;">Then</span>
			arrRunningCounterLogs.Add(strCollectionName)
		<span style="color: #000080;">Else</span>
			arrStoppedCounterLogs.Add(strCollectionName)
		<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
	<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
<span style="color: #000080;">Next</span>
&nbsp;
<span style="color: #000080;">If</span> arrStoppedCounterLogs.Count &gt; 0 <span style="color: #000080;">Then</span>
	<span style="color: #000080;">Set</span> oShell = WScript.CreateObject(&quot;WScript.Shell&quot;)
	boolErrors = <span style="color: #000080;">False</span>
&nbsp;
	<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> strCounterLog <span style="color: #000080;">in</span> arrStoppedCounterLogs
		oShell.Run &quot;logman start &quot;&quot;&quot; &amp; strCounterLog &amp; &quot;&quot;&quot; -s &quot; &amp; strComputer, 0, <span style="color: #000080;">True</span>
&nbsp;
		<span style="color: #000080;">If</span> IsLogRunning(strCounterLog) <span style="color: #000080;">Then</span>
			strMessage = strMessage &amp; &quot;  &quot; &amp; strCounterLog &amp; _
						 &quot; was stopped - started log at &quot; &amp; Now &amp; vbCrLf
		<span style="color: #000080;">Else</span>
			strMessage = strMessage &amp; _
						 &quot;  <span style="color: #000080;">ERROR</span>: Unable <span style="color: #000080;">to</span> start &quot; &amp; strCounterLog &amp; vbCrLf
			boolErrors = <span style="color: #000080;">True</span>
		<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
	<span style="color: #000080;">Next</span>
&nbsp;
	<span style="color: #000080;">If</span> boolErrors <span style="color: #000080;">Then</span>
		strSubject = &quot;Stopped Counter Log Alert - Some counters could <span style="color: #000080;">not</span> be started&quot;
	<span style="color: #000080;">Else</span>
		strSubject = &quot;Stopped Counter Logs Detected - Counter Logs Started&quot;
	<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
&nbsp;
	SendEmail strExchangeServer, strScriptEmailIdentity, strLogStartEmailRecipients, strSubject, strMessage
<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
&nbsp;
<span style="color: #000080;">Function</span> InArray(needle, haystack) <span style="color: #008000;">'As Boolean
</span>	InArray = <span style="color: #000080;">False</span>
	<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> item <span style="color: #000080;">In</span> haystack
		<span style="color: #000080;">If</span> needle = item <span style="color: #000080;">Then</span> : InArray = <span style="color: #000080;">True</span> : <span style="color: #000080;">Exit</span> <span style="color: #000080;">Function</span> : <span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
	<span style="color: #000080;">Next</span>
<span style="color: #000080;">End</span> <span style="color: #000080;">Function</span>
&nbsp;
<span style="color: #000080;">Function</span> IsLogRunning(logName) <span style="color: #008000;">'As Boolean
</span>	IsLogRunning = <span style="color: #000080;">False</span>
	oReg.GetDWORDValue HKLM, dictCounterLogs(logName), &quot;Current State&quot;, dwCurrentState
	<span style="color: #000080;">If</span> dwCurrentState <span style="color: #000080;">Then</span>
		IsLogRunning = <span style="color: #000080;">True</span>
	<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
<span style="color: #000080;">End</span> <span style="color: #000080;">Function</span>
&nbsp;
<span style="color: #000080;">Sub</span> SendEmail(server, sender, recipient, subject, textbody)
	<span style="color: #000080;">Set</span> objMessage = CreateObject(&quot;CDO.Message&quot;) 
	objMessage.Subject = subject 
	objMessage.From = sender 
	objMessage.<span style="color: #000080;">To</span> = recipient 
	objMessage.TextBody = textbody
&nbsp;
	objMessage.Configuration.Fields.Item _
		(&quot;http://schemas.microsoft.com/cdo/configuration/sendusing&quot;) = 2 
	objMessage.Configuration.Fields.Item _
		(&quot;http://schemas.microsoft.com/cdo/configuration/smtpserver&quot;) = server
	objMessage.Configuration.Fields.Item _
		(&quot;http://schemas.microsoft.com/cdo/configuration/smtpserverport&quot;) = 25 
	objMessage.Configuration.Fields.Update
&nbsp;
	objMessage.Send 
<span style="color: #000080;">End</span> <span style="color: #000080;">Sub</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://timlaqua.com/2008/11/monitoring-starting-and-stopping-perfmon-performance-counter-logs-using-vbscript/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Changing Server Names in Excel 2007 Embedded Workbook Connections</title>
		<link>http://timlaqua.com/2008/09/changing-server-names-in-excel-2007-embeded-workbook-connections/</link>
		<comments>http://timlaqua.com/2008/09/changing-server-names-in-excel-2007-embeded-workbook-connections/#comments</comments>
		<pubDate>Mon, 29 Sep 2008 19:59:44 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Scripts & Code]]></category>
		<category><![CDATA[connections]]></category>
		<category><![CDATA[data sources]]></category>
		<category><![CDATA[embeded connections]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[excel 2007]]></category>
		<category><![CDATA[pivot table]]></category>
		<category><![CDATA[regular expressions]]></category>
		<category><![CDATA[ssas]]></category>
		<category><![CDATA[vbscript]]></category>

		<guid isPermaLink="false">http://timlaqua.com/?p=48</guid>
		<description><![CDATA[Ok, so you want to migrate servers, eh? Well - all your business users pry have a couple thousand Pivot Reports lying around that point to the old server. We need to point all references to the old server at the new server. There are two places these references exist (afaik) - The My Data [...]]]></description>
			<content:encoded><![CDATA[<p>Ok, so you want to migrate servers, eh?  Well - all your business users pry have a couple thousand Pivot Reports lying around that point to the old server.  We need to point all references to the old server at the new server.</p>
<p>There are two places these references exist (afaik) - The My Data Sources folder (Windows XP / Excel 2007) which holds all of the odc objects for the logged in user, and the real pain - Embedded data sources in Excel Workbooks.</p>
<p>For the odc objects - you can just loop through the My Data Sources folder files and do a little find/replace action.</p>
<p>For the Excel files - we need to first find all the files, then loop through them and hunt for embedded Connections.  Once we find a connection, we can just blindly replace occurrences of the old server name with the new server name.  The first thing we need here is a function we can call recursively to go hunt down all the excel files - then we loop through and play with the connections (when found).<br />
<span id="more-48"></span></p>
<p>Let me know how it goes!  Here's the full version:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
</pre></td><td class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #000080;">Set</span> regEx = <span style="color: #000080;">New</span> RegExp
regEx.IgnoreCase = <span style="color: #000080;">True</span>
regEx.Global = <span style="color: #000080;">True</span>
<span style="color: #000080;">Set</span> WshShell = Wscript.CreateObject(&quot;Wscript.Shell&quot;)
strMyDocsPath = WshShell.RegRead(&quot;HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Personal&quot;)
strDataSourceDir = strMyDocsPath &amp; &quot;\My Data Sources&quot;
&nbsp;
<span style="color: #008000;">'======================== Fix all the Data Sources
</span><span style="color: #000080;">Set</span> objFSO = CreateObject(&quot;Scripting.FileSystemObject&quot;)
<span style="color: #000080;">Set</span> Folder = objFSO.GetFolder(strDataSourceDir)
<span style="color: #000080;">Set</span> Files = Folder.Files
&nbsp;
<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> File <span style="color: #000080;">In</span> Files
	<span style="color: #000080;">If</span> LCase(Right(File.Name, 4)) = &quot;.odc&quot; <span style="color: #000080;">Then</span>
	    <span style="color: #000080;">Set</span> objReadFile = objFSO.OpenTextFile(File.Path, 1)
	    strContents = &quot;&quot;
&nbsp;
		<span style="color: #000080;">Do</span> <span style="color: #000080;">While</span> <span style="color: #000080;">Not</span> objReadFile.AtEndOfStream
			strContents = strContents &amp; objReadFile.ReadLine &amp; vbCrLf
		<span style="color: #000080;">Loop</span>
&nbsp;
	    objReadFile.<span style="color: #000080;">Close</span>
&nbsp;
		regEx.Pattern = &quot;(?=.*Data Source=OldCrappyServerName.*)(&lt;odc:ConnectionString&gt;.+&lt;/odc:ConnectionString&gt;)&quot;
&nbsp;
		<span style="color: #000080;">If</span> regEx.Test(strContents) <span style="color: #000080;">Then</span>
			<span style="color: #000080;">Set</span> colMatches = regEx.Execute(strContents)
&nbsp;
			<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> objMatch <span style="color: #000080;">in</span> colMatches
				strOldConnectionString = objMatch.SubMatches(0)
				regEx.Pattern = &quot;Data Source=OldCrappyServerName&quot;
				strNewConnectionString = regEx.Replace(strOldConnectionString, &quot;Data Source=NewAwesomeServerName&quot;)
				regEx.Pattern = strOldConnectionString
				strContents = regEx.Replace(strContents, strNewConnectionString)
			<span style="color: #000080;">Next</span>
&nbsp;
			<span style="color: #000080;">Set</span> objWriteFile = objFSO.CreateTextFile(File.Path, <span style="color: #000080;">True</span>)
			objWriteFile.Write strContents
			objWriteFile.<span style="color: #000080;">Close</span>
		<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
	<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
<span style="color: #000080;">Next</span>
&nbsp;
&nbsp;
<span style="color: #008000;">'================================ Fix all the embeded connections (yikes)
</span>
<span style="color: #000080;">Set</span> arrFileList = CreateObject( &quot;System.Collections.ArrayList&quot; )
<span style="color: #000080;">Set</span> objExcel = CreateObject(&quot;Excel.Application&quot;)
objExcel.DisplayAlerts = <span style="color: #000080;">False</span>
&nbsp;
populateExcelFileList(strMyDocsPath)
&nbsp;
<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> strFileName <span style="color: #000080;">In</span> arrFileList
	objExcel.Workbooks.<span style="color: #000080;">Open</span>(strFileName)
	<span style="color: #000080;">Set</span> objWorkbook = objExcel.Workbooks(1)
	<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> objWorkbook <span style="color: #000080;">in</span> objExcel.Workbooks
		<span style="color: #000080;">If</span> objWorkbook.Connections.Count &gt; 0 <span style="color: #000080;">Then</span>
			WScript.Echo strFileName
			<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> objConnection <span style="color: #000080;">in</span> objWorkbook.Connections
				strOldConnection =  objConnection.OLEDBConnection.Connection
				regEx.Pattern = &quot;OldCrappyServerName&quot;
				strNewConnection = regEx.Replace(strOldConnection, &quot;NewAwesomeServerName&quot;)
				objConnection.OLEDBConnection.Connection = strNewConnection
			<span style="color: #000080;">Next</span>
&nbsp;
		<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
&nbsp;
		objWorkbook.<span style="color: #000080;">Close</span> <span style="color: #000080;">True</span>
	<span style="color: #000080;">Next</span>
&nbsp;
	objExcel.Quit
<span style="color: #000080;">Next</span>
&nbsp;
<span style="color: #000080;">Function</span> populateExcelFileList(path)
	<span style="color: #000080;">Set</span> pathFolder = objFSO.GetFolder(path)
	<span style="color: #000080;">Set</span> pathFiles = pathFolder.Files
	<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> pathSubFolder <span style="color: #000080;">in</span> pathFolder.SubFolders
		populateExcelFileList(pathSubFolder.Path)
	<span style="color: #000080;">Next</span>
&nbsp;
	<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> pathFile <span style="color: #000080;">in</span> pathFiles
		<span style="color: #000080;">If</span> (LCase(Right(pathFile.Name, 5)) = &quot;.xlsx&quot; _
			<span style="color: #000080;">Or</span> LCase(Right(pathFile.Name, 4)) = &quot;.xls&quot;) _
			<span style="color: #000080;">And</span> Left(pathFile.Name, 1) &lt;&gt; &quot;~&quot; <span style="color: #000080;">Then</span>
			arrFileList.Add pathFile.Path
		<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
	<span style="color: #000080;">Next</span>
<span style="color: #000080;">End</span> <span style="color: #000080;">Function</span></pre></td></tr></table></div>

<p><strong><em>Update</em></strong><br />
I added in support for .xls files - doing this against .xls files can (and usually will) break backwards compatibility for SSAS Pivot Tables.</p>
]]></content:encoded>
			<wfw:commentRss>http://timlaqua.com/2008/09/changing-server-names-in-excel-2007-embeded-workbook-connections/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Aggregating Seller Feedback from Amazon.com</title>
		<link>http://timlaqua.com/2008/04/aggregating-seller-feedback-from-amazoncom/</link>
		<comments>http://timlaqua.com/2008/04/aggregating-seller-feedback-from-amazoncom/#comments</comments>
		<pubDate>Sat, 05 Apr 2008 05:35:12 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Scripts & Code]]></category>
		<category><![CDATA[ecommerce]]></category>
		<category><![CDATA[vbscript]]></category>
		<category><![CDATA[xmlhttp]]></category>

		<guid isPermaLink="false">http://timlaqua.com/?p=4</guid>
		<description><![CDATA[I received a request from a professor to aggregate all of the feedback for a given Amazon.com seller. The problem is that Amazon.com seller feedback is displayed 25 at a time on the feedback page and, of course, even if we could get all of them on one page, there is NO way we're going [...]]]></description>
			<content:encoded><![CDATA[<p>I received a request from a professor to aggregate all of the feedback for a given Amazon.com seller.  The problem is that Amazon.com seller feedback is displayed 25 at a time on the feedback page and, of course, even if we could get all of them on one page, there is NO way we're going to manually move all the records to a database when there are 50,000+ feedback records.</p>
<p>In this post, I will discuss one approach to solving this problem<br />
<span id="more-4"></span><br />
<u><strong>Plan A - Use the Amazon.com API</strong></u><br />
After some research, I came up with this query to pull feedback via their ECS api doodad:</p>
<pre>

http://ecs.amazonaws.com/onca/xml?

  Service=AWSECommerceService&#038;
  AWSAccessKeyId=[myKEYID]&#038;
  Operation=SellerLookup&#038;
  SellerId=[SELLERID]&#038;
  ResponseGroup=Seller&#038;
  FeedbackPage=1
</pre>
<p>So that's nice... but it only returns 5 records.  On top of that, the valid range of FeedbackPage is 1-10, so it only allows a maximum of 50 (5 records per page by 10 pages) records.  Not cool.</p>
<p><u><strong>Plan B - Scraping HTML pages via XMLHTTP</strong></u><br />
<strong>Step 1: Figure out what pages we want to scrape</strong><br />
Lets start here:<br />
<a href="http://www.amazon.com/gp/help/seller/feedback.html?ie=UTF8&#038;asin=0471789569&#038;marketplaceSeller=1&#038;seller=ADWEDOQFWH4RS">http://www.amazon.com/gp/help/seller/feedback.html?ie=UTF8&#038;asin=0471789569&#038;marketplaceSeller=1&#038;seller=ADWEDOQFWH4RS</a></p>
<p>There's a "Next Page" link at the bottom that goes here:<br />
<a href="http://www.amazon.com/gp/help/seller/feedback.html?ie=UTF8&#038;asin=0471789569&#038;pageNumber=1&#038;marketplaceSeller=1&#038;seller=ADWEDOQFWH4RS">http://www.amazon.com/gp/help/seller/feedback.html?ie=UTF8&#038;asin=0471789569&#038;pageNumber=1&#038;marketplaceSeller=1&#038;seller=ADWEDOQFWH4RS</a></p>
<p>Notice that the distinguishing query parameter is <strong>pageNumber</strong>.  So, for simplicity, lets see if pageNumber=0 yields the first page:<br />
<a href="http://www.amazon.com/gp/help/seller/feedback.html?ie=UTF8&#038;asin=0471789569&#038;pageNumber=0&#038;marketplaceSeller=1&#038;seller=ADWEDOQFWH4RS">http://www.amazon.com/gp/help/seller/feedback.html?ie=UTF8&#038;asin=0471789569&#038;pageNumber=0&#038;marketplaceSeller=1&#038;seller=ADWEDOQFWH4RS</a></p>
<p>Ok, that worked as expected.  Now, lets see what happens when we get to the last page (actually, the page after last) by thowing in a huge page number:<br />
<a href="http://www.amazon.com/gp/help/seller/feedback.html?ie=UTF8&#038;asin=0471789569&#038;pageNumber=5000&#038;marketplaceSeller=1&#038;seller=ADWEDOQFWH4RS">http://www.amazon.com/gp/help/seller/feedback.html?ie=UTF8&#038;asin=0471789569&#038;pageNumber=5000&#038;marketplaceSeller=1&#038;seller=ADWEDOQFWH4RS</a></p>
<p>Perfect - no records.  So now for a given seller, we can just start at pageNumber 0 and keep going up until the returned page doesn't have any feedback on it.</p>
<p><strong>Step 2 - What's a record look like?</strong><br />
We need to define a regular expression pattern to identify a feedback record in the HTML pages.  Now, this doesn't have to be perfect, it just has to work for now.  These patterns will be dependant on the HTML formatting of the site (if they don't use IDs - Amazon.com doesn't) - so if they change formatting too much, we'll have to make a new pattern.  No real big deal, but it is important to note that this isn't an exact science.  Just make it work.</p>
<p>View the feedback page source and locate a record:</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;">            <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">tr</span>&gt;</span>
              <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">td</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;120&quot;</span> <span style="color: #000066;">valign</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;top&quot;</span> <span style="color: #000066;">bgcolor</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#F6F6F6&quot;</span>&gt;</span>
                <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;small&quot;</span>&gt;</span>
                  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">font</span> <span style="color: #000066;">color</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#009900&quot;</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">b</span>&gt;</span>5<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">b</span>&gt;</span> out of <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">b</span>&gt;</span>5<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">b</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">font</span>&gt;</span>:
                <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">span</span>&gt;</span>
              <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">td</span>&gt;</span>
              <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">td</span> <span style="color: #000066;">bgcolor</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#F6F6F6&quot;</span>&gt;</span>
                <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;small&quot;</span>&gt;</span>
                  &quot;none&quot;
                  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">br</span> <span style="color: #66cc66;">/</span>&gt;</span>
                  Date: 4/4/2008 <span style="color: #ddbb00;">&amp;nbsp;&amp;nbsp;&amp;nbsp;</span> Rated by Buyer: Jason M.
                <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">span</span>&gt;</span>
              <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">td</span>&gt;</span>
            <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">tr</span>&gt;</span></pre></div></div>

<p>Now - I find it's easiest for this sort of thing to just ignore tabs(\t), newline characters(\n) and carridge return characters(\r) because we will just strip all those before we apply the pattern.</p>
<p>Locate the pieces of info you want to scrap in HTML and convert to a regular expression</p>
<table>
<tr>
<th>Target Data</tr>
<th>HTML</th>
<th>RegEx Pattern</tr>
</tr>
<tr>
<td>Feedback rating</td>
<td>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">b</span>&gt;</span>5<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">b</span>&gt;</span> out of <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">b</span>&gt;</span>5<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">b</span>&gt;</span></pre></div></div>

</td>
<td>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">&lt;b&gt;(\d)&lt;/b&gt; out of &lt;b&gt;(\d)&lt;/b&gt;</pre></div></div>

</td>
</tr>
<tr>
<td>Comment</td>
<td>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;">                <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;small&quot;</span>&gt;</span>
                  &quot;none&quot;
                  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">br</span> <span style="color: #66cc66;">/</span>&gt;</span></pre></div></div>

</td>
<td>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">&lt;span class=&quot;&quot;small&quot;&quot;&gt;(.*?)&lt;br /&gt;</pre></div></div>

</td>
</tr>
<tr>
<td>Date</td>
<td>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;">Date: 4/4/2008</pre></div></div>

</td>
<td>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Date:\s+(\d\d?/\d\d?/\d{4})</pre></div></div>

</td>
</tr>
<tr>
<td>User name</td>
<td>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;">Rated by Buyer: Jason M.
                <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">span</span>&gt;</span></pre></div></div>

</td>
<td>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Rated by Buyer: (.*?)&lt;</pre></div></div>

</td>
</tr>
</table>
<p>And then we just glue it all together with LAZY wildcard matches:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">&lt;b&gt;(\d)&lt;/b&gt; out of &lt;b&gt;(\d)&lt;/b&gt;.*?&lt;span class=&quot;&quot;small&quot;&quot;&gt;(.*?)&lt;br /&gt;.*?Date:\s+(\d\d?/\d\d?/\d{4}).*?Rated by Buyer: (.*?)&lt;</pre></div></div>

<p><strong>Step 3: Implement!</strong></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
</pre></td><td class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #008000;">'********************************************************
</span><span style="color: #008000;">'* amazonSellerFeedback.vbs
</span><span style="color: #008000;">'* Tim Laqua, 2008
</span><span style="color: #008000;">'* 
</span><span style="color: #008000;">'* Usage: amazonSellerFeedback.vbs SELLERID[,SELLERID[,SELLERID,[...]]]
</span><span style="color: #008000;">'********************************************************
</span><span style="color: #000080;">Set</span> http = createObject(&quot;Microsoft.XMLHTTP&quot;)
<span style="color: #000080;">Set</span> regEx = <span style="color: #000080;">New</span> RegExp
regEx.IgnoreCase = <span style="color: #000080;">True</span>
regEx.Global = <span style="color: #000080;">True</span>
&nbsp;
<span style="color: #008000;">' Get the Seller(s) from the command line
</span><span style="color: #000080;">Set</span> objArgs = WScript.Arguments
<span style="color: #000080;">If</span> objArgs.Count &lt; 1 <span style="color: #000080;">Then</span>
  WScript.Echo &quot;Please specify seller ID&quot;
  WScript.Quit
<span style="color: #000080;">End</span> <span style="color: #000080;">If</span>
&nbsp;
<span style="color: #008000;">' We allow multiple sellers separated by commas, so split the sellers on a comma
</span>arrSellers = Split(objArgs.Item(0), &quot;,&quot;)
&nbsp;
<span style="color: #008000;">' Loop for each seller
</span><span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> strSeller <span style="color: #000080;">in</span> arrSellers
  WScript.Echo &quot;Processing Seller: &quot; &amp; strSeller
  intPage = 1
&nbsp;
  <span style="color: #008000;">' This pattern identifies a single feedback record
</span>  strRecordPattern = &quot;&lt;b&gt;(\d)&lt;/b&gt; out of &lt;b&gt;(\d)&lt;/b&gt;.*?&quot; &amp; _
                            &quot;&lt;span class=&quot;&quot;small&quot;&quot;&gt;(.*?)&lt;br /&gt;.*?&quot; &amp; _
                            &quot;Date:\s+(\d\d?/\d\d?/\d{4}).*?&quot; &amp; _
                            &quot;Rated by Buyer: (.*?)&lt;&quot;
&nbsp;
  intTimerStart = Timer
&nbsp;
  <span style="color: #008000;">' Create the output file
</span>  strFileName = &quot;amazonSellerFeedback_&quot; &amp; strSeller &amp; &quot;.csv&quot;
  <span style="color: #000080;">Set</span> objFSO = CreateObject(&quot;Scripting.FileSystemObject&quot;)
  <span style="color: #000080;">Set</span> objTextFile = objFSO.CreateTextFile(strFileName, <span style="color: #000080;">True</span>)
&nbsp;
  <span style="color: #008000;">' Write column headers
</span>  objTextFile.WriteLine &quot;Seller,Rating,Comment,<span style="color: #000080;">Date</span>,User&quot;
&nbsp;
  <span style="color: #008000;">' Populate strFeedbackText with first feedback page
</span>  strFeedbackText = getFeedback(intPage)
  regEx.Pattern = strRecordPattern
&nbsp;
  <span style="color: #008000;">' Keep going until the page doesn't have any feedback records on it
</span>  <span style="color: #000080;">Do</span> <span style="color: #000080;">While</span> regEx.Test(strFeedbackText)
    Wscript.Echo &quot;Processing records &quot; &amp; intPage*25 &amp; &quot;-&quot; &amp; (intPage+1)*25
&nbsp;
    <span style="color: #000080;">Set</span> colMatches = regEx.Execute(strFeedbackText)
    <span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> objMatch <span style="color: #000080;">in</span> colMatches
      strRecord = strSeller &amp; &quot;,&quot; &amp; _
            objMatch.SubMatches(0) &amp; &quot;,&quot; &amp; _
            &quot;&quot;&quot;&quot; &amp; Replace(Trim(objMatch.SubMatches(2)),&quot;&quot;&quot;&quot;,&quot;&quot;&quot;&quot;&quot;&quot;) &amp; &quot;&quot;&quot;,&quot; &amp; _
            Trim(objMatch.SubMatches(3)) &amp; &quot;,&quot; &amp; _
            &quot;&quot;&quot;&quot; &amp; Replace(Trim(objMatch.SubMatches(4)),&quot;&quot;&quot;&quot;,&quot;&quot;&quot;&quot;&quot;&quot;) &amp; &quot;&quot;&quot;&quot;
&nbsp;
      <span style="color: #008000;">'Write record to file
</span>      objTextFile.WriteLine(strRecord)
&nbsp;
    <span style="color: #000080;">Next</span>
    intPage = intPage + 1
    strFeedbackText = getFeedback(intPage)
    regEx.Pattern = strRecordPattern
  <span style="color: #000080;">Loop</span> 
&nbsp;
  WScript.Echo &quot;Processing Finished...&quot; &amp; vbCrLf
  objTextFile.<span style="color: #000080;">Close</span>
&nbsp;
  <span style="color: #008000;">' Stats and status messages
</span>  WScript.Echo &quot;Data Saved <span style="color: #000080;">to</span> &quot; &amp; strFileName
  intProcTime = Timer - intTimerStart
  WScript.Echo &quot;Processing Time: &quot; &amp; intProcTime &amp; &quot; seconds&quot;
  WScript.Echo &quot;Per Record Time: &quot; &amp; Round(intProcTime/((intPage - 1)*25), 4)
<span style="color: #000080;">Next</span>
&nbsp;
<span style="color: #008000;">' Function to retreive a a given feedback page for the current strSeller
</span><span style="color: #000080;">Function</span> getFeedback(intFeedbackPage)
  strURL =   &quot;http://www.amazon.com/gp/help/seller/feedback.html?&quot; &amp; _
        &quot;ie=UTF8&amp;&quot; &amp; _
        &quot;asin=0471789569&amp;&quot; &amp; _
        &quot;pageNumber=&quot; &amp; intPage &amp; &quot;&amp;&quot; &amp; _
        &quot;seller=&quot; &amp; strSeller
&nbsp;
  http.<span style="color: #000080;">open</span> &quot;GET&quot;, strURL, <span style="color: #000080;">False</span>
  http.send
&nbsp;
  regEx.Pattern = &quot;\n|\r|\t&quot;
  strMungedResponse = regEx.Replace(http.responseText, &quot;&quot;)
&nbsp;
  getFeedback = strMungedResponse
<span style="color: #000080;">End</span> <span style="color: #000080;">Function</span></pre></td></tr></table></div>

<p>Screenshot of the script running in 7 different threads (I got impatient):<br />
<a href="/wp-content/uploads/2008/04/amazonsellerfeedback_7threads_done.jpg" title="Enlarge"><img src="/wp-content/uploads/2008/04/amazonsellerfeedback_7threads_done.jpg" width="600px" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://timlaqua.com/2008/04/aggregating-seller-feedback-from-amazoncom/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
