Code to help with the re-arranging of my life in 2024.
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.
 
 

11 KiB

Zoopla Manchester

Setup Common Lisp Environment

I’ve copied the following code block over from other files. Run it if this is your first file open in the session.

  (ql:quickload :com.inuoe.jzon) ; JSON parser.
  (ql:quickload :dexador)        ; HTTP requests.
  (ql:quickload :plump)          ; HTML/XML parser.
  (ql:quickload :lquery)         ; HTML/DOM manipulation.
  (ql:quickload :lparallel)      ; Parallel programming.
  (ql:quickload :cl-ppcre)       ; RegEx. library.
  (ql:quickload :plot/vega)      ; Vega plotting library.
  (ql:quickload :lisp-stat)      ; Stat's library.
  (ql:quickload :data-frame)     ; Data frame library eqv. to Python's Numpy.
  (ql:quickload :str)            ; String library, expands on 'string' library.

Gather Zoopla Rent Data (Manually)

The site produced a single page so I didn't feel the need to scrap the data. I just saved the page into raw-data/external/2024-03-18-zoopla-rent-manc/. The data is the actual HTML and CSS, so the files will not be committed to the repository, to match the established behaviour of the other sites I've already looked at.

The filters I used:

  • Date: 2024-03-18
  • Location: Manchester City Centre, Greater Manchester
  • Radius: 'This area only'
  • Price Range: £400–£1,300 pcm
  • Only monthly rents listed

Clean Up and Parse Data

Going to separate the listings out into their own files, to match the established behaviour with other sites I've looked at.

  mkdir raw-data/external/2024-03-18-zoopla-rent-manc-listings/

/craig.oates/overhaul2024/src/branch/master/raw-data/external/2024-03-18-zoopla-rent-manc-listings

  (let ((counter 0))
    (loop for file-path
            in (directory #P"raw-data/external/2024-03-18-zoopla-rent-manc/*.html")
          do (with-open-file (in-stream file-path)
               (let* ((doc (plump:parse in-stream))
                      ;; .listing-info
                      (listings (lquery:$ doc ".dkr2t82" (serialize))))
                 (loop for item across listings
                       do (let ((out-path
                                  (merge-pathnames
                                   #P"raw-data/external/2024-03-18-zoopla-rent-manc-listings/"
                                   (format nil "listing-~a.html" (write-to-string counter)))))
                            (with-open-file (out-stream
                                             out-path
                                             :direction :output
                                             :if-exists :supersede)
                              (format out-stream "~a~%" item))
                            (incf counter)))))))
  COUNT=$(ls -1 "raw-data/external/2024-03-18-zoopla-rent-manc-listings/" | wc -l)
  echo "There are $COUNT files in the directory."
There are 14 files in the directory.

There are some listings which are student-only. Unfortunately, there doesn't seem to be a filter for removing student-only listings. So, I'll need to remove them manually at little later down the line. The total amount of listing is small enough for it to not be a problem.

Create CSV of Listings

  (let ((row-id 0)
        (out-file #P"working-data/2024-03-18-zoopla-manc.csv"))
    (with-open-file (out-stream
                     out-file
                     :direction :output
                     :if-exists :supersede)
      (format out-stream "ROW-ID,RENT,LOCATION,URL,DESCRIPTION~%")
      (loop for input
              in (directory #P"raw-data/external/2024-03-18-zoopla-rent-manc-listings/*.html")
            do (with-open-file (in-stream input)
                 (let* ((doc (plump:parse in-stream))
                        (price (lquery:$ doc "._64if862._194zg6t6" (text)))
                        (description (lquery:$ doc ".m6hnz63._194zg6t9" (text)))
                        ;; e.g. Transform '£1,250 per month' to '1250'.
                        (cleaned-price
                          (first
                           (cl-ppcre:all-matches-as-strings
                            "\\d+"
                            (cl-ppcre:regex-replace-all
                             "[\\s\\n]+"
                             (format nil "~s" (str:replace-all "," "" (aref price 0)))
                             " "))))
                        (location (lquery:$ doc "address" (text)))
                        (link (lquery:$ doc "a" (attr :href))))
                   (format out-stream "~d,~d,~a,~a,~a~%"
                           row-id
                           cleaned-price
                           (str:replace-all "," " " (aref location 0))
                           (cl-ppcre:regex-replace "\\?search.*" (aref link 0) "")
                           (str:replace-all "," " " (aref description 0)))))
               (incf row-id)))
    (format t "[[file:./~a]]" out-file))

/craig.oates/overhaul2024/src/branch/master/working-data/2024-03-18-zoopla-manc.csv

I've manually removed the student-only listing, since creating the CSV file. File is left with 5 listings.

Explore CSV Data for Zoopla (2024-03-18)

  (lisp-stat:defdf *zoop-man*
      (lisp-stat:read-csv #P"working-data/2024-03-18-zoopla-manc.csv"))
#<DATA-FRAME:DATA-FRAME (5 observations of 5 variables)>

The total amount of listings is tiny, so I can list them out here.

  (lisp-stat:print-markdown *zoop-man*)
ROW-ID RENT LOCATION URL DESCRIPTION
2 1150 Arches Whitworth Street West Manchester M1 https://www.zoopla.co.uk/to-rent/details/65630906/ 3 month agreements only - available 23rd March A true Manchester gem minutes from the Northern Quarter Canal Street and Piccadilly. This is …
3 1150 Water Street Manchester M3 https://www.zoopla.co.uk/to-rent/details/66713818/ 1-6 months Tenancy bills included no couples due to regulations**Perfect for Contractors & Work Teams****Perfect for Business …
5 1250 Arches Whitworth Street West Manchester M1 https://www.zoopla.co.uk/to-rent/details/66338812/ 3 month agreements only - available 23rd March A true Manchester gem minutes from the Northern Quarter Canal Street and Piccadilly. This is …
8 1050 Little Lever Street Manchester Greater Manchester M1 https://www.zoopla.co.uk/to-rent/details/65042494/ * available from 19/04/2024 * * all bills inclusive in rent * Reeds Rains are delighted to market this fantastic furnished studio apartment …
11 1089 Cross Street Manchester M2 https://www.zoopla.co.uk/to-rent/details/66673111/ Listing code 692841. Our contemporary studio apartments at 25 Cross Street are thoughtfully designed to a high standard.Featuring a comfy double …
    (vega:defplot zoopla-monthly-manc
      `(:title "Rent Rates for Manchester on Zoople (18/03/2024)"
        :width 600
        :height 600
        :data ,*zoop-man*
        :layer #((:mark (:type :bar)
                  :encoding (:x (:field :row-id :title "Assigned Id." :type :nominal :axis ("labelAngle" 0))
                             :y (:field :rent :title "Monthly Rent with Bills Inc. (£)" :type :quantitative)
                             :tooltip (:field :rent)))
                 (:mark (:type rule :color "darkorange" :size 3)
                  :encoding (:y (:field :rent :type :quantitative :aggregate :average)
                             :tooltip (:field :rent :type :quantitative :aggregate :average))))))
    (vega:write-html zoopla-monthly-manc "renders/2024-03-18-zoopla-rent-manc.html")

/craig.oates/overhaul2024/src/branch/master/renders/2024-03-18-zoopla-rent-manc.html

  mv ~/Downloads/visualization.png ./renders/2024-03-18-zoopla-rent-manc.png

/craig.oates/overhaul2024/src/branch/master/renders/2024-03-18-zoopla-rent-manc.png

  (format t "- Mean Rent: £ ~a~%" (float (lisp-stat:mean *zoop-man*:rent)))
  (format t "- Min. Rent: £ ~d~%" (reduce #'min *zoop-man*:rent))
  (format t "- Max. Rent: £ ~d" (reduce #'max *zoop-man*:rent))
  • Mean Rent: £ 1137.8
  • Min. Rent: £ 1050
  • Max. Rent: £ 1250
  1137.8 * 12
13653.6

Summary of Zoopla

Based on the average rent for Zoopla, I would need to make around £14,000/yr to cover my living costs. This doesn't include travel, food, clothing, socialising or Income Tax Payments.

Most listing were aimed at students and the number of listings was tiny, especially when compared to Spareroom and Open Rent.

To get an idea of what I need for ’survival mode’, I'll add £5,000 onto the total above and apply the usual calculations, established in the other files.

  13653.6 + 5000
18653.6

Using £18,653.6 as the starting point (see UK Wage and Tax Rated,

  (let* ((earning-target 18653.6)
         (p-allow 12570)
         (taxable-income (- earning-target p-allow))
         (tax-to-pay (* taxable-income 0.2))
         (total (- earning-target tax-to-pay)))
    (format t "- Annual Target Salary: £~a~%" earning-target)
    (format t "- Part of Salary which is Taxable: £~a~%" taxable-income)
    (format t "- Tax to Pay: £~a~%" tax-to-pay)
    (format t "- Salary After Tax: £~a~%" total))
  • Annual Target Salary: £18653.6
  • Part of Salary which is Taxable: £6083.5996
  • Tax to Pay: £1216.72
  • Salary After Tax: £17436.879
Time Span Value After Tax (£) Mean Rent (£)
Annually 17436.88 1137.8
Monthly (Before Rent) 1453.0733
Monthly (After Rent) 315.2733
Weekly (After Rent) 78.818325
Daily (After Rent) 11.259761

So, the spending limit is £11.26/day.