diff --git a/python_scrapers/PlanningExplorer.py b/python_scrapers/PlanningExplorer.py
index 5c3e2ec..ebdef7e 100644
--- a/python_scrapers/PlanningExplorer.py
+++ b/python_scrapers/PlanningExplorer.py
@@ -5,6 +5,12 @@ import cgi
import re
import datetime
+
+import cookielib
+
+cookie_jar = cookielib.CookieJar()
+
+
from BeautifulSoup import BeautifulSoup
from PlanningUtils import PlanningApplication, \
@@ -64,6 +70,8 @@ class PlanningExplorerParser:
# If fetch_info_page is set to true, then we need to get a copy of the info page and store it as an attribute on current_application (naughty!)
fetch_info_page = False
+ asp_args_regex = re.compile(']*name=\"(__[A-Z]*)\"[^>]*value=\"([^\"]*)\"[^>]*>')
+
def _modify_response(self, response):
"""For most sites, we have managed to get all the apps on a
single page by choosing the right parameters.
@@ -90,7 +98,7 @@ class PlanningExplorerParser:
"""If an authority has info urls which are for some reason full
of crap (like Broadland does), then this method should be overridden
in order to tidy them up."""
- return url
+ return ''.join(url.split())
def _getHeaders(self):
"""If the authority requires any headers for the post request,
@@ -194,16 +202,17 @@ class PlanningExplorerParser:
get_request = urllib2.Request(self.search_url)
get_response = urllib2.urlopen(get_request)
+ cookie_jar.extract_cookies(get_response, get_request)
+
html = get_response.read()
# We need to find those ASP parameters such as __VIEWSTATE
# so we can use them in the next POST
- asp_args_regex = re.compile(']*name=\"(__[A-Z]*)\"[^>]*value=\"([^\"]*)\"[^>]*>')
# re.findall gets us a list of key value pairs.
# We want to concatenate it with a tuple, so we must
# make it a tuple
- asp_args = tuple(re.findall(asp_args_regex, html))
+ asp_args = tuple(re.findall(self.asp_args_regex, html))
# The post data needs to be different for different councils
# so we have a method on each council's scraper to make it.
@@ -212,7 +221,7 @@ class PlanningExplorerParser:
headers = self._getHeaders()
request = urllib2.Request(self.search_url, post_data, headers)
-
+ cookie_jar.add_cookie_header(request)
post_response = urllib2.urlopen(request)
# We have actually been returned here by an http302 object
@@ -358,19 +367,36 @@ class CharnwoodParser(PlanningExplorerParser):
class CreweParser(PlanningExplorerParser):
use_firefox_user_agent = True
- address_td_no = 4
+ use_referer = True
+
+ info_url_path = "Northgate/PlanningExplorer/Generic/"
+ search_url_path = "northgate/planningexplorer/generalsearch.aspx"
+
+ results_table_attrs = {"class": "display_table"}
def _getPostData(self, asp_args, search_date):
year_month_day = search_date.timetuple()[:3]
post_data = urllib.urlencode(asp_args + (
- ("drDateReceived:_ctl0_hidden", urllib.quote('' %year_month_day)),
- ("drDateReceivedxxctl0_input", search_date.strftime(date_format)),
- ("drDateReceived:_ctl1_hidden", urllib.quote('' %year_month_day)),
- ("drDateReceivedxxctl1_input", search_date.strftime(date_format)),
- ("cboNumRecs", "99999"),
+ ("txtApplicantName", ""),
+ ("txtAgentName", ""),
+ ("cboStreetReferenceNumber", ""),
+ ("txtProposal", ""),
+ ("cboWardCode", ""),
+ ("cboParishCode", ""),
+ ("cboApplicationTypeCode", ""),
+ ("cboDevelopmentTypeCode", ""),
+ ("cboStatusCode", ""),
+ ("cboSelectDateValue", "DATE_RECEIVED"),
+ ("cboMonths", "1"),
+ ("cboDays", "1"),
+ ("rbGroup", "rbRange"),
+ ("dateStart", search_date.strftime(date_format)),
+ ("dateEnd", search_date.strftime(date_format)),
+ ("edrDateSelection", ""),
("csbtnSearch", "Search"),
- ))
+ )
+ )
return post_data
@@ -430,26 +456,72 @@ class HackneyParser(PlanningExplorerParser):
return new_response
-
+#txtApplicationNumber=&ctl00=DATE_REGISTERED&ctl01=1&ctl02=1&rbGroup=ctl05&ctl07_hidden=&ctl07_input=28%2F08%2F2008&ctl08_hidden=&ctl08_input=28%2F08%2F2008&edrDateSelection=1&cboApplicationTypeCode=&txtLocality=&txtPostCode=&txtPropertyName=&txtPropertyNumber=&txtSiteAddress=&txtStreetName=&csbtnSearch=Search&
def _getPostData(self, asp_args, search_date):
+ """Note - using date registered here, not date received. There is too much time taken
+ between the council 'receiving' an app and 'registering' it for the latter to be useful."""
post_data = urllib.urlencode(asp_args + (
- ("ctl00", "DATE_RECEIVED"),
+ ("txtApplicationNumber", ""),
+ ("ctl00", "DATE_REGISTERED"),
+ ("ctl01", "1"),
+ ("ctl02", "1"),
("rbGroup", "ctl05"),
+ ("ctl07_hidden", ""),
("ctl07_input", search_date.strftime(date_format)),
+ ("ctl08_hidden", ""),
("ctl08_input", search_date.strftime(date_format)),
("edrDateSelection", "1"),
+ ("cboApplicationTypeCode", ""),
+ ("txtLocality", ""),
+ ("txtPostCode", ""),
+ ("txtPropertyName", ""),
+ ("txtPropertyNumber", ""),
+ ("txtSiteAddress", ""),
+ ("txtStreetName", ""),
("csbtnSearch", "Search"),
- ))
-
+ )
+ )
return post_data
-
+
class KennetParser(BroadlandLike, PlanningExplorerParser):
comments_path = "Northgate/PlanningExplorer/PLComments.aspx?pk=%s"
class LincolnParser(PlanningExplorerParser):
use_firefox_user_agent = True
- results_table_attrs = {"class": "resultstable"}
+ use_referer = True
+
+ results_table_attrs = {"class": "display_table"}
+ search_url_path = "northgate/planningexplorer/generalsearch.aspx"
+ info_url_path = "Northgate/PlanningExplorer/Generic/"
+
+
+ def _getPostData(self, asp_args, search_date):
+ post_data = urllib.urlencode(asp_args + (
+ ("txtApplicationNumber", ""),
+ ("txtApplicantName", ""),
+ ("txtAgentName", ""),
+ ("cboApplicationTypeCode", ""),
+ ("cboStatusCode", ""),
+ ("txtPropertyName", ""),
+ ("txtPropertyNumber", ""),
+ ("cboStreetReferenceNumber", ""),
+ ("txtPostCode", ""),
+ ("cboLocality", ""),
+ ("txtProposal", ""),
+ ("cboSelectDateValue", "DATE_REGISTERED"),
+ ("cboMonths", "1"),
+ ("rbGroup", "rbDay"),
+ ("cboDays", "10"),
+ ("dateStart", search_date.strftime(date_format)),
+ ("dateEnd", search_date.strftime(date_format)),
+ ("edrDateSelection", ""),
+ ("csbtnSearch", "Search"),
+ )
+ )
+ return post_data
+
+
class LiverpoolParser(PlanningExplorerParser):
comments_email_address = "planningandbuildingcontrol@liverpool.gov.uk"
use_firefox_user_agent = True
@@ -639,9 +711,9 @@ if __name__ == '__main__':
# parser = EastStaffsParser("East Staffordshire Borough Council", "East Staffs", "http://www2.eaststaffsbc.gov.uk/")
# parser = EppingForestParser("Epping Forest District Council", "Epping Forest", "http://plan1.eppingforestdc.gov.uk/")
# parser = ForestHeathParser("Forest Heath District Council", "Forest Heath", "http://195.171.177.73/")
- parser = HackneyParser("London Borough of Hackney", "Hackney", "http://www.hackney.gov.uk/servapps/")
+# parser = HackneyParser("London Borough of Hackney", "Hackney", "http://www.hackney.gov.uk/servapps/")
# parser = KennetParser("Kennet District Council", "Kennet", "http://mvm-planning.kennet.gov.uk/")
-# parser = LincolnParser("Lincoln City Council", "Lincoln", "http://online.lincoln.gov.uk/")
+ parser = LincolnParser("Lincoln City Council", "Lincoln", "http://online.lincoln.gov.uk/")
# parser = LiverpoolParser("Liverpool City Council", "Liverpool", "http://www.liverpool.gov.uk/")
# parser = ShrewsburyParser("Shrewsbury and Atcham Borough Council", "Shrewsbury", "http://www2.shrewsbury.gov.uk/")
# parser = SouthNorfolkParser("South Norfolk Council", "South Norfolk", "http://planning.south-norfolk.gov.uk/")
@@ -655,7 +727,7 @@ if __name__ == '__main__':
# parser = WalthamForestParser("Waltham Forest", "Waltham Forest", "http://planning.walthamforest.gov.uk/")
# parser = ConwyParser("Conwy County Borough Council", "Conwy", "http://www.conwy.gov.uk/")
# parser = MertonParser("London Borough of Merton", "Merton", "http://planning.merton.gov.uk")
- print parser.getResults(4, 9, 2008)
+ print parser.getResults(9, 9, 2008)
# To Do
@@ -666,3 +738,7 @@ if __name__ == '__main__':
# Charnwood
# South Norfolk has no postcodes. I wonder if the postcodes are in the WAM site...
+
+# Notes:
+
+# Since the changed, Liverpool and Crewe look rather similar. They are also a little Broadlandlike. Maybe we can do some consolidation