Skip to content

About

Parse the location strings job boards actually emit — remote detection, ATS corruption stripping, alias normalization. Zero dependencies.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

location-parser

tests license: MIT

Parse the location strings that job boards actually emit.

The location normalizer from SearchSteward's ingest pipeline, published as a standalone, dependency-free Python library. It turns the free-text location field of a job posting into structured {city, admin, country, remote} components and a clean display string.

Real ATS location fields are not clean data. Across millions of scraped postings we've stored, all of these are actual values from the location field:

Raw value What it should mean
Gretna, Louisiana / R-26-0036719 Workday appends the requisition id
San Francisco, CA / {'name': 'San Francisco, CA'} Greenhouse leaks its API dict
Washington, DC 20004 trailing ZIP makes "washington" parse as WA state
9 Locations a count, not a place
Us - San Francisco, Nyc, 9Th Arrondissement .title() corruption
Mexico, Remote remote — but not US-remote
Hybrid - Chicago, IL work arrangement glued onto the place
Toronto, ontario, CA Canada — not California
Bengaluru, IN India — not Indiana
Memphis, TN <span class=… a real city with an HTML tag tail
FLORIDA - VIRTUAL - FL01 an arrangement standing where a city should be
Byron Center, Michigan a real town, not "Byron" plus a facility word

This library handles all of them.

Install

# One file, stdlib only — vendor it:
curl -O https://raw.githubusercontent.com/searchsteward/location-parser/main/location_parser.py

A PyPI package (steward-location-parser) is planned; the file above is the same code.

Usage

from location_parser import (
    parse_job_location, normalize_location_text, titlecase_place, is_us_or_remote,
    country_and_region, is_canadian_location,
)

parse_job_location("Hybrid - Washington, DC 20004")
# {'remote': False, 'city': 'washington', 'admin': 'DC', 'country': 'US'}

normalize_location_text("Gretna, Louisiana / R-26-0036719")
# 'Gretna, LA, US'

normalize_location_text("Mexico, Remote")
# 'Mexico, Remote'          — the country survives; this is NOT a US-remote role

normalize_location_text("Remote - United States")
# 'Remote'

titlecase_place("us - san francisco")
# 'US - San Francisco'      — .title() would give 'Us - San Francisco'

is_us_or_remote("EMEA [Remote]")   # False — remote, but scoped to a region
is_us_or_remote("California, Remote")  # True

country_and_region("Austin, TX")            # ('US', 'TX')
country_and_region("Toronto, ontario, CA")  # ('CA', 'ON')   — not California
country_and_region("Bengaluru, IN")         # ('IN', None)   — not Indiana
country_and_region("Nowhere In Particular") # (None, None)   — never guesses

is_canadian_location("Ontario, CA")   # False — the city in California
is_canadian_location("CA / Remote")   # True

API

Function Returns
parse_job_location(s) {city, admin, country, remote} components
country_and_region(s) canonical (ISO 3166-1 alpha-2, subdivision code), or (None, None)
normalize_location_text(s) a clean single-line rendering
sanitize_location_for_display(s) strips known corruptions without parsing
is_remote(s) / is_us_or_remote(s) / is_canadian_location(s) bool predicates
titlecase_place(s) casing that survives US, NYC, McLean, 9th
strip_markup_tail(s) / is_location_list(s) / join_places(parts) helpers

What it handles

  • 300+ country/state/city aliases — "deutschland" → DE, "bombay" → mumbai, "sf bay area" → san francisco, full US state names and abbreviations, Canadian provinces.
  • Remote detection that keeps the geography. "Remote - Philippines" is remote and Philippine — collapsing it to bare "Remote" is how foreign roles sneak into US-only feeds. Bare "Remote" with no other geography defaults to US-remote.
  • ATS corruption stripping: Workday trailing req-ids, both Greenhouse dict-leak formats (YAML-flow and Python-repr, including unclosed-brace variants), trailing US ZIPs, "N Locations" placeholders, work-arrangement prefixes ("hybrid in", "on-site in", "based in").
  • Casing that doesn't destroy meaning. titlecase_place preserves acronyms (NYC, EMEA), already-uppercase state codes (Portland, OR — where .lower() would turn Oregon into a disjunction), ordinals (9th), and mixed case (McLean).
  • Canada, correctly. "Toronto, ON, CA" is the single most common Canadian shape in the wild, and a naive parser reads the trailing CA as California and drops the province. country_and_region and normalize_location_text both resolve Canada through one predicate so they can never disagree — while "Ontario, CA" still stays the city in California.
  • ISO2 codes that collide with US states. "Bengaluru, IN" is India, not Indiana; "Bogota, CO" is Colombia, not Colorado. A colliding code only flips to the country when another token in the same string corroborates it, so "Denver, CO" is unaffected.
  • HTML that leaked into the location field. A scraped "Memphis, TN <span…" keeps its city; a location field holding a whole job description resolves to nothing rather than to whatever country name the prose happened to contain.
  • Work arrangements standing where a city should be. "FLORIDA - VIRTUAL - FL01" and "USA, CT, Home Office" do not yield cities called "Virtual" and "Home" — which were, respectively, the most common "cities" in our corpus before this was fixed.
  • Facility words stripped without truncating real towns. "Denver Service Center" is a building; "Byron Center, Michigan" is a municipality 20 miles from Byron. Both resolve correctly.
  • Garbage rejection: "Not specified", "TBD", "Various", "Flexible" parse to nothing instead of fake places.

Scope

  • Rule-based and deterministic — no geocoding service, no network, no dependencies. Ambiguity is resolved conservatively (e.g. "CA" is never guessed between California and Canada from casing alone).
  • North-America-centric admin parsing: US states and Canadian provinces are first-class and round-trip to ISO 3166-2 subdivision codes; other international locations resolve to city + country.

Location parsing originally ported and adapted from Feashliaa/job-board-aggregator (MIT).

About

Built and maintained by SearchSteward — a job-search radar that watches 50,000+ company career pages and scores every new opening against your résumé. A location filter is only as good as its parser, so we publish the parser.

License

MIT. Contributions welcome — see CONTRIBUTING.md.

About

Parse the location strings job boards actually emit — remote detection, ATS corruption stripping, alias normalization. Zero dependencies.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages