A fast and expressive Craigslist API wrapper

Overview

pycraigslist

PyPI version fury.io PyPI pyversions

A fast and expressive Craigslist API wrapper.

As of September 2021, it is believed that Craigslist added a rate-limiter. It is advised to throttle requests to Craigslist to prevent a 403 HTTP response status code. View the Exceptions section below to appropriately handle this error if encountered.

Disclaimer

  • I do not work or have an affiliation with Craigslist.
  • This library is intended for educational purposes. It is not advised to crawl and download data from Craigslist.

Installation

pip install pycraigslist

Quick Start

Find cars & trucks for sale with keyword "Mazda Miata" in the East Bay Area, California:

>> {'country': 'US', 'region': 'CA', 'site': 'sfbay', 'area': 'eby', 'category': 'cto', 'id': '7291715564', 'repost_of': '', 'last_updated': '2021-03-15 09:06', 'title': '1990 Mazda Miata', 'neighborhood': 'oakland lake merritt / grand', 'price': '$5,000', 'url': 'https://sfbay.craigslist.org/eby/cto/d/oakland-1990-mazda-miata/7291715564.html'} # ... ">
import pycraigslist

miatas = pycraigslist.forsale.cta(site="sfbay", area="eby", query="Mazda Miata")
for miata in miatas.search():
    print(miata)

>>> {'country': 'US',
    'region': 'CA',
    'site': 'sfbay',
    'area': 'eby',
    'category': 'cto',
    'id': '7291715564',
    'repost_of': '',
    'last_updated': '2021-03-15 09:06',
    'title': '1990 Mazda Miata',
    'neighborhood': 'oakland lake merritt / grand',
    'price': '$5,000',
    'url': 'https://sfbay.craigslist.org/eby/cto/d/oakland-1990-mazda-miata/7291715564.html'}
    # ...

Background

This library is intended to be expressive and easy to use.

pycraigslist classes

  • pycraigslist.community             (craigslist.org > community)
  • pycraigslist.events                   (craigslist.org > event calendar)
  • pycraigslist.forsale                 (craigslist.org > for sale)
  • pycraigslist.gigs                       (craigslist.org > gigs)
  • pycraigslist.housing                 (craigslist.org > housing)
  • pycraigslist.jobs                       (craigslist.org > jobs)
  • pycraigslist.resumes                 (craigslist.org > resumes)
  • pycraigslist.services               (craigslist.org > services)

We can search for posts in parent classes. For example, finding paid gigs in Portland, Oregon:

>> {'country': 'US', 'region': 'OR', 'site': 'portland', 'area': 'mlt', 'category': 'lbg', 'id': '7295392821', 'repost_of': '7292985211', 'last_updated': '2021-03-22 13:00', 'title': 'Packing and moving', 'neighborhood': 'SE Portland', 'price': '', 'url': 'https://portland.craigslist.org/mlt/lbg/d/portland-packing-and-moving/7295392821.html'} # ... ">
import pycraigslist

paid_gigs = pycraigslist.gigs(site="portland", is_paid=True)
for gig in paid_gigs.search():
    print(gig)

>>> {'country': 'US',
    'region': 'OR',
    'site': 'portland',
    'area': 'mlt',
    'category': 'lbg',
    'id': '7295392821',
    'repost_of': '7292985211',
    'last_updated': '2021-03-22 13:00',
    'title': 'Packing and moving',
    'neighborhood': 'SE Portland',
    'price': '',
    'url': 'https://portland.craigslist.org/mlt/lbg/d/portland-packing-and-moving/7295392821.html'}
    # ...

pycraigslist subclasses

Most pycraigslist classes have subclasses to allow for categorical searches. For example:

  • pycraigslist.forsale.bia         (craigslist.org > for sale > bikes)
  • pycraigslist.forsale.cta         (craigslist.org > for sale > cars & trucks)
  • pycraigslist.housing.apa         (craigslist.org > housing > apartments / housing for rent)
  • pycraigslist.housing.roo         (craigslist.org > housing > apartments / rooms & shares)

Finding pycraigslist subclasses

Use class method .get_categories() to search for subclasses. The resulting keys are the subclass names.

import pycraigslist

print(pycraigslist.housing.get_categories())

