Automatically exported from code.google.com/p/planningalerts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

163 lines
5.3 KiB

  1. import urllib2
  2. import urllib
  3. import urlparse
  4. from cgi import parse_qs
  5. import datetime
  6. import cookielib
  7. cookie_jar = cookielib.CookieJar()
  8. from BeautifulSoup import BeautifulSoup
  9. from PlanningUtils import PlanningApplication, \
  10. PlanningAuthorityResults, \
  11. getPostcodeFromText
  12. date_format = "%d/%m/%Y"
  13. class PlanetParser:
  14. def __init__(self,
  15. authority_name,
  16. authority_short_name,
  17. base_url,
  18. debug=False):
  19. self.authority_name = authority_name
  20. self.authority_short_name = authority_short_name
  21. self.base_url = base_url
  22. self.debug = debug
  23. self._results = PlanningAuthorityResults(self.authority_name, self.authority_short_name)
  24. def getResultsByDayMonthYear(self, day, month, year):
  25. # What is the serviceKey for this council?
  26. # It's in our base url
  27. query_string = urlparse.urlsplit(self.base_url)[3]
  28. # This query string just contains the servicekey
  29. query_dict = parse_qs(query_string)
  30. service_key = query_dict['serviceKey'][0]
  31. # First get the form
  32. get_request = urllib2.Request(self.base_url)
  33. get_response = urllib2.urlopen(get_request)
  34. cookie_jar.extract_cookies(get_response, get_request)
  35. # We also need to get the security token
  36. get_soup = BeautifulSoup(get_response.read())
  37. security_token = get_soup.find('input', {'name': 'securityToken'})['value']
  38. # Now post to it
  39. search_date = datetime.date(year, month, day)
  40. search_data = urllib.urlencode(
  41. {
  42. "serviceKey":service_key,
  43. "securityToken": security_token,
  44. "STEP":"Planet_SearchCriteria",
  45. #X.resultCount=
  46. "X.pageNumber": "0",
  47. "X.searchCriteria_StartDate": search_date.strftime(date_format),
  48. "X.searchCriteria_EndDate": search_date.strftime(date_format),
  49. }
  50. )
  51. post_request = urllib2.Request(self.base_url, search_data)
  52. cookie_jar.add_cookie_header(post_request)
  53. post_response = urllib2.urlopen(post_request)
  54. post_soup = BeautifulSoup(post_response.read())
  55. # 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
  56. ref_no_text = post_soup.find(text="Ref No")
  57. first_tr = ref_no_text.findNext("tr")
  58. other_trs = first_tr.findNextSiblings()
  59. trs = [first_tr] + other_trs
  60. for tr in trs:
  61. self._current_application = PlanningApplication()
  62. # We don't need to get the date, it's the one we searched for.
  63. self._current_application.date_received = search_date
  64. tds = tr.findAll("td")
  65. self._current_application.council_reference = tds[0].a.string.strip()
  66. self._current_application.address = tds[1].string.strip()
  67. self._current_application.postcode = getPostcodeFromText(self._current_application.address)
  68. self._current_application.description = tds[2].string.strip()
  69. # There is no good info url, so we just give the search page.
  70. self._current_application.info_url = self.base_url
  71. # Similarly for the comment url
  72. self._current_application.comment_url = self.base_url
  73. self._results.addApplication(self._current_application)
  74. return self._results
  75. # post data for worcester
  76. # hopefully we can ignore almost all of this...
  77. #ACTION=NEXT
  78. #serviceKey=SysDoc-PlanetApplicationEnquiry
  79. #serviceGeneration=
  80. #securityToken=NTgxMjE3OTExMjA4OQ%3D%3D
  81. #enquiry=
  82. #STEP=Planet_SearchCriteria
  83. #RECEIVED=
  84. #COMMENTS=
  85. #LAST_UPDATED=
  86. #status=
  87. #X.endEnquiry=
  88. #X.resultCount=
  89. #X.applicationNotFound=
  90. #X.pageNumber=0
  91. #X.searchCriteria_ApplicationReference=
  92. #X.searchCriteria_StartDate=20%2F04%2F2008
  93. #X.searchCriteria_EndDate=20%2F04%2F2008
  94. #X.searchCriteria_Ward=
  95. #X.searchCriteria_Parish=
  96. #X.searchCriteria_Address=
  97. #X.searchCriteria_Postcode=
  98. #X.searchCriteria_ApplicantName=
  99. #X.searchCriteria_AgentName=
  100. #X.searchCriteria_UndecidedApplications=
  101. return self._results
  102. def getResults(self, day, month, year):
  103. return self.getResultsByDayMonthYear(int(day), int(month), int(year)).displayXML()
  104. if __name__ == '__main__':
  105. # parser = PlanetParser("Elmbridge Borough Council", "Elmbridge", "http://www2.elmbridge.gov.uk/Planet/ispforms.asp?serviceKey=SysDoc-PlanetApplicationEnquiry")
  106. # parser = PlanetParser("North Lincolnshire Council", "North Lincolnshire", "http://www.planning.northlincs.gov.uk/planet/ispforms.asp?ServiceKey=SysDoc-PlanetApplicationEnquiry")
  107. # parser = PlanetParser("Rydale District Council", "Rydale", "http://www.ryedale.gov.uk/ispforms.asp?serviceKey=SysDoc-PlanetApplicationEnquiry")
  108. parser = PlanetParser("Tewkesbury Borough Council", "Tewkesbury", "http://planning.tewkesbury.gov.uk/Planet/ispforms.asp?serviceKey=07WCC04163103430")
  109. print parser.getResults(21,5,2008)
  110. # parser = PlanetParser("Worcester City Council", "Worcester", "http://www.worcester.gov.uk:8080/planet/ispforms.asp?serviceKey=SysDoc-PlanetApplicationEnquiry", debug=True)
  111. # TODO
  112. # 1) Pagination
  113. # 2) Work OK with no results.
  114. # 3) Use OSGB for Tewkesbury?