---
title: "Logistics data scraping"
description: "Logistics data from carrier and port websites: vessel schedules, freight rates, surcharges and terminal status from Maersk, MSC, COSCO and APM Terminals."
canonical: https://www.zenrows.com/use-cases/logistics-data
updated: 2026-10-18
---

# Logistics data scraping

Logistics data is the schedule, pricing and status data that carriers, ports and freight platforms publish on their websites, such as vessel schedules, freight rates, surcharges and terminal updates. Zenrows fetches those protected carrier and port pages, runs the schedule search forms when needed, and returns structured JSON your forwarding or visibility platform can load.

## Sample output: one sailing on a lane

```json
{
  "source": "carrier_schedule",
  "carrier": "Example Line",
  "origin": { "port": "Shanghai", "unlocode": "CNSHA" },
  "destination": { "port": "Rotterdam", "unlocode": "NLRTM" },
  "service": "AE7",
  "vessel": "EXAMPLE EXPRESS",
  "voyage": "442W",
  "etd": "2026-10-27T18:00:00+08:00",
  "eta": "2026-11-29T06:00:00+01:00",
  "transit_days": 33,
  "transshipments": [],
  "cutoffs": {
    "documentation": "2026-10-23T12:00:00+08:00",
    "cargo": "2026-10-25T17:00:00+08:00"
  },
  "fetched_at": "2026-10-17T07:00:00Z"
}
```

An illustrative sailing from a point-to-point schedule search, with port names mapped to UN/LOCODE in your pipeline so lanes from different carriers line up.

## What logistics teams collect from the web

Forwarders, freight marketplaces and visibility platforms need the same few facts from dozens of carriers: when a service sails, what it costs, and what is happening at the terminal. Most carriers publish them on their website long before, or instead of, offering an API.

| Job | Data you collect | Typical sources |
|---|---|---|
| Ocean schedule tracking | Vessel, voyage, service, ETD, ETA, transit time, cutoffs per lane | Maersk, MSC, CMA CGM, COSCO, Hapag-Lloyd, HMM, Yang Ming, Evergreen (ShipmentLink) |
| Port and terminal status | Vessel berthing plans, gate hours, container availability, terminal advisories | APM Terminals and port authority vessel-call pages |
| Air cargo schedules and status | Flight schedules, air waybill status, embargo and capacity notices | AF-KLM Cargo, Lufthansa Cargo, Turkish Cargo, Etihad Cargo |
| Freight rate and surcharge benchmarking | Published spot rates, GRI notices, bunker and peak season surcharges | Carrier tariff and customer advisory pages, freight marketplaces |
| Parcel service and pricing | Service levels, published rate tables, fuel and delivery area surcharges | USPS, UPS, FedEx and DHL service and surcharge pages |
| Warehouse and industrial space | Location, size, asking rent, dock doors, availability date | Commercial property portals such as Crexi and broker listings |

## Why carrier websites are hard to scrape

Carrier and terminal sites are queried constantly by forwarders and platforms, and carriers protect them accordingly. The data is also rarely sitting in the HTML waiting to be read.

| What breaks | What it looks like | How Zenrows handles it |
|---|---|---|
| Carrier bot protection | Cloudflare, Akamai or fingerprint checks return 403s and challenge pages on carrier sites | Zenrows' stealth gets through Cloudflare, Akamai and similar protections, with browser rendering when the page needs it |
| Schedules behind a search form | Nothing to read until you enter origin, destination and a date | Page actions fill and submit the form before the page is returned |
| Data from internal APIs | The HTML is an empty shell and the sailings arrive as JSON in a background call | Zenrows captures the page's background network calls (XHR) and returns them with the result |
| A different format per carrier | Twenty carriers, twenty ways to write a port, a date and a voyage | Extract gives you consistent fields to map to UN/LOCODE |
| Advisories buried in news sections | Surcharge and GRI announcements spread across paged notice lists | Crawl the advisory section with an include pattern and Markdown output |
| Weekly refresh windows | Every lane for every carrier has to be re-read when schedules roll forward | Batch runs the full lane list as one job |

## How to collect logistics data with Zenrows

1. **List your lanes and sources.** Write down the origin and destination pairs you quote, and the carriers, terminals and cargo airlines that serve them.
2. **Find where the data lives.** Open each schedule or status page in a browser and check whether results arrive in the HTML or in a background JSON call.
3. **Fetch one lane per request.** Use page actions to fill search forms, and capture the background network calls when the data comes from an internal API. Both run in a full browser render.
4. **Refresh the whole lane list.** Submit every lane URL to Batch on your schedule, daily for terminal status and weekly for sailings, and store each run with a timestamp.

```python Python
# pip install requests
import json
import requests

params = {
    "apikey": "YOUR_ZENROWS_API_KEY",
    "url": "SCHEDULE_SEARCH_URL",  # a carrier's point-to-point schedule page
    "js_render": "true",
    "premium_proxy": "true",
    "json_response": "true",  # include the background API calls in the result
    "js_instructions": json.dumps([
        {"fill": ["#origin", "Shanghai"]},
        {"fill": ["#destination", "Rotterdam"]},
        {"click": "button[type=submit]"},
        {"wait_for": ".schedule-results"},
    ]),
}
response = requests.get("https://api.zenrows.com/v1/", params=params)
print(response.json())  # selectors are illustrative; match them to the carrier
```

```javascript Node.js
// One Batch job for every lane URL you track
const lanes = [
  { url: "LANE_URL_CNSHA_NLRTM", id: "CNSHA-NLRTM" },
  { url: "LANE_URL_SGSIN_USLAX", id: "SGSIN-USLAX" },
];

const res = await fetch("https://async.api.zenrows.com/v1/jobs", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_ZENROWS_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    type: "regular",
    status: "closed",
    zenrows_params: { mode: "auto", extract: "auto" },
    tasks: lanes.map((lane) => ({ url: lane.url, external_id: lane.id })),
  }),
});
const job = await res.json();
console.log("submitted", job.job_id);
```

```bash CLI
npx -y @zenrows/cli init
# Read one carrier advisory page as Markdown before you write a parser
zenrows fetch ADVISORY_URL --output markdown
# lanes.jsonl: one {"url": "LANE_URL"} per line
zenrows batch create lanes.jsonl --wait
zenrows batch results <job-id> --out lanes-results.jsonl
```

```text Claude Code (MCP)
# Connect once
claude mcp add zenrows -e ZENROWS_API_KEY=YOUR_ZENROWS_API_KEY -- npx -y @zenrows/mcp

# Then ask:
Use Zenrows to open the Maersk point-to-point schedule search, look up sailings from
Shanghai to Rotterdam departing next week, and return each sailing's vessel, voyage,
departure date and arrival date as JSON.
```

## Which Zenrows product fits

| If you need to | Use | Why |
|---|---|---|
| Read one schedule, rate or terminal page | [Fetch](/products/fetch) | Fills the search form, renders the page and returns HTML or the captured API JSON |
| Normalize sailings from many carriers | [Extract](/products/extract) | Returns vessel, voyage and dates as fields, whatever the layout |
| Collect every surcharge notice a carrier posts | [Crawl](/products/crawl) | Walks the advisory section and keeps only notice pages |
| Refresh hundreds of lanes on a schedule | [Batch](/products/batch) | One job per refresh, with an `external_id` per lane to join results back |
| Test a source from the terminal | [CLI](/cli) | `fetch` with Markdown output shows what a page holds before you build anything |

## What success looks like

| Measure | What good looks like | How to check it |
|---|---|---|
| Lane coverage | Every lane you quote has current sailings from every carrier that serves it | Count lanes with zero sailings in the latest run, per carrier |
| Schedule freshness | Sailings reflect the carrier's latest published schedule | Compare the age of each record with your refresh interval |
| ETA change capture | Delays and blank sailings show up in the run after the carrier publishes them | Diff ETD and ETA per voyage between consecutive runs |
| Port code match rate | Every port in the data maps to a UN/LOCODE | Share of records whose origin and destination resolve to a code |
| Failed lanes per run | Lanes that error or come back empty are a small, stable share of each run | Count failed and empty results per Batch job, per carrier |

## Logistics data FAQ

### What is logistics data?

Logistics data describes how goods move and what it costs: carrier schedules, transit times, freight rates and surcharges, port and terminal status, air cargo schedules and parcel service levels. Much of it is published on carrier and port websites, which makes web data a practical way to cover carriers that offer no API or EDI feed.

### Can Zenrows scrape Maersk, MSC and COSCO?

Yes. Large carrier sites commonly sit behind protections such as Cloudflare or Akamai, and Zenrows' stealth gets through them. Send requests with Adaptive Stealth Mode, which starts with the lightest setup and escalates to browser rendering and stealth only when a page needs it. Add page actions in a full browser render when the page needs a search before it shows results.

### How do I get vessel schedules from carrier websites?

Most carriers offer a point-to-point schedule search. Fill origin, destination and date with page actions, wait for the results element to load, and read the sailings from the page. If the carrier loads results from its own API, capture the page's background network calls (XHR) and read that JSON directly, which is easier to parse than the rendered table.

### Can I collect freight rates and surcharges?

Yes, for rates the carrier publishes: spot quotes on public pages, tariff tables, and advisory notices for general rate increases, bunker and peak season surcharges. Crawl the advisory section with Markdown output to get every notice as text. Contract rates that sit inside your own carrier account need a logged-in session with Browser .

### Where does container tracking fit?

Tracking individual containers and bills of lading is a supply chain visibility job with its own volume and timing needs. It is covered on the supply chain intelligence page, with code for tracking flows that need clicks.

### How do I match port names across carriers?

Carriers write the same port as "Rotterdam", "NLRTM", "Rotterdam (Maasvlakte)" or a terminal name. Keep a lookup table that maps every spelling you see to its five-letter UN/LOCODE, and resolve each scraped origin and destination through it before you store a sailing. Log any name the table cannot resolve, review that list after each run, and add the new spellings so the match rate climbs over time.

### How often should logistics data be refreshed?

Match the refresh to how often the source changes. Ocean schedules roll forward weekly, so a daily or weekly run works. Terminal availability and gate notices change within the day and suit an hourly run on a short URL list. Surcharge notices are often announced weeks ahead, so a daily crawl of advisory pages is enough.

## Related use cases

- [Supply chain intelligence](https://www.zenrows.com/use-cases/supply-chain-intelligence.md): Container milestones, supplier stock and disruption notices from carrier, supplier and port websites, as JSON.
- [Alternative data for investors](https://www.zenrows.com/use-cases/alternative-data.md): Hiring, pricing, app ranks, reviews and store counts per ticker, collected weekly as point-in-time series.
- [Competitive intelligence](https://www.zenrows.com/use-cases/competitive-intelligence.md): Pricing, hiring, reviews, launches and partners across your market, structured for battlecards and strategy.
- [Dynamic pricing data](https://www.zenrows.com/use-cases/dynamic-pricing.md): Live competitor price, stock and demand inputs for a repricing engine, on demand or on a schedule.
- [Browser automation](https://www.zenrows.com/use-cases/browser-automation.md): Logins, portal lookups and report downloads run in a cloud browser your Playwright or Puppeteer code drives.

Start free: https://app.zenrows.com/register. Docs: https://docs.zenrows.com
