Amazon Scraper API vs Proxy: Choose a Product Data Source
Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.
Read guideBuild a reviewable job-posting sample with source records, duplicate checks, and closure dates before estimating vacancy counts.

A job-market dataset should count observed posting pages first and estimate vacancies only after duplicate and status review. Use sources the team owns or is authorized to access, retain each source observation, and report the employers, locations, dates, exclusions, and unresolved groups behind the estimate.
Decide what the output must answer: for example, changes in postings on a named set of employer career sites, or roles observed in a defined region during a fixed period. This is a sample of selected sources, not a census of vacancies or labor demand.
Before fetching, list the source owner, permitted access path, target pages or application programming interface (API), relevant terms, request pace, role and location filters, observation window, and retention period. Prefer an official feed, export, or API when available. Read the site's terms and applicable access instructions; pause when a source denies access or asks clients to slow down. The Robots Exclusion Protocol is a crawler instruction mechanism, not a general access grant.
One job can appear on an employer site, an applicant tracking system (ATS), and several boards. One posting can also describe multiple hires. Keep a row for each observed page, then link rows into a reviewed vacancy group only when evidence supports the match.
| Record | Example fields | Why it stays separate |
|---|---|---|
| Posting observation | posting_id, source URL, retrieval time, visible title and location, raw response hash |
Records what one source showed at one time |
| Vacancy candidate | vacancy_group_id, matching fields, review state, evidence references |
Groups posting rows for review and remains a hypothesis |
| Status check | checked_at, page status, application status, evidence note |
Records whether a posting still appeared open on a particular date |
Google's JobPosting guidance says JobPosting structured data belongs on a page for one job, not a search-results page. It describes datePosted, validThrough, canonical URLs, and how publishers should update expired postings. These fields help describe a publisher's page; they are not a universal vacancy identifier, and absent or stale markup does not settle whether a role remains open. Schema.org's JobPosting lists the vocabulary fields.
Run the schema example with Python 3.12.0, tested locally; it uses only the standard library.
Start with a compact record contract before building a collector. The example below uses synthetic observations and validates fields; it does not fetch websites, confirm permission, or prove that two posts represent one vacancy.
from datetime import date
from urllib.parse import urlparse
REQUIRED = {"posting_id", "source_url", "employer", "title", "location", "retrieved_on"}
OBSERVATIONS = [
{
"posting_id": "obs-001",
"source_url": "https://careers.example.org/jobs/eng-1",
"employer": "Example Works",
"title": "Platform Engineer",
"location": "Remote, US",
"retrieved_on": "2026-09-24",
},
{
"posting_id": "obs-001",
"source_url": "https://jobs.example.net/posting/44",
"employer": "Example Works",
"title": "Platform Engineer",
"location": "Remote, US",
"retrieved_on": "2026-09-24",
},
{
"posting_id": "obs-003",
"source_url": "file:///tmp/job.html",
"employer": "Example Works",
"title": "Analyst",
"location": "New York",
"retrieved_on": "not-a-date",
},
]
def errors_for(row):
errors = [f"missing {key}" for key in sorted(REQUIRED - row.keys())]
parsed_url = urlparse(row.get("source_url", ""))
if parsed_url.scheme != "https" or not parsed_url.netloc:
errors.append("source_url must be an absolute HTTPS URL")
try:
retrieved_on = row.get("retrieved_on", "")
if date.fromisoformat(retrieved_on).isoformat() != retrieved_on:
raise ValueError
except (TypeError, ValueError):
errors.append("retrieved_on must be YYYY-MM-DD")
if not isinstance(row.get("posting_id"), str) or not row["posting_id"].strip():
errors.append("posting_id must be nonempty text")
return errors
seen = set()
for row in OBSERVATIONS:
errors = errors_for(row)
posting_id = row.get("posting_id")
if isinstance(posting_id, str) and posting_id.strip():
if posting_id in seen:
errors.append("posting_id is not unique")
seen.add(posting_id)
label = posting_id if isinstance(posting_id, str) and posting_id.strip() else "<missing ID>"
print(f'{label}: {"accepted" if not errors else "; ".join(errors)}')
Expected result for the synthetic rows:
obs-001: accepted
obs-001: posting_id is not unique
obs-003: source_url must be an absolute HTTPS URL; retrieved_on must be YYYY-MM-DD
A production validator should also record source-specific identifiers, application URLs where present, structured-data version, response outcome, and missing fields. Keep the raw observation or a controlled reference to it so later corrections do not overwrite what was seen.
Use a requisition ID or canonical application URL when a publisher exposes a stable identifier. Otherwise, compare normalized employer, title, location, employment type, team, and dates as candidate signals. A matching title alone is weak evidence. Preserve both posting rows and route uncertain pairs to review; never turn fuzzy similarity into an unqualified vacancy count.
After review, store a group decision, reviewer, timestamp, matching evidence, and rule version. Re-run a fixed sample after changing normalization rules. A new URL with old text can indicate a repost, but it can also describe a separate opening. Keep the status uncertain until the source record or reviewer resolves it.
Store first_seen, last_seen, checked_at, and status_evidence. Record explicit closure text, a closed application form, a redirect, or an unavailable page separately. A Hypertext Transfer Protocol (HTTP) 200 response can contain a login wall, an empty shell, or a careers index; HTTP success alone is not an open posting. Do not discard a last valid observation after a temporary fetch failure. Mark it stale and report its age.
A board-only sample reflects the sources and search visibility represented by that board. A career-site sample favors employers with discoverable pages. Report the employer frame, board/source mix, geography, remote policy, language, salary disclosure, collection period, field missingness, duplicate rule, closure cadence, and all exclusions before comparing counts. Do not infer the full labor market from that frame.
A proxy can supply a network route for a permitted fetch or a regional presentation check. It does not provide the source list, validate a posting, decide reuse rights, or remove sampling bias. For a route needed by an approved collection, review ProxyLane plans and test the client against one permitted source before scheduling a larger run.
Scale your workflows with the tools you already use. Rotating or sticky sessions up to 72 hours.
Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.
Read guideChoose the right anti-detect browser proxy guide, map the shared verification steps, and keep account access separate from the network route.
Read guideOur picks for market research: ProxyLane for small, intermittent projects, plus options for regional tracking, monthly collection and managed extraction.
Read guide