14

Real World Problem:

I have my app hosted on Heroku, who (to my knowledge) are unable to offer a solution for running a Headless (GUI-less) Browser - such as HTMLUnit - for generating HTML Snapshots for Googlebot to index my AJAX content.

My Proposed Solution:

If you haven't already, I suggest reading Google's Full Specification for Making AJAX Applications Crawlable.

Imagine I have:

  • a Sinatra app hosted on Heroku on the domain http://example.com
  • the app has tabs along the top of the page TabA, TabB and TabC
  • under each tab is SubTab1, SubTab2, SubTab3
  • onload if the url is http://example.com#!tab=TabA&subtab=SubTab3 then client-side Javascript takes the location.hash and loads in TabA, SubTab3 content via AJAX.

Note: the Hash Bang (#!) is part of the google spec.

I would like to build a simple "web service" hosted on Google App Engine (GAE) that:

  1. Accepts a URL param e.g. http://htmlsnapshot.appspot.com?url=http://example.com#!tab=TabA&subtab=SubTab3 (url param should be URLEncoded)
  2. Runs HTMLUnit to open http://example.com#!tab=TabA&subtab=SubTab3 and run the client-side javascript on the sever.
  3. HTMLUnit returns the DOM once everything is complete (or something like 45 seconds has passed).
  4. The return content could be sent back via JSON/JSONP, or alternatively a URL is return to a file generated and stored on the google app engine server (for file based "cached" results)... open to suggestions here. If a URL to a file was returned then you could CURL to get the source code (aka a HTML Snapshot).

My http://example.com app would need to manage the call to http://htmlsnapshot.appspot.com... basically:

  1. Catch Googlebots call to http://example.com/?_escaped_fragment_=tab=TabA%26subtab=SubTab3 (googlebot crawler escapes certain characters e.g. %26 = &).
  2. Send request from the backend to http://htmlsnapshot.appspot.com?url=http://example.com#!tab=TabA&subtab=SubTab3 (url param should be URLEncoded)
  3. Render the returned HTML Snapshot to the frontend.
  4. Google Indexes the content and we rejoice!

I don't have any experience with Google App Engine or Java or HTMLUnit.

I might be able to figure it out... and will post my results if I do.

Otherwise I feel this is a VERY good opportunity for someone to write a kick-ass blog post that outlines a novices step-by-step guide to setting up a web service like this.

This will introduce more people to the excellent (and free!) Google App Engine. Also it will undoubtably encourage more people to adopt Google's specs for crawlable AJAX content... something we can all benefit from!

As Google's specification gains more acceptance the "hurdle" of setting up a Headless Browser is going to send many devs Googling for answers! Get in now with an answer for fame and glory! (edit: at the very least I will sing your praises).

Hit me up on twitter @_chrisjacob if you would like to discuss solutions.

Chris Jacob
  • 11,878
  • 7
  • 47
  • 42
  • Interesting read: "Get HtmlUnit to run on Google App Engine (GAE)" http://sourceforge.net/tracker/index.php?func=detail&aid=2962074&group_id=47038&atid=448269 – Chris Jacob Aug 19 '10 at 01:14
  • See htmlunit 2.8 release notes. – Matthew H Aug 19 '10 at 02:10
  • htmlunit 2.8 release notes: http://htmlunit.sourceforge.net/changes-report.html#a2.8 - you're right they state that GAE support is functional (or at least "fixed"). – Chris Jacob Aug 20 '10 at 09:02

1 Answers1

2

I have successfully used HTMLunit on AppEngine. My GWT code to do this is available in the gwt-platform project the results I got were similar to that of the HTMLunit-AppEngine test application by Amit Manjhi.

It should be relatively easy to use GWTP current HTMLunit support to do exactly what you describe, although you could likely do it in a simpler app. One problem I see is that AppEngine requests have a 30 second timeout, so you can't have a page that takes HTMLunit longer than that to process.

UPDATE: It's been a while, but I finally closed the long standing issue about making GWT applications crawlable using GWTP. The documentation is not entirely there, but check out the issue: http://code.google.com/p/gwt-platform/issues/detail?id=1

Philippe Beaudoin
  • 3,290
  • 1
  • 22
  • 25
  • I still have a problem accessing my own application with HTMLunit, which makes it hard for an app to serve itself to the crawler. The details of my issue are subtle but I describe them here (http://bit.ly/bViIMr). I haven't tested this in a while, so maybe the problem went away. – Philippe Beaudoin Aug 19 '10 at 03:05
  • On Amit Manjhi's test app it seems to work fine with the same URL. Maybe this has fixed itself, or maybe it depends on a multitude of factors. – Matthew H Aug 19 '10 at 09:56
  • Could be. I wondered for a while if it wasn't some limitation of the free AppEngine account that wouldn't spawn two Servlets in frequent succession. – Philippe Beaudoin Aug 19 '10 at 18:38
  • Thanks Philippe and Matt. I will investigate GWTP and see what results I can come up with. If either of you are interested in working with me on this I think a Headless Brower as a Web Service is an interesting project (and shouldn't be very hard with GAE and GWTP). Today I've been spec'ing out my own solution for building crawlable, accessible, deeplinked AJAX web apps. Leveraging a Headless Browser to generate HTML Snapshots when the client does not have javascript.. "Headless AJAX" I think I'll call it ;). More info soon. – Chris Jacob Aug 20 '10 at 07:22
  • Chris, there is an open issue on GWTP regarding a module to make App Engine based GWTP apps crawlable. It's blocked on the bug I described above but my latest idea, following the proposal here, is to cut the Gordian knot by providing an easy way to build your own Web Service. Maybe you'd like to contribute on this? (Issue and discussion is at: http://code.google.com/p/gwt-platform/issues/detail?id=1) – Philippe Beaudoin Aug 22 '10 at 07:30