>>> {'apa': 'apartments / housing for rent',
    'swp': 'housing swap',
    'off': 'office & commercial',
    'prk': 'parking & storage',
    'rea': 'real estate',
    'reb': 'real estate - by dealer',
    'reo': 'real estate - by owner',
    'roo': 'rooms & shares',
    'sub': 'sublets & temporary',
    'vac': 'vacation rentals',
    'hou': 'wanted: apts',
    'rew': 'wanted: real estate',
    'sha': 'wanted: room/share',
    'sbw': 'wanted: sublet/temp'}

We'd choose pycraigslist.housing.vac if we're interested in searching for vacation rentals.

Finding and using filters

We can apply filters to our search. Use .get_filters() to find valid filters for a class or subclass instance.

Search filters are sensitive to the context of the pycraigslist instance and the language of the region. For example, here are applicable filters for cars & trucks for sale in Tokyo, Japan:

>> {'query': '...', 'search_titles': 'True/False', 'has_image': 'True/False', 'posted_today': 'True/False', 'bundle_duplicates': 'True/False', 'search_distance': '...', 'zip_code': '...', 'min_price': '...', 'max_price': '...', 'make_model': '...', 'min_year': '...', 'max_year': '...', 'min_miles': '...', 'max_miles': '...', 'min_engine_displacement': '...', 'max_engine_displacement': '...', 'condition': ['新品', 'ほぼ新品', '美品', '良品', '使用に問題なし', 'サルベージ'], 'auto_cylinders': ['3気筒', '4気筒', '5気筒', '6気筒', '8気筒', '10気筒', '12気筒', 'その他'], 'auto_drivetrain': ['前輪', '後輪', '4WD'], 'auto_fuel_type': ['ガソリン', 'ディーゼル', 'ハイブリッド', '電気', 'その他'], 'auto_paint': ['ブラック', 'ブルー', 'ブラウン', 'グリーン', 'グレー', 'オレンジ', 'パープル', 'レッド', 'シルバー', 'ホワイト', 'イエロー', 'カスタム'], 'auto_size': ['コンパクト', 'フルサイズ', '中型', 'サブコンパクト'], 'auto_title_status': ['クリーン', 'サルベージ', '再生', '部品のみ', '先取特権', '不明'], 'auto_transmission': ['MT', 'AT', 'その他'], 'auto_bodytype': ['バス', 'コンバーチブル', 'クーペ', 'ハッチバック', 'ミニバン', 'オフロード', 'ピックアップ', 'セダン', 'トラック', 'SUV', 'ワゴン', 'バン', 'その他'], 'language': ['afrikaans', 'català', 'dansk', 'deutsch', 'english', 'español', 'suomi', 'français', 'italiano', 'nederlands', 'norsk', 'português', 'svenska', 'filipino', 'türkçe', '中文', 'العربية', '日本語', '한국말', 'русский', 'tiếng việt']} ">
import pycraigslist

tokyo_autos = pycraigslist.forsale.cta(site="tokyo")
print(tokyo_autos.get_filters())

>>> {'query': '...', 'search_titles': 'True/False', 'has_image': 'True/False',
    'posted_today': 'True/False', 'bundle_duplicates': 'True/False',
    'search_distance': '...', 'zip_code': '...', 'min_price': '...', 'max_price': '...',
    'make_model': '...', 'min_year': '...', 'max_year': '...', 'min_miles': '...',
    'max_miles': '...', 'min_engine_displacement': '...', 'max_engine_displacement': '...',
    'condition': ['新品', 'ほぼ新品', '美品', '良品', '使用に問題なし', 'サルベージ'],
    'auto_cylinders': ['3気筒', '4気筒', '5気筒', '6気筒', '8気筒', '10気筒', '12気筒', 'その他'],
    'auto_drivetrain': ['前輪', '後輪', '4WD'],
    'auto_fuel_type': ['ガソリン', 'ディーゼル', 'ハイブリッド', '電気', 'その他'],
    'auto_paint': ['ブラック', 'ブルー', 'ブラウン', 'グリーン', 'グレー', 'オレンジ', 'パープル',
                   'レッド', 'シルバー', 'ホワイト', 'イエロー', 'カスタム'],
    'auto_size': ['コンパクト', 'フルサイズ', '中型', 'サブコンパクト'],
    'auto_title_status': ['クリーン', 'サルベージ', '再生', '部品のみ', '先取特権', '不明'],
    'auto_transmission': ['MT', 'AT', 'その他'],
    'auto_bodytype': ['バス', 'コンバーチブル', 'クーペ', 'ハッチバック', 'ミニバン', 'オフロード',
                      'ピックアップ', 'セダン', 'トラック', 'SUV', 'ワゴン', 'バン', 'その他'],
    'language': ['afrikaans', 'català', 'dansk', 'deutsch', 'english', 'español', 'suomi',
                 'français', 'italiano', 'nederlands', 'norsk', 'português', 'svenska',
                 'filipino', 'türkçe', '中文', 'العربية', '日本語', '한국말', 'русский',
                 'tiếng việt']}

