import urllib2 import urllib import urlparse from cgi import parse_qs import datetime import cookielib cookie_jar = cookielib.CookieJar() from BeautifulSoup import BeautifulSoup from PlanningUtils import PlanningApplication, \ PlanningAuthorityResults, \ getPostcodeFromText date_format = "%d/%m/%Y" class PlanetParser: def __init__(self, authority_name, authority_short_name, base_url, debug=False): self.authority_name = authority_name self.authority_short_name = authority_short_name self.base_url = base_url self.debug = debug self._results = PlanningAuthorityResults(self.authority_name, self.authority_short_name) def get_info_url(self, soup_fragment): return self.base_url def get_comment_url(self, soup_fragment): return self.get_info_url(soup_fragment) def getResultsByDayMonthYear(self, day, month, year): # What is the serviceKey for this council? # It's in our base url query_string = urlparse.urlsplit(self.base_url)[3] # This query string just contains the servicekey query_dict = parse_qs(query_string) service_key = query_dict['serviceKey'][0] # First get the form get_request = urllib2.Request(self.base_url) get_response = urllib2.urlopen(get_request) cookie_jar.extract_cookies(get_response, get_request) # We also need to get the security token get_soup = BeautifulSoup(get_response.read()) security_token = get_soup.find('input', {'name': 'securityToken'})['value'] # Now post to it search_date = datetime.date(year, month, day) search_data = urllib.urlencode( { "serviceKey":service_key, "securityToken": security_token, "STEP":"Planet_SearchCriteria", #X.resultCount= "X.pageNumber": "0", "X.searchCriteria_StartDate": search_date.strftime(date_format), "X.searchCriteria_EndDate": search_date.strftime(date_format), } ) post_request = urllib2.Request(self.base_url, search_data) cookie_jar.add_cookie_header(post_request) post_response = urllib2.urlopen(post_request) post_soup = BeautifulSoup(post_response.read()) # Now we need to find the results. We'll do this by searching for the text "Ref No" and then going forward from there. For some reason a search for the table gets the table without contents ref_no_text = post_soup.find(text="Ref No") first_tr = ref_no_text.findNext("tr") other_trs = first_tr.findNextSiblings() trs = [first_tr] + other_trs for tr in trs: self._current_application = PlanningApplication() # We don't need to get the date, it's the one we searched for. self._current_application.date_received = search_date tds = tr.findAll("td") self._current_application.council_reference = tds[0].a.string.strip() self._current_application.address = tds[1].string.strip() self._current_application.postcode = getPostcodeFromText(self._current_application.address) self._current_application.description = tds[2].string.strip() # There is no good info url, so we just give the search page. self._current_application.info_url = self.get_info_url(tr) # Similarly for the comment url self._current_application.comment_url = self.get_comment_url(tr) self._results.addApplication(self._current_application) return self._results # post data for worcester # hopefully we can ignore almost all of this... #ACTION=NEXT #serviceKey=SysDoc-PlanetApplicationEnquiry #serviceGeneration= #securityToken=NTgxMjE3OTExMjA4OQ%3D%3D #enquiry= #STEP=Planet_SearchCriteria #RECEIVED= #COMMENTS= #LAST_UPDATED= #status= #X.endEnquiry= #X.resultCount= #X.applicationNotFound= #X.pageNumber=0 #X.searchCriteria_ApplicationReference= #X.searchCriteria_StartDate=20%2F04%2F2008 #X.searchCriteria_EndDate=20%2F04%2F2008 #X.searchCriteria_Ward= #X.searchCriteria_Parish= #X.searchCriteria_Address= #X.searchCriteria_Postcode= #X.searchCriteria_ApplicantName= #X.searchCriteria_AgentName= #X.searchCriteria_UndecidedApplications= return self._results def getResults(self, day, month, year): return self.getResultsByDayMonthYear(int(day), int(month), int(year)).displayXML() class ElmbridgeParser(PlanetParser): info_url_template = "http://emaps.elmbridge.gov.uk/LinkToSoftwareAG.aspx?appref=%s" def get_info_url(self, soup_fragment): return self.info_url_template %self._current_application.council_reference if __name__ == '__main__': parser = ElmbridgeParser("Elmbridge Borough Council", "Elmbridge", "http://www2.elmbridge.gov.uk/Planet/ispforms.asp?serviceKey=SysDoc-PlanetApplicationEnquiry") # parser = PlanetParser("North Lincolnshire Council", "North Lincolnshire", "http://www.planning.northlincs.gov.uk/planet/ispforms.asp?ServiceKey=SysDoc-PlanetApplicationEnquiry") # parser = PlanetParser("Rydale District Council", "Rydale", "http://www.ryedale.gov.uk/ispforms.asp?serviceKey=SysDoc-PlanetApplicationEnquiry") # parser = PlanetParser("Tewkesbury Borough Council", "Tewkesbury", "http://planning.tewkesbury.gov.uk/Planet/ispforms.asp?serviceKey=07WCC04163103430") # parser = PlanetParser("Worcester City Council", "Worcester", "http://www.worcester.gov.uk:8080/planet/ispforms.asp?serviceKey=SysDoc-PlanetApplicationEnquiry", debug=True) print parser.getResults(1,5,2009) # TODO # 1) Pagination # 2) Work OK with no results. # 3) Use OSGB for Tewkesbury?