Seafarer Jobs Scraper — 4 Sources, 19K+ Listings avatar

Seafarer Jobs Scraper — 4 Sources, 19K+ Listings

Pricing

from $6.00 / 1,000 results

Go to Apify Store
Seafarer Jobs Scraper — 4 Sources, 19K+ Listings

Seafarer Jobs Scraper — 4 Sources, 19K+ Listings

Seafarer and maritime crewing vacancies from four boards (Martide, Crewell, FindSeaJobs, SeaCrew) in one normalised dataset, ~19,000 listings. Adds monthly-USD salary, rank tier, joining-date countdown and a dataCompleteness flag. Pick boards with sourcesToInclude. Each run writes an HTML dashboard.

Pricing

from $6.00 / 1,000 results

Rating

0.0

(0)

Developer

Sankov Vadim

Sankov Vadim

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Maritime Crewing & Seafarer Jobs Scraper

Four public seafarer job boards — Martide, Crewell, FindSeaJobs and SeaCrew — read in one run and returned as a single normalised dataset of roughly 19,000 live vacancies: rank, vessel type, employer, wage, contract length and joining date, with the same column meaning the same thing whichever board a row came from.

Disclaimer. This is an unofficial, independent job aggregator. It is not affiliated with, endorsed by, sponsored by, or connected to Martide, Crewell, FindSeaJobs, SeaCrew, or any employer listed on those sites. Their names are used here only to identify the publicly accessible websites this Actor reads. All job content belongs to its respective publishers.

What this Actor does

Maritime crewing demand is split across boards that do not talk to each other. A recruiter who wants a view of the market has to read four sites, each with its own field names, its own salary formats and its own pagination. This Actor collapses that into one export.

  1. It crawls each selected board's listing pages in order, following pagination dynamically — it keeps going until a page returns no job cards, so it adapts as a board grows or shrinks. No page count is hard-coded.
  2. On Martide, FindSeaJobs and SeaCrew it opens every individual job page and extracts the full record, not just the summary card. Crewell is read from its listing cards only, for the reason given below.
  3. It maps all four sources onto one shared record shape, so rank, salaryMin and joiningDate mean the same thing in every row. Fields that only one board publishes are not thrown away — they survive under siteSpecificExtra.
  4. It enriches each record with derived fields no board publishes: a monthly-USD wage, a seniority tier and a real calendar joining date.
  5. It marks each record's dataCompleteness so you can always tell a full detail-page extraction from a listing-card one.
  6. It offers a cross-board possibleDuplicateKey, because manning agents cross-post the same berth to several boards.
  7. When the run finishes it builds an HTML run report and saves it to the run's key-value store.

The four sources

SourceSiteApprox. live vacanciesExtractionNotes
Martidemartide.com~130Full detail pagesRichest per-record data: vessel name, DWT, engine type, trading area
Crewellcrewell.net~3,600Listing cards onlyrobots.txt declares Crawl-delay: 10; see below
FindSeaJobsfindseajobs.com~7,300Full detail pagesBot-protection CDN; may need a proxy on some IPs — see below
SeaCrewseacrew.net~8,500Full detail pagesAlso publishes vessel flag, view and applicant counts

Use the sourcesToInclude input to pick which of the four actually run. Every source you include multiplies the number of records, and therefore the cost, of a full crawl — so deselecting the boards you do not need is the main cost control here.

Why Crewell is listing-only

Crewell's robots.txt publishes Crawl-delay: 10. Honouring it means one request every ten seconds, so opening a detail page for each of ~3,600 vacancies would be a ten-hour crawl; reading the 180 listing pages alone takes about half an hour. The same robots.txt also disallows /*/vacancies/details/ and annotates it as an anti-scraping honeypot — every Crewell listing page carries exactly one link into that trap, and this Actor rejects the path explicitly rather than relying on link-following luck.

The cards are rich enough that this costs little: rank, vessel type, salary, joining window, contract length, employer name and employer profile URL are all on the card. Crewell records therefore carry dataCompleteness: "LISTING_ONLY", so you can see what was traded away instead of having to infer it. Records from the other three sources carry "FULL".

FindSeaJobs and proxies

FindSeaJobs sits behind a bot-protection CDN that rejects some datacentre IP ranges. In practice that means:

  • From an Apify platform run it normally works with no proxy at all — verified on a real run.
  • From some other IPs the CDN returns 403 on every path, robots.txt included.

So no proxy is configured by default. If a run reports zero records from FindSeaJobs while the other boards return data, re-run with a residential proxy group in proxyConfiguration. Either way a blocked source never fails the run: it logs the skip and the other three complete normally, and you are not billed for a source that returned nothing.