To find cars & trucks with clean titles, we'd use the filter parameter "クリーン" (pronounced 'koo-lean'):

>> {'country': 'JP', 'region': '', 'site': 'tokyo', 'area': '', 'category': 'cto', 'id': '7301105503', 'repost_of': '', 'last_updated': '2021-04-03 14:04', 'title': 'Suzuki Jimny 660 XG 4WD Keyless Entry Aluminum Wheel Non-Smoking Car', 'neighborhood': 'Chiba Ken, Noda shi, Funakata 1630-1', 'price': '¥650,000', 'url': 'https://tokyo.craigslist.org/cto/d/suzuki-jimny-660-xg-4wd-keyless-entry/7301105503.html'} # ... ">
import pycraigslist

tokyo_autos = pycraigslist.forsale.cta(site="tokyo", auto_title_status="クリーン")
for auto in tokyo_autos.search():
    print(auto)

>>> {'country': 'JP',
    'region': '',
    'site': 'tokyo',
    'area': '',
    'category': 'cto',
    'id': '7301105503',
    'repost_of': '',
    'last_updated': '2021-04-03 14:04',
    'title': 'Suzuki Jimny 660 XG 4WD Keyless Entry Aluminum Wheel Non-Smoking Car',
    'neighborhood': 'Chiba Ken, Noda shi, Funakata 1630-1',
    'price': '¥650,000',
    'url': 'https://tokyo.craigslist.org/cto/d/suzuki-jimny-660-xg-4wd-keyless-entry/7301105503.html'}
    # ...

When applying many filters, pass a dictionary of filters into the filters keyword parameter. Note: keyword argument filters will override filters if there are conflicting keys. For example:

import pycraigslist

bike_filters = {
    "bicycle_frame_material": "steel",
    # array of filter values are accepted
    "bicycle_wheel_size": ["650C", "700C"],
    "bicycle_type": "road",
}
# we'd still get titanium road bikes with size 650C or 700C wheels
titanium_bikes = pycraigslist.forsale.bia(
    site="sfbay", area="sfc", bicycle_frame_material="titanium", filters=bike_filters
)

Searching for posts

General search

To search for Craigslist posts, use .search(). .search() will return a dictionary of post attributes (type str) and will search for every post by default. Use the limit keyword parameter to add a stop limit to a query. For example, use limit=50 to get 50 posts. There is a maximum of 3000 posts per query.

Find the first 20 posts for farming and gardening services in Denver, Colorado:

>> {'country': 'US', 'region': 'CO', 'site': 'denver', 'area': '', 'category': 'fgs', 'id': '7301324564', 'repost_of': '6974119634', 'last_updated': '2021-04-03 11:47', 'title': '🌲 Tree Removal/Trimming, Stump Grind: LICENSED/INSURED! 720-605-1584', 'neighborhood': 'All Areas', 'price': '', 'url': 'https://denver.craigslist.org/fgs/d/littleton-tree-removal-trimming-stump/7301324564.html'} # ... ">
import pycraigslist

gardening_services = pycraigslist.services.fgs(site="denver")
for service in gardening_services.search(limit=20):
    print(service)

>>> {'country': 'US',
    'region': 'CO',
    'site': 'denver',
    'area': '',
    'category': 'fgs',
    'id': '7301324564',
    'repost_of': '6974119634',
    'last_updated': '2021-04-03 11:47',
    'title': '🌲 Tree Removal/Trimming, Stump Grind: LICENSED/INSURED! 720-605-1584',
    'neighborhood': 'All Areas',
    'price': '',
    'url': 'https://denver.craigslist.org/fgs/d/littleton-tree-removal-trimming-stump/7301324564.html'}
    # ...

Detailed search

Use .search_detail() to get detailed Craigslist posts. The limit keyword parameter in .search also applies to .search_detail. Set include_body=True to include the post's body in the output. By default, include_body=False. Disclaimer: .search_detail is more time consuming than .search.

Get detailed posts with the post body for all cars & trucks for sale in Abilene, Texas:

>> {'country': 'US', 'region': 'TX', 'site': 'abilene', 'area': '', 'category': 'cto', 'id': '7309894792', 'repost_of': '', 'last_updated': '2021-04-20 12:17', 'title': '2009 Mercedes GL-320', 'neighborhood': 'Brownwood', 'price': '$12,000', 'url': 'https://abilene.craigslist.org/cto/d/brownwood-2009-mercedes-gl-320/7309894792.html', 'lat': '31.729000', 'lon': '-99.019000', 'address': '', 'misc': ['2009 mercedes-benz gl-class'], 'condition': 'excellent', 'drive': 'fwd', 'fuel': 'diesel', 'odometer': '100700', 'paint_color': 'black', 'title_status': 'clean', 'transmission': 'automatic', 'body': 'BEAUTIFUL car inside and out!! Diesel with only 100k, mechanic says its in great condition.'} # ... ">
import pycraigslist

all_autos = pycraigslist.forsale.cta(site="abilene")
for auto in all_autos.search_detail(include_body=True):
    print(auto)

>>> {'country': 'US',
    'region': 'TX',
    'site': 'abilene',
    'area': '',
    'category': 'cto',
    'id': '7309894792',
    'repost_of': '',
    'last_updated': '2021-04-20 12:17',
    'title': '2009 Mercedes GL-320',
    'neighborhood': 'Brownwood',
    'price': '$12,000',
    'url': 'https://abilene.craigslist.org/cto/d/brownwood-2009-mercedes-gl-320/7309894792.html',
    'lat': '31.729000',
    'lon': '-99.019000',
    'address': '',
    'misc': ['2009 mercedes-benz gl-class'],
    'condition': 'excellent',
    'drive': 'fwd',
    'fuel': 'diesel',
    'odometer': '100700',
    'paint_color': 'black',
    'title_status': 'clean',
    'transmission': 'automatic',
    'body': 'BEAUTIFUL car inside and out!! Diesel with only 100k, mechanic says its in great condition.'}
    # ...

Additional attributes

  • __doc__: Gets category name.
  • url: Gets full URL.
  • count: Gets number of posts.
>> 'apartments / housing for rent' # 2 print(east_bay_apa.url) >>> 'https://sfbay.craigslist.org/search/eby/apa?searchNearby=1&s=0&max_price=800' # 3 print(east_bay_apa.count) >>> 56 ">
import pycraigslist

east_bay_apa = pycraigslist.housing.apa(site="sfbay", area="eby", max_price=800)

# 1
print(east_bay_apa.__doc__)
>>> 'apartments / housing for rent'

# 2
print(east_bay_apa.url)
>>> 'https://sfbay.craigslist.org/search/eby/apa?searchNearby=1&s=0&max_price=800'

# 3
print(east_bay_apa.count)
>>> 56

Exceptions

pycraigslist has the following exceptions:

  • ConnectionError : exceeded maximum retries for a query
  • HTTPError : encountered a client or server error
  • InvalidFilterValue : filter is not recognized or has an invalid value

To use pycraigslist exceptions, import / import from pycraigslist.exceptions. For example:

import pycraigslist
from pycraigslist.exceptions import ConnectionError, HTTPError, InvalidFilterValue

try:
    sf_bikes = pycraigslist.forsale.bia(site="sfbay", area="sfc", min_price=50)
    for bike in sf_bikes.search():
        print(bike)
except ConnectionError:
    print("Yikes! Something's up with the network.")
except HTTPError as e:
    print(f"Bad HTTP response encountered: {e.status_code} {e.detail}")
except InvalidFilterValue as e:
    print(f"Craigslist filter validation failed. Filter: '{e.name}', Value: '{e.value}'")

Contribute

Support

If you are having issues or would like to propose a new feature, please use the issues tracker.

License

The project is licensed under the MIT license.

Owner
Ira Horecka
Ira Horecka
Robot to convert files to direct links, hosting files on Telegram servers, unlimited and without restrictions

stream-cloud demo : downloader_star_bot Run : Docker : install docker , docker-compose set Environment or edit Config/init.py docker-compose up Heroku

53 Dec 21, 2022
Add Reactions to your Channel Posts!

• Shaaak - Post Reaction Bot Simple and Minimalistic telegram bot to add Reactions and Comments to your Channel Posts! - What's Unique About it?

Harsh Raj 4 Jan 31, 2022
Retrieve information from DBLP and update BibTex files automatically

