feat(amazon-shopping): scrape and filter amazon product results
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import type { ProductFilters, ProductSearchResult, SearchProductsResponse } from "./types.js";
|
||||
|
||||
export interface ResponseInput {
|
||||
query: string;
|
||||
filters: ProductFilters;
|
||||
limit: number;
|
||||
maxSearchPages: number;
|
||||
results: ProductSearchResult[];
|
||||
filteredOutCount: number;
|
||||
warnings: string[];
|
||||
now?: () => Date;
|
||||
}
|
||||
|
||||
export function createResponse(input: ResponseInput): SearchProductsResponse {
|
||||
return {
|
||||
query: input.query,
|
||||
filters: input.filters,
|
||||
limit: input.limit,
|
||||
maxSearchPages: input.maxSearchPages,
|
||||
results: input.results,
|
||||
filteredOutCount: input.filteredOutCount,
|
||||
warnings: input.warnings,
|
||||
source: {
|
||||
site: "amazon.com",
|
||||
scrapedAt: (input.now ?? (() => new Date()))().toISOString(),
|
||||
automation: "web-automation/CloakBrowser"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function formatFilters(filters: ProductFilters): string {
|
||||
const parts = [
|
||||
filters.minRating !== undefined ? `rating ${filters.ratingComparison ?? "gte"} ${filters.minRating}` : "",
|
||||
filters.minReviews !== undefined ? `reviews ${filters.reviewCountComparison ?? "gte"} ${filters.minReviews}` : "",
|
||||
filters.maxPrice !== undefined ? `price <= $${filters.maxPrice}` : "",
|
||||
filters.maxUnitPrice !== undefined ? `unit price <= $${filters.maxUnitPrice}` : ""
|
||||
].filter(Boolean);
|
||||
return parts.length > 0 ? parts.join(", ") : "none";
|
||||
}
|
||||
|
||||
function formatProduct(product: ProductSearchResult, index: number): string {
|
||||
const specs = product.specs.slice(0, 3).map((spec) => `${spec.name}: ${spec.value}`).join("; ");
|
||||
const lines = [
|
||||
`${index}. ${product.title}`,
|
||||
` Link: ${product.url}`,
|
||||
` Price: ${product.price?.display ?? "unknown"}${product.unitPrice ? ` (${product.unitPrice.display})` : ""}`,
|
||||
` Rating: ${product.rating ?? "unknown"} stars; reviews: ${product.reviewCount ?? "unknown"}`,
|
||||
` Delivery: ${product.delivery?.display ?? "unknown"}`,
|
||||
specs ? ` Specs: ${specs}` : "",
|
||||
product.bullets[0] ? ` Notes: ${product.bullets.slice(0, 2).join(" ")}` : "",
|
||||
product.missingFields.length > 0 ? ` Missing: ${product.missingFields.join(", ")}` : "",
|
||||
product.isSponsored ? " Sponsored: yes" : ""
|
||||
].filter(Boolean);
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
export function createMarkdownReport(response: SearchProductsResponse): string {
|
||||
const lines = [
|
||||
`# Amazon Shopping Results`,
|
||||
"",
|
||||
`Query: ${response.query}`,
|
||||
`Filters: ${formatFilters(response.filters)}`,
|
||||
`Results returned: ${response.results.length} (filtered out: ${response.filteredOutCount})`,
|
||||
response.warnings.length > 0 ? `Warnings: ${response.warnings.join("; ")}` : "",
|
||||
"",
|
||||
...response.results.map((product, index) => formatProduct(product, index + 1))
|
||||
].filter((line) => line !== "");
|
||||
return `${lines.join("\n")}\n`;
|
||||
}
|
||||
Reference in New Issue
Block a user