Skip to main content

liferay-docs-scraper

Scrape learn.liferay.com/w/dxp/* into local Markdown and install a liferay-expert Claude Code skill that answers Liferay DXP questions from those files.

The goal is simple: when you ask Claude Code about Liferay DXP, it should read the current docs you fetched locally, cite the source URL, and avoid guessing from model memory. No bundled Liferay content, no embeddings, no vector DB.

PyPI package · Python 3.10-3.13 · MIT license

Quickstart

From zero to asking Liferay questions in Claude Code:

# 1. One-time browser setup for crawl4ai/Playwright
uvx --from crawl4ai crawl4ai-setup

# 2. Scrape the official Liferay DXP docs into ~/.liferay-docs
uvx liferay-docs-scraper

# 3. Install the Claude Code skill in your current project
npx skills add mordonez/liferay-docs-scraper --skill liferay-expert -a claude-code

# 4. Verify docs freshness, reports, and skill installation
uvx --from liferay-docs-scraper liferay-docs-scraper-doctor

Then ask Claude Code something like:

How do I configure synonym sets in Liferay Search?

The skill searches your local Markdown, reads the best matching pages, and cites the original learn.liferay.com URL from each file's frontmatter.

Keep -a claude-code in the install command. It avoids interactive installer edge cases where the skill can appear installed but not land in .claude/skills/.

Requirements

  • Python 3.10-3.13
  • uv
  • Node/npm for npx skills add

crawl4ai uses Playwright. Run the browser setup once per machine before the first scrape:

uvx --from crawl4ai crawl4ai-setup

How It Works

flowchart LR
  A[learn.liferay.com] --> B[crawl4ai BFS crawl]
  B --> C[local Markdown in ~/.liferay-docs]
  C --> D[search_index.jsonl and anomalies.jsonl]
  C --> E[liferay-expert Claude Code skill]
  D --> E
  E --> F[cited Liferay answers]

The official scraper starts at https://learn.liferay.com/w/dxp/index and uses crawl4ai's BFS deep crawler to follow internal /w/dxp/* links. For each page, it extracts the article body, classifies the URL into a Liferay capability, and writes Markdown locally.

The scraper is intentionally boring:

  • It fetches from the live Liferay docs when you run it; this package does not redistribute Liferay documentation text.
  • It writes to one shared docs directory, so every project can use the same corpus.
  • It retries through crawl4ai, writes files atomically, and exits non-zero when the crawl or page fetches fail.
  • It never starts a long scrape from inside the skill. If docs are missing, the skill tells you which command to run.

Where Files Go

By default, everything is written under:

~/.liferay-docs

Use LIFERAY_DOCS_DIR when you want a repo-local or custom corpus:

export LIFERAY_DOCS_DIR="$PWD/.liferay-docs"
uvx liferay-docs-scraper
uvx --from liferay-docs-scraper liferay-docs-scraper-doctor

Layout:

~/.liferay-docs/
  raw/{capability}/*.md
  raw/_navigation/{capability}/*.md
  raw/_removed/{capability}/*.md
  raw/community-howto/{capability}/*.md
  raw/community-troubleshooting/{capability}/*.md
  reports/filtered/
    search_index.jsonl
    anomalies.jsonl
    summary.json
    *_urls.txt

raw/{capability}/*.md is the main official-docs corpus the skill reads first. raw/_navigation/ keeps table-of-contents/navigation pages out of normal answers while preserving them. raw/_removed/ holds pages only after the scraper directly confirms their original URL is gone.

Refreshing Official Docs

Run the scraper again whenever you want fresh docs:

uvx liferay-docs-scraper

A normal full run usually takes tens of minutes. For a smoke test:

uvx liferay-docs-scraper --max-pages 200

Useful options:

uvx liferay-docs-scraper --max-depth 12
uvx liferay-docs-scraper --max-pages 3000

Each full run starts from the current site state. If a previously known page is not rediscovered by BFS, the scraper checks that page directly before moving it to raw/_removed/. If the page is still alive, it refreshes it directly and records the BFS coverage gap in the reports.

Community Articles

Community articles are optional, larger, and lower-authority than the official DXP docs:

uvx --from liferay-docs-scraper liferay-docs-scraper-community

This fetches Liferay community How-To and Troubleshooting articles from learn.liferay.com/kb-article/*. They are stored separately:

raw/community-howto/{capability}/*.md
raw/community-troubleshooting/{capability}/*.md

Many community articles have no usable capability tag, so they go to _uncategorized/. The skill treats community content as secondary evidence and says so when citing it.

Useful commands:

# Only How-To articles
uvx --from liferay-docs-scraper liferay-docs-scraper-community --resource-type howto

# Smaller test run per resource type
uvx --from liferay-docs-scraper liferay-docs-scraper-community --limit 100

Community scraping can take much longer than the official-docs scrape because it fetches thousands of additional articles.

Installing The Skill

Install liferay-expert into each Claude Code project where you want Liferay help:

npx skills add mordonez/liferay-docs-scraper --skill liferay-expert -a claude-code

Manual install also works: place the skill file at:

.claude/skills/liferay-expert/SKILL.md

The skill resolves docs the same way the scraper does:

  1. $LIFERAY_DOCS_DIR, if set.
  2. ~/.liferay-docs, otherwise.

When answering, it searches reports/filtered/search_index.jsonl when present, falls back to normal file search under raw/, reads Markdown files directly, and cites the url: frontmatter. Official docs are preferred over community articles when both cover the same topic.

Doctor

Use the doctor when something feels off:

uvx --from liferay-docs-scraper liferay-docs-scraper-doctor

It checks:

  • Which docs directory is active.
  • Whether official Markdown exists.
  • How many community Markdown files exist.
  • The official-docs freshness window.
  • Search index and anomaly report entry counts.
  • Whether .claude/skills/liferay-expert/SKILL.md exists in the current project.

To inspect a different project directory:

uvx --from liferay-docs-scraper liferay-docs-scraper-doctor --project-dir /path/to/project

The doctor does not scrape docs and does not install the skill. It only reports status and prints the next command to run.

Reports

The scraper writes agent-facing reports under reports/filtered/.

search_index.jsonl is a local retrieval index. Each JSON line includes title, source URL, source type, capability, file path, headings, and fetched_at. The skill uses it first because it is faster and cleaner than searching every Markdown file.

anomalies.jsonl is an informational scrape-quality report. It flags signals like very short bodies, missing titles, known error markers, unusually large pages, and large body-size swings versus the previous local copy. It does not mean a page is unusable; it means the page may deserve a quick check before you trust or cite it heavily.

summary.json records the latest run counts, crawl failures, direct refreshes, coverage gaps, and search index size.

Troubleshooting

crawl4ai or browser errors on the first run

Run the Playwright setup again:

uvx --from crawl4ai crawl4ai-setup

Claude Code says the skill is missing

Run the install command from the project where you are using Claude Code:

npx skills add mordonez/liferay-docs-scraper --skill liferay-expert -a claude-code

Then verify:

uvx --from liferay-docs-scraper liferay-docs-scraper-doctor

Claude Code says docs are missing

Check whether you are using a custom docs directory:

echo "$LIFERAY_DOCS_DIR"

If it is empty, the skill expects ~/.liferay-docs. If it points somewhere else, run the scraper with that same environment variable.

Docs are stale

Refresh official docs:

uvx liferay-docs-scraper

The doctor warns when official docs are older than about seven days.

A scrape stops partway through

Rerun the same command. Already written Markdown remains usable, but a failed run exits non-zero and avoids treating untouched pages as removed.

Community answers feel weaker than official docs

That is expected. Community How-To and Troubleshooting articles are useful for practical cases and errors, but the skill should label them as community content and prefer official docs when official docs answer the question.

Development

uv sync --group dev
uv run ruff check .
uv run --with pytest python -m pytest
uv build

CI runs lint, tests, and package build on Python 3.10, 3.11, 3.12, and 3.13. It does not run a real scrape. Release publishing is documented in docs/release.md.

License

MIT applies to this tool and skill only. Liferay documentation content remains Liferay's content and is fetched locally by each user.

Release files for liferay-docs-scraper 0.6.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for liferay-docs-scraper 0.6.2
File Size Uploaded
liferay_docs_scraper-0.6.2.tar.gz 49.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for liferay-docs-scraper 0.6.2
File Interpreter ABI Platform
liferay_docs_scraper-0.6.2-py3-none-any.whl Python 3 none any Details

Total release size: 78.9 kB

Release files / liferay_docs_scraper-0.6.2.tar.gz

Download URL liferay_docs_scraper-0.6.2.tar.gz
Size 49.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8f845433253db492197f603e68099098c662f0654e0ef6981526189ddd60c0c9
BLAKE2b-256 checksum
How to use checksums
601a3fbf720c485cb980336a96b520a16c9859b182f224d32f36c581f3d52c32
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / liferay_docs_scraper-0.6.2-py3-none-any.whl

Download URL liferay_docs_scraper-0.6.2-py3-none-any.whl
Size 29.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dd618d27cbe050e16e8981af7559d9c97aa59d11232a89abcd46375488a79d00
BLAKE2b-256 checksum
How to use checksums
6e88a662e62e3278c68096474aa45aa5eecfe4d111bdf1852b61e773fdd4d601
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.6.2 This release

2 release files

0.6.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page