Rebib TLDR: This script retrieves information from DBLP to update your BibTex files. python rebib.py --bibfile xxx.bib It first parses the bib entries

Shangtong Zhang 49 Jan 01, 2023
Select random winners for a Twitter giveaway

twitter_picker Select random winners for a Twitter giveaway Once the Twitter giveaway (or airdrop) is closed, assign a number to each participant. The

Michael Rawner 1 Dec 11, 2021
A python library for creating Slack slash commands using AWS Lambda Functions

slashbot Slashbot makes it easy to create slash commands using AWS Lambda functions. These can be handy for creating a secure way to execute automated

Eric Brassell 17 Oct 21, 2022
Github action for automatically determine the version for next release by using repository tags

This action will automatically determine the version for next release by using repository tags

Igor Gov 7 Oct 25, 2022
Python library for the eWarehousing Solutions API.

eWarehousing Solutions Python Library This library provides convenient access to the eWarehousing Solutions API from applications written in the Pytho

eWarehousing Solutions 2 Nov 09, 2022
A GitHub Follower Bot that is a WIP.

GitHub Follower Bot (WIP) Work In Progress This bot is a WIP. There are still many features I plan to add and code I need to improve (I'm still fairly

Christian Deacon 71 Dec 29, 2022
Petit webhook manager by moi (wassim)

Webhook Manager By wassim oubliez pas de ⭐ le projet Installations il te faut python sinon quand tu va lancer le start.bat sa va tout installer tout s

wassim 9 Jul 08, 2021
This is a open source discord bot project

pythonDiscordBot This is a open source discord bot project #based on the MAX A video: https://www.youtube.com/watch?v=jHZlvRr9KxM Prerequisites Python

Edson Holanda Teixeira Junior 3 Oct 11, 2021
A chatbot that helps you set price alerts for your amazon products.

Amazon Price Alert Bot Description A Telegram chatbot that helps you set price alerts for amazon products. The bot checks the price of your watchliste

Rittik Basu 24 Dec 29, 2022
Telegram Bot for updating ongoing matches of Fotmob.com in channel by @AbirHasan2005

Fotmob-Bot A very simple Telegram Bot which will update ongoing matches of Fotmob in a channel. Demo Channel Configs API_ID - Get this from @TeleORG_B

Abir Hasan 22 Oct 21, 2022
Use CSV files as a Nornir Inventory source with hosts, groups and defaults.

nornir_csv Use CSV files as a Nornir Inventory source with hosts, groups and defaults. This can be used as an equivalent to the Simple Inventory plugi

Matheus Augusto da Silva 2 Aug 13, 2022
As Slack no longer provides an API to invite people, this is a Selenium Python script to do so

As Slack no longer provides an API to invite people, this is a Selenium Python script to do so

Trust-minimized Bitcoin wallet

coldcore Trust-minimized, airgapped Bitcoin management This is experimental software. Wait for a formal release before use with real funds. A trust-mi

James O'Beirne 121 Jan 01, 2023
Open Source Discord bot with many cool features like Weather, Balance, Avatar, User, Server, RP-commands, Gif search, YouTube search, VK post search etc.

Сокобот Дискорд бот с открытым исходным кодом. Содержит в себе экономику, полезные команды (!аватар, !юзер, !сервер и тд.), рп-команды (!обнять, !глад

serverok 2 Jan 16, 2022
Based Telegram Bot and Userbot To Play Music in Your Telegram Groups With Some Cool Extra Features! 🥰

CallMusicPlus69 This Repo base on! 🤗️ A CallsMusic Based Telegram Bot and Userbot To Play Music in Your Telegram Groups With Some Cool Extra Features

brut✘⁶⁹ // ユスフ 6 Jun 26, 2022
Ethone-Selfbot - Open Source Discord Self-Bot, written in discord.py

Ethone SB Table of contents Newest open-source Discord SelfBot with useful commands and easy documentation on how to add your own and change the exist

Ethone 3 Jan 08, 2022
A Python IRC bot with dynamically loadable modules

pybot This is a modular, plugin-based IRC bot written in Python. Plugins can bedynamically loaded and unloaded at runtime. A design goal is the abilli

Jeff Kent 1 Aug 20, 2021
A Telegram bot for personal utilities

Aqua Aqua is a Telegram bot for personal utilities. Installation Prerequisites: Install Poetry for managing dependencies and fork/clone the repository

Guilherme Vasconcelos 2 Mar 30, 2022