Hack 45 Find Purchase Circles by Zip Code

figs/expert.giffigs/hack45.gif

Combining two different Web Services can create a new feature.

Finding purchase circles is pretty easy, and with a bit of scraping, you can tie them into geographic data. Amazon doesn't offer the ability to look up purchase circles by U.S. zip code, but using the USPS web site and some simple pattern matching, you can find purchase circles for all cities within a given zip code.

45.1 The Code

This PHP script combines two different services with screen scraping. It looks for all of the cities within a particular zip code at the U.S. Postal Service web site. Then it finds matching purchase circles at Amazon and provides links to them. Create zip_circle.php with the following code:

<?php
$strZip = $_GET['zipcode'];
$zipPage = "";
$indexPage = "";
$cntCity = 0;
$myCity = "";

set_time_limit(60);

//get a certain number of characters
function left($str_in,$num) {
    return ereg_replace("^(.{1,$num})[ .,].*","\\1", $str_in); 
}

function findCircle($city) {
    $indexPage = "";
    //Find purchase cirlce brose codes
    $abc = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
    $a_abc = split(",", $abc);
    $thisLetter = strtolower(substr($city,0,1));
    for($j = 0;$j < count($a_abc)-1; $j++) {
        if ($thisLetter == $a_abc[$j]) {
            $thisCode = 226120 + ($j + 1);
        }
    }
    $url = "http://www.amazon.com/exec/obidos/tg/cm/browse-communities/-/" . 
           $thisCode . "/t/";
    $contents = fopen($url,"r");
    do {
       $data = fread ($contents, 4096);                                     
       if (strlen($data) == 0) {                                            
          break;                                                             
       }                                                                    
       $indexPage .= $data;                                                 
   } while(1);
    fclose ($contents);
    $k = 0;
    if (preg_match_all('/i>.*?<a href=/exec/obidos/tg/browse/-/(.*?)/t/[RETURN]
.*?>(.*?)</a>.*?<l/s',$indexPage,$cities)) {
      foreach ($cities[2] as $cityName) {
        if (strtolower($city) == strtolower($cityName)) {
          $link = "http://www.amazon.com/exec/obidos/tg/cm/[RETURN]
browse-communities/-/";
          $link = $link . $cities[1][$k];
          $link = "<a href=" . $link . ">";
          $link = $link . $cityName . "</a>";
          return $link;
        }
        $k++;
       } // foreach
       return "No purchase circle found for " . $city;
    } //if
} //function

//Get cities associated with zip codes from USPS
$url = "http://www.usps.com/zip4/zip_response.jsp?zipcode=" . $strZip;
$contents = fopen($url,"r");
while (!feof ($contents))
    $zipPage .= fgets($contents, 4096);
fclose ($contents);

if (preg_match_all('/<tr valign="top" bgcolor=".*?">(.*?)</tr>/
s',$zipPage,$cityState)) {
    foreach ($cityState[0] as $cs) {
        $cntCity++;
        if (preg_match_all('/\n\n(.*?)</font></td>\n/',$cs,$c)) {
            foreach ($c[1] as $d) {
                $myCity = $myCity . $d . ", ";
            }
        $myCity = $myCity . Chr(8);
        $myCity = ereg_replace(", ".chr(8), chr(8), $myCity);
        } else {
            echo "city not found.";
        }
    }
}

echo "<h2>Purchase Circles</h2>";

$a_myCity = split(chr(8), $myCity);
for($i = 0;$i < count($a_myCity)-1; $i++) {
    $thisCity = $a_myCity[$i];
    echo findCircle($thisCity) . "<br>";
}
?>

Scraping both the USPS site and Amazon can take some time, so the time limit for the script has been increased to 60 seconds.

This script relies on the fact that certain purchase circle pages have predictable IDs. Armed with the knowledge that every city that starts with A is in Purchase Circle 226121, we can assume that cities that start with B will be in Purchase Circle ID 226122, etc. As cities are found at the USPS site, their first letter is matched up with a Purchase Circle ID, and the page is scraped to find an exact match.

45.2 Running the Hack

Upload this script to a web server and access the page providing a zip code in the querystring, like so:

http://your.server/zip_circle.php?zipcode=zip code

The result should be a list of links to Amazon purchase circles for cities in that code.