Scrape Realtor listings for free
Intro
I wrote a script that will scrape property listings from Realtor and export as a csv!
How to Use It
Go to the search page.
Open your browsers console and copy the code below and paste it into the console. Here's a video to show you how to do that.
Hit enter and let it do it's magic! π§ββοΈ
It will take a few minutes to run. When it's done, it will download a csv file with all the data.
The script is pretty slow. If you need something super speedy, I can run a custom scraper for you that I built that is lightning fast.
How to Hire Me
If you need anything else scraped, I am accepting new clients, send me an email to get a custom scraper/bot created π adrian@thewebscrapingguy.com
async function scrollToBottom() {
return new Promise((resolve) => {
const scrollHeight = document.documentElement.scrollHeight
const windowHeight = window.innerHeight
const scrollStep = 20 // Adjust this value to control scrolling speed
let currentPosition = window.scrollY
function scroll() {
if (currentPosition < scrollHeight - windowHeight) {
currentPosition += scrollStep
window.scrollTo(0, currentPosition)
requestAnimationFrame(scroll)
} else {
window.scrollTo(0, scrollHeight)
resolve() // Resolve the Promise when scrolling is complete
}
}
scroll()
})
}
function createCSV(jsonData, fileName) {
// Convert JSON to CSV
const csvData = []
// Extract the headers
const headers = Object.keys(jsonData[0])
csvData.push(headers.join(','))
jsonData.forEach((item) => {
const row = []
for (const key in item) {
if (item.hasOwnProperty(key)) {
if (typeof item[key] === 'number') {
row.push(item[key])
continue
}
const value = item[key]?.includes(',') ? `"${item[key]}"` : item[key]
row.push(value)
}
}
csvData.push(row.join(','))
})
// Create a Blob containing the CSV data
const csvBlob = new Blob([csvData.join('\n')], {
type: 'text/csv;charset=utf-8',
})
// Create a URL for the Blob
const csvUrl = URL.createObjectURL(csvBlob)
// Create a link element
const link = document.createElement('a')
link.href = csvUrl
link.target = '_blank'
link.download = fileName
// Append the link to the body
document.body.appendChild(link)
// Trigger a click event on the link
link.click()
// Remove the link and revoke the Blob URL
document.body.removeChild(link)
URL.revokeObjectURL(csvUrl)
}
function getListings() {
const listings = []
const listingDivs = document.querySelectorAll(
'div[id*="placeholder_property"]',
)
for (let i = 0; i < listingDivs.length; i++) {
const listingDiv = listingDivs[i]
const status = listingDiv.querySelector(
"div[class*='StatusBadgestyles']",
)?.textContent
const priceString = listingDiv
.querySelector("div[data-testid*='card-price']")
?.textContent?.replace('From', '')
const price = Number(
priceString?.replace('$', '')?.replace(',', '').replace(',', ''),
)
const beds = listingDiv
.querySelector("li[data-testid*='property-meta-beds']")
?.textContent?.replace('bed', '')
const baths = listingDiv
.querySelector("li[data-testid*='property-meta-baths']")
?.textContent?.replace('bath', '')
const sqftString = listingDiv.querySelector(
"li[data-testid*='property-meta-sqft'] > span > span",
)?.textContent
const sqft = Number(
sqftString?.replace('sqft', '')?.replace(',', '')?.replace(',', ''),
)
const lotSize = listingDiv.querySelector(
"li[data-testid*='property-meta-lot-size'] > span > span",
)?.textContent
const streetAddress = listingDiv.querySelector(
"div[data-testid*='card-address-1']",
)?.textContent
const cityStateZip = listingDiv.querySelector(
"div[data-testid*='card-address-2']",
)?.textContent
const link = listingDiv.querySelector('a')?.href
listings.push({
price,
priceString,
beds,
baths,
sqft,
lotSize,
status,
link,
streetAddress,
cityStateZip,
})
}
return listings
}
async function scrapeRealtorListings() {
const allListings = []
let page = 1
let nextButton = document.querySelector('.next-link')
let isDisabled = nextButton?.classList?.contains('disabled')
while (!isDisabled) {
await scrollToBottom()
await new Promise((resolve) => setTimeout(resolve, 200))
console.log(`Scraping page ${page}`)
const listings = getListings()
console.log(`You scraped ${listings.length} listings`)
console.log(
`If you need anything on the web scraped, email me: adrian@thewebscrapingguy.com`,
)
allListings.push(...listings)
nextButton = document.querySelector('.next-link')
isDisabled = nextButton?.classList?.contains('disabled')
nextButton.click()
await new Promise((resolve) => setTimeout(resolve, 2000))
page++
}
console.log(`Congrats! π You scraped ${allListings.length} listings`)
createCSV(allListings, `realtor-listings-${new Date().getTime()}.csv`)
}
await scrapeRealtorListings()