Street Scraping

Ever wanted to download Google Street View panoramas programmatically? If you said "yes!", then this is the code for you.
I reverse-engineered their URL query scheme using the Live HTTP Headers plug-in for Firefox. From there, I just parsed through the XML returned to download each jpeg tile and then stitch them together in order.
I used a variation of this code in combination with a few other programs to parse a GPS log, download the street view panorama for each position in the log, and then stitch each frame together into a video documenting my trip on the M5 bus.
- import processing.core.*;
- import processing.net.*;
- import processing.xml.*;
- // get a hold of this for the xml library
- // better way to do this part?
- PApplet main = this;
- void setup() {
- // we usually end up with 3328 x 1664 pixel images
- // let's undersample considerably for a more sane window size
- size(832, 416);
- // your google maps api key goes here
- // sign up: http://code.google.com/apis/maps/signup.html
- String apiKey = "REPLACE ME WITH YOUR VERY OWN API KEY";
- // pick a location
- // takes an address or a lat / lon
- String location = "721 broadway, new york, ny";
- // generate the panorama
- Panorama pano = new Panorama(location, apiKey);
- // show the image
- image(pano.fullPano, 0, 0, width, height);
- // save the full-res image to the sketch folder
- pano.fullPano.save(location + ".jpg");
- // skip the draw loop
- noLoop();
- }
- class Panorama {
- float lat;
- float lon;
- String panoId;
- int imageWidth;
- int imageHeight;
- int tileWidth;
- int tileHeight;
- int xTileCount;
- int yTileCount;
- PImage[][] tiles;
- PImage fullPano;
- String apiKey;
- // constructor
- Panorama(String address, String _apiKey) {
- apiKey = _apiKey;
- String[] location = geocode(address);
- lon = float(location[0]);
- lat = float(location[1]);
- fetchInfo(lat, lon);
- buildImage();
- }
- void fetchInfo(float lat, float lon) {
- String url = "http://maps.google.com/cbk?output=xml&ll=" + lat + "," + lon;
- XMLElement response = new XMLElement(main, url);
- XMLElement kid = response.getChild(0);
- imageWidth = kid.getIntAttribute("image_width");
- imageHeight = kid.getIntAttribute("image_height");
- tileWidth = kid.getIntAttribute("tile_width");
- tileHeight = kid.getIntAttribute("tile_height");
- panoId = kid.getStringAttribute("pano_id");
- xTileCount = imageWidth / tileWidth;
- yTileCount = imageHeight / tileHeight;
- println("Panorama ID: " + panoId);
- println("X Tile Count: " + xTileCount);
- println("Y Tile Count: " + yTileCount);
- }
- void buildImage() {
- fullPano = createImage(imageWidth, imageHeight, RGB);
- fullPano.loadPixels();
- for(int xPos = 0; xPos <= xTileCount; xPos++) {
- for(int yPos = 0; yPos <= yTileCount; yPos++) {
- // &.jpg fools processing into handling it
- String imageUrl = "http://cbk0.google.com/cbk?output=tile&panoid=" + panoId + "&zoom=3&x=" + xPos + "&y=" + yPos + "&.jpg";
- fullPano.set(xPos * tileWidth, yPos * tileHeight, loadImage(imageUrl));
- println("Loaded tile " + xPos + "::" + yPos);
- }
- }
- fullPano.updatePixels();
- }
- String[] geocode(String address) {
- String cleanAddress = address.replace(' ', '+');
- String url = "http://maps.google.com/maps/geo?q=" + cleanAddress + "&output=xml&oe=utf8&sensor=false&key=" + apiKey;
- println(url);
- XMLElement location = new XMLElement(main, url);
- XMLElement kid = location.getChild("Response/Placemark/Point/coordinates");
- String rawCoordinates = kid.getContent();
- String[] latlon = shorten(split(rawCoordinates, ',')); // ditch the 0
- println(latlon);
- return latlon;
- }
- }
Add Your Comment