How it treats the source sites

  • robots.txt is fetched and honoured for every source on every request.
  • Each site's own published limit wins where it is stricter than your maxRequestsPerMinute. Crewell is never crawled faster than 6 requests per minute regardless of the input.
  • The rate limit is applied per source, expressed as a rate rather than a sleep, so one board's politeness rule does not set the pace for the other three.
  • Only publicly accessible pages are read. There is no login, no paywall circumvention and no bot-protection evasion of any kind.
  • Martide's robots.txt carries a Content-Signal: ai-train=no preference. This Actor produces a structured job dataset for recruitment and market-analysis use; it is not an AI training-corpus collector, and buyers should respect that signal in their own downstream use.

Input parameters

Every parameter is optional. With no input at all, the Actor pulls a small 60-record sample so a plain run finishes in well under a minute — set maxItems to whatever size you actually want (1,000, 2,000, 10,000, or 0 for every job currently listed across all four boards, ~19,000 and well over five minutes to run).

ParameterTypeDefaultDescription
sourcesToIncludearrayall fourWhich boards to crawl: martide, crewell, findseajobs, seacrew.
maxItemsinteger60Stop the whole run after this many records across all sources combined. 0 means no limit. A hard spend cap.
maxPagesinteger0Limit listing pages per source. With 4 sources and maxPages=5, up to 20 listing pages are visited in total. 0 means follow pagination until exhausted.
startPageinteger11-based listing page each source begins from. Raise it only to resume or to split a crawl across runs.
includeJobDescriptionbooleantrueInclude the free-text description and its original HTML. Turn off for a tighter tabular export.
maxRequestsPerMinuteinteger60Courtesy rate limit applied to each source separately. A site's own stricter limit still wins.
proxyConfigurationobjectdisabledUsually unnecessary. A residential group is the fallback if FindSeaJobs returns nothing.

Note the asymmetry: maxItems is global, maxPages is per source. A spend cap that silently quadrupled with the number of sources would not be a cap.

Example input

{
"sourcesToInclude": ["martide", "crewell", "findseajobs", "seacrew"],
"maxItems": 500,
"includeJobDescription": true,
"maxRequestsPerMinute": 60
}

Output

One dataset item per vacancy, on a stable column set that does not depend on which sources a run included — a CSV whose columns shift with the input is not a usable export. Fields a given board does not publish are returned as null rather than omitted.

Shared fields

FieldTypeDescription
sourceSitestringmartide, crewell, findseajobs or seacrew. Part of the public contract; these values will not be renamed.
sourceUrlstringCanonical job page on the originating board.
sourceListingIdstringThe board's own id for the listing. Unique per source, not globally — two boards legitimately reuse numbers.
dataCompletenessstringFULL (built from a detail page) or LISTING_ONLY (built from a listing card).
scrapedAtstringISO 8601 timestamp of the extraction.
title / rankstringCombined posting title, and the seafarer rank on its own.
companyNamestringHiring company or manning agent.
vesselType / vesselNamestringe.g. Container Ship, Oil/Chemical Tanker; specific vessel when disclosed.
salaryMin / salaryMaxnumberWage bounds. Equal when a single figure is advertised, distinct for ranges.
salaryCurrency / salaryPeriodstringe.g. USD, MONTH. Both null when no wage is disclosed, so a currency is never reported without an amount.
contractLengthValue / contractLengthUnitnumber / stringe.g. 4, MONTHS.
joiningDatestringRequested embarkation date exactly as the board published it.
datePostedstringISO 8601 publication timestamp, where the board publishes one.
siteSpecificExtraobjectEverything one board publishes and the others do not. See below.
possibleDuplicateKeystringCross-board cross-post signal. See below.

siteSpecificExtra

Flattening four boards to a lowest common denominator would throw away most of what makes each one worth paying for, so anything outside the shared shape lands here instead of being dropped: Martide's deadweight tonnage, engine type and trading area; SeaCrew's vessel flag, view and applicant counts; FindSeaJobs' tags and department; Crewell's joining window. A parser gaining a new field never silently loses it.

Derived fields

Boards publish wages in whatever period the employer chose, ranks as free text, and joining dates often with no year. These five fields are computed from the scraped record so you can sort and filter the export directly, without writing a normalisation pass of your own.

FieldTypeDescription
monthlyEquivalentUsdnumberThe published wage restated as a monthly USD figure — daily rates × 30, weekly × 52/12, annual ÷ 12, monthly unchanged. A published range is reduced to its midpoint. null when no wage is published or when it is not in USD.
salaryNormalizationstringWhy the wage above is or is not present: NORMALIZED_USD, NO_SALARY_PUBLISHED, NON_USD_NOT_CONVERTED or UNSUPPORTED_PAY_PERIOD. Lets you separate "this employer pays nothing we can see" from "we could not convert this currency".
rankTierstringCoarse seniority bucket — Senior, Mid-level, Junior / Support or Unclassified — matched on the rank text. A heuristic, not an official maritime grade.
joiningDateIsostringjoiningDate resolved to a real YYYY-MM-DD date. Boards print "13 September" with no year; the year is inferred from datePosted. null when the text cannot be parsed safely (ASAP, TBC, and similar).
daysUntilJoiningintegerDays from scrapedAt to joiningDateIso. Sort ascending for the most urgent vacancies. Negative values mean the join date has already passed and the listing is stale.

Three deliberate omissions, so you know what the numbers do and do not claim:

  • No currency conversion. Non-USD wages keep their original figures and are flagged NON_USD_NOT_CONVERTED. A published Actor runs for months; a fixed exchange-rate table baked into it would quietly drift and present a stale guess as confidently as a scraped fact.
  • No invented dates. Where the joining text is ambiguous, joiningDateIso and daysUntilJoining are null rather than a guess.
  • No cross-source inference. A field one board omits is never filled in from another board's posting, even when possibleDuplicateKey suggests they are the same berth.

Cross-posting: possibleDuplicateKey

Manning agents cross-post: the same berth appears on two or three of these boards under different ids, different wording and a salary quoted a couple of hundred dollars apart. possibleDuplicateKey hashes the identifying parts — employer, vessel type and rank normalised, salary rounded to a bucket, joining date reduced to its ISO week — so cross-posts of one berth collide.

This Actor never de-duplicates on it. Two matching keys are strong evidence of a cross-post, not proof: sister ships of one operator can legitimately collide. Dropping a real vacancy is worse for a recruiter than seeing two rows, and only you know which way that trade goes for your use. So the key is exported and the decision is yours — GROUP BY possibleDuplicateKey to collapse, or ignore the column. It is null where too little identifying data is present to make any claim at all.

Within a single source, exact re-appearances are de-duplicated during the crawl by sourceListingId, so a vacancy that shifts between listing pages mid-run is saved, and charged, only once.

Dataset views

The dataset ships with four views, selectable in the Console's dataset tab and in exports:

  • Overview — the columns you want when scanning vacancies.
  • Compensation — wage fields plus monthlyEquivalentUsd, salaryNormalization and rankTier.
  • Cross-postingpossibleDuplicateKey alongside the fields that feed it.
  • Source & completeness — provenance, dataCompleteness, and siteSpecificExtra.

Run report (HTML dashboard)

Every run writes a self-contained HTML report to the run's key-value store under the key DASHBOARD. The Actor logs its URL at the end of the run log, and you can also reach it from the run's Storage → Key-value store tab. Open it in a browser — no download, no spreadsheet, no notebook.

The report shows:

  • Run summary tiles — jobs scraped, how many published a wage and what share of the run that is, the average monthly USD wage across those, and the number of distinct employers, vessel types and rank tiers.
  • Wage distribution — a histogram of monthlyEquivalentUsd, so you can see the shape of the market rather than just its mean.
  • Top 10 employers by vacancies — which manning agents are hiring hardest this run.
  • Vacancies by vessel type, by rank tier, by source site and by data completeness.

Practical details:

  • It is one HTML file with the data embedded. Nothing is fetched from a server of ours, and the file can be saved, emailed or attached to a report as-is.
  • Every chart has a plain data table underneath it, behind a Show data table toggle. The numbers stay readable if charts do not render, and screen readers get real table markup rather than a canvas.
  • It follows your system light/dark setting, and it is readable on a phone.

Why this rather than a bare-JSON scraper

Most job-board Actors stop at the raw dump of a single site: unnormalised fields, a thin README, and whatever that site happened to render. The work of making it usable — reading three more boards, reconciling their field names, converting wage periods, resolving year-less dates, bucketing free-text ranks, spotting cross-posts, then building a chart to see what you actually got — lands on you, every run.

Typical job-board ActorThis Actor
CoverageOne boardFour boards, ~19,000 listings, selectable per run
Field namesWhatever the site usedOne shared shape across all sources, stable column set
One-board-only fieldsDropped, or left in an ad-hoc blobPreserved under siteSpecificExtra
Wage fieldsWhatever string the site printedParsed bounds, currency and period, plus a monthly USD equivalent with an explicit status flag
RankFree textFree text plus a seniority tier
Joining date"13 September"Same, plus a real ISO date and a days-out countdown
Cross-posts between boardsInvisiblepossibleDuplicateKey, exported and left to you
Missing dataField absent, or a silent 0Explicit null with a reason code
Extraction depthUnstateddataCompleteness on every record
Seeing your resultsOpen the JSONAn HTML report linked from every run

Who this is for

Crewing and recruitment agencies

A crewing agency staffing container vessels needs to know what the market is paying this week, not last quarter — and across the whole market, not one board. Run this on a daily or weekly schedule and the dataset becomes a live wage benchmark: filter to rank = "Chief Engineer" and vesselType = "Container Ship", sort by monthlyEquivalentUsd, and you can see whether your own offer is competitive before a candidate turns it down. Because that field puts daily, weekly and monthly adverts on one scale, a day-rate posting no longer looks cheap next to a monthly one. And because salaryNormalization is explicit, you benchmark against published wages only instead of silently averaging zeros.

The same dataset supports four further workflows:

  • Competitor monitoring. Group by companyName to see which manning agents are hiring, for which vessel types, and how aggressively they are pricing — including which of them work which boards.
  • Demand forecasting. joiningDateIso and contractLengthValue together show when crew will rotate off and when the next hiring wave lands. Sort by daysUntilJoining to surface the berths that need filling first.
  • Candidate matching. rank, rankTier and vesselType let you match a bench of available seafarers to live vacancies in seconds rather than reading postings one by one.
  • Board coverage analysis. Group by sourceSite and possibleDuplicateKey to see how much of each board is unique and how much is cross-posted — which tells you which boards are worth your own recruiters' time.

Maritime market analysts and job boards

Track wage movement by rank and vessel type over time across four sources at once, or enrich an existing vacancy aggregator with a feed that arrives already normalised and already flagged for cross-posting.

Pricing

This Actor uses Apify's pay-per-event model. One event, job-scraped, is charged once per job record saved to the dataset. You pay nothing for listing pages that yield no data, nothing for a source that is skipped, and nothing for retries.

Two consequences worth knowing:

  • You are never billed twice for the same listing. Records are de-duplicated by sourceListingId within each source during the crawl, so a vacancy that shifts between listing pages mid-run is saved, and charged, once.
  • maxItems is a hard spend cap. Set it and the run stops at exactly that many records across all sources combined. The counter is guarded against the four concurrent source crawlers, so it cannot overshoot.

Frequently asked questions

How current is the data?

Every run reads the live sites. datePosted comes from the posting itself where the board publishes it, and scrapedAt records when the extraction happened, so you can always tell how fresh a record is.

Why do some records have less data than others?

Check dataCompleteness. FULL records were built from an individual job page. LISTING_ONLY records — every Crewell record — were built from the listing card, which carries rank, vessel type, salary, joining window, contract length and employer but not the detail-page fields. The flag is on every row precisely so this is never a guess.

Why is the salary missing on some jobs?

Because the employer did not publish one. Those records carry null wage fields and salaryNormalization: "NO_SALARY_PUBLISHED", rather than a misleading zero. The run report shows what share of the run that was, so you always know how much of the market you are benchmarking against.

How accurate is rankTier?

It is a heuristic. These boards publish ranks as free text with no seniority taxonomy behind them, so the tier is matched on rank keywords — command ranks to Senior, certificated officers and engineers to Mid-level, ratings, cadets and catering crew to Junior / Support. Anything the keywords do not cover returns Unclassified rather than being forced into a bucket. Use it to slice a dataset quickly; use rank itself when the exact grade matters.

Can I run only one board?

Yes. Set sourcesToInclude to just that source. It is also the cheapest way to sample: one board, maxItems: 20.

Where do I find the HTML report?

At the end of the run log, and in the run's Storage → Key-value store tab under the key DASHBOARD. It is a single file you can open, save or forward.

Can I run this on a schedule?

Yes. Use Apify Schedules to run it daily or weekly, and de-duplicate on sourceSite + sourceListingId to maintain a rolling database of live vacancies.

Does it need a proxy?

Normally no. All four boards have been crawled from an Apify platform run with no proxy configured. Martide, Crewell and SeaCrew serve plain server-rendered HTML with no bot protection at all; FindSeaJobs has a CDN in front of it that refuses some IP ranges, so a residential group is the fallback if that one board comes back empty.

This Actor collects only publicly available job postings. It does not collect seafarer personal data, does not access any account-protected area, and does not bypass authentication or bot protection on any of the four sources.

Job listing content remains the property of the publishers. You are responsible for ensuring your use of the data complies with applicable law — including data protection rules in your jurisdiction — and with each source site's own terms. If you intend to republish scraped listings, review those terms first.