Input and output data reference
Written by Elena David, SEO, ORM, and AI Visibility Consultant.
Input file format
Both snapshots are CSV files opened with:
csv_path.open("r", encoding="utf-8-sig", newline="")
utf-8-sig accepts ordinary UTF-8 and removes an initial UTF-8 byte-order mark when present. csv.DictReader maps column headers to text values.
Required input fields
| Field | Python value after loading | Required | Constraint | Fictional example |
|---|---|---|---|---|
review_id |
str |
Yes | Non-empty after trimming; first valid occurrence must be unique within the file. | REV-021 |
practice_id |
str |
Yes | Non-empty after trimming. | PR-006 |
practice_name |
str |
Yes | Non-empty after trimming. | Cabinet Médical Exemple |
review_date |
datetime.date |
Yes | Must be accepted by date.fromisoformat(); use YYYY-MM-DD for documented interoperability. |
2026-10-12 |
rating |
int |
Yes | Must convert with int() and be in range(1, 6). |
2 |
review_text |
str |
Yes | Non-empty after trimming. | Fictional review |
source_label |
str |
Yes | Non-empty after trimming. | Demo Reviews |
All required values are stripped of leading and trailing whitespace. Header names are not stripped or case-normalized.
Although the validation message describes YYYY-MM-DD, Python 3.11's date.fromisoformat() accepts some additional ISO 8601 forms. Use YYYY-MM-DD; version 1.0 does not explicitly enforce a regular expression for that exact representation.
Structural validation
The loader compares the header set with the seven required names. One or more missing names raise:
Missing required columns: field_name, another_field
An empty file has no field names and therefore reports all required columns as missing. Extra columns are ignored.
Row validation messages
| Condition | Message form | Result |
|---|---|---|
| Empty required value | empty required field(s): ... |
Row skipped. |
Rating cannot convert with int() |
rating must be a whole number from 1 to 5 |
Row skipped. |
| Integer outside 1–5 | rating must be from 1 to 5 |
Row skipped. |
| Date conversion fails | review_date must use YYYY-MM-DD format |
Row skipped. |
| Valid ID already seen | duplicate review_id '...' in this input |
Later row skipped. |
CSV data rows begin at reported row 2 because row 1 is the header.
In-memory types
Review
├── review_id: str
├── practice_id: str
├── practice_name: str
├── review_date: date
├── rating: int
├── review_text: str
└── source_label: str
LoadResult contains reviews: list[Review] and issues: list[ValidationIssue].
Supported website extraction methods
The importer attempts these methods in order and reports the first format that produces valid records:
- Schema.org
ReviewJSON-LD inapplication/ld+jsonscripts, including reviews nested under an organization or medical-practice entity. - Schema.org
ReviewMicrodata usingitemscope,itemtype, anditempropattributes. - Operator-provided CSS selectors, when enabled in Streamlit.
- The existing
article.reviewlayout.
JSON-LD and Microdata mappings use reviewRating.ratingValue or ratingValue, datePublished, reviewBody or description, and itemReviewed.name. @id, identifier, itemid, and source URLs are retained when present.
The article.review layout uses data-review-id and data-practice-id when available. It contains .review-practice, .review-rating with data-rating or visible rating text, time[datetime], .review-text, and an optional a.review-source[href].
<article class="review" data-review-id="web-001" data-practice-id="practice-demo">
<h2 class="review-practice">Clinique Exemple Rivoli</h2>
<span class="review-rating" data-rating="2">2 stars</span>
<time datetime="2026-10-15">15 October 2026</time>
<p class="review-text">The appointment began later than expected.</p>
<a class="review-source" href="/reviews/web-001">Source</a>
</article>
Extracted fields pass through the same validation as CSV rows. The importer accepts public HTTP(S) URLs only, checks robots.txt, validates redirect destinations, blocks non-public IP space, limits redirects to three and HTML to 2 MB, and uses connection/read timeouts. It does not support arbitrary markup, authenticated pages, CAPTCHAs, JavaScript rendering, or Google review pages.
When a source omits a review or practice identifier, the importer generates a deterministic identifier and displays a notice in the preview. A generated review identifier can change if its source content changes. Missing ratings and dates are not generated or defaulted: the record fails validation and the preview reports the missing fields.
For a custom static layout, configure a container selector plus selectors for review text, rating, date, and practice name. Review ID, practice ID, and source URL selectors are optional. Attribute settings support values stored in attributes such as data-rating, datetime, or href. Invalid selectors produce an unsupported-format error rather than a partial analysis.
Alert CSV output
The alert writer emits the seven review fields plus:
| Field | Type in CSV | Value |
|---|---|---|
alert_reason |
Text | Generated from maximum_rating; the default is New review rated 1 or 2 stars. |
Dates are serialized with date.isoformat(). CSV files contain text, so consumers must parse the rating if they require an integer type.
The output uses UTF-8, includes a header even when no alerts exist, and is overwritten on each run to the same path.
HTML output
The HTML report contains summary counts, a six-column alert table when comparison is available, and validation messages. Dynamic text is HTML-escaped. With no previous snapshot it explicitly states that comparison was not run and does not identify reviews as new. It does not embed the output CSV's practice_id or alert_reason fields.
See Error handling and validation for control flow after each type of problem.