mirror of
https://github.com/primedigitaltech/azon_seeker.git
synced 2026-10-05 15:22:59 +08:00
fix: classify bottom Sponsored Brands video placements
This commit is contained in:
parent
793c343fb6
commit
6b4aa2306a
@ -47,6 +47,19 @@ const html = `
|
|||||||
<a href="/dp/B000000005"><img src="https://example.com/unknown.jpg" /></a>
|
<a href="/dp/B000000005"><img src="https://example.com/unknown.jpg" /></a>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="bottom-sponsored-video-module">
|
||||||
|
<video></video>
|
||||||
|
<span>Sponsored</span>
|
||||||
|
<div class="puis-card-container">
|
||||||
|
<div class="puisg-row">
|
||||||
|
<article data-asin="B000000008">
|
||||||
|
<h3>Sponsored Brands video product</h3>
|
||||||
|
<a href="/dp/B000000008"><img src="https://example.com/brand-video.jpg" /></a>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside id="rightResultsATF" data-component-type="sponsored-display">
|
<aside id="rightResultsATF" data-component-type="sponsored-display">
|
||||||
@ -71,7 +84,7 @@ Object.assign(globalThis, {
|
|||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const items = await collectAmazonSearchPageData({ pattern: 'pattern-2' });
|
const items = await collectAmazonSearchPageData({ pattern: 'pattern-2' });
|
||||||
assert.equal(items.length, 7);
|
assert.equal(items.length, 8);
|
||||||
|
|
||||||
const byAsin = new Map(items.map((item) => [item.asin, item]));
|
const byAsin = new Map(items.map((item) => [item.asin, item]));
|
||||||
assert.equal(byAsin.get('B000000003')?.adType, 'organic');
|
assert.equal(byAsin.get('B000000003')?.adType, 'organic');
|
||||||
@ -90,9 +103,13 @@ async function main() {
|
|||||||
assert.equal(byAsin.get('B000000005')?.placement, 'bottomOfSearch');
|
assert.equal(byAsin.get('B000000005')?.placement, 'bottomOfSearch');
|
||||||
assert.equal(byAsin.get('B000000006')?.adType, 'sponsoredDisplay');
|
assert.equal(byAsin.get('B000000006')?.adType, 'sponsoredDisplay');
|
||||||
assert.equal(byAsin.get('B000000006')?.placement, 'sidebar');
|
assert.equal(byAsin.get('B000000006')?.placement, 'sidebar');
|
||||||
|
assert.equal(byAsin.get('B000000008')?.adType, 'sponsoredBrands');
|
||||||
|
assert.equal(byAsin.get('B000000008')?.adFormat, 'video');
|
||||||
|
assert.equal(byAsin.get('B000000008')?.placement, 'bottomOfSearch');
|
||||||
|
assert.equal(items.filter((item) => item.asin === 'B000000008').length, 1);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
items.map((item) => item.pageRank),
|
items.map((item) => item.pageRank),
|
||||||
[1, 2, 3, 4, 5, 6, 7],
|
[1, 2, 3, 4, 5, 6, 7, 8],
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('Amazon search parser fixtures passed.');
|
console.log('Amazon search parser fixtures passed.');
|
||||||
|
|||||||
@ -134,17 +134,18 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
|||||||
|
|
||||||
const findAdModule = (card: HTMLElement) => {
|
const findAdModule = (card: HTMLElement) => {
|
||||||
let current: HTMLElement | null = card;
|
let current: HTMLElement | null = card;
|
||||||
for (let depth = 0; current && depth < 6; depth++, current = current.parentElement) {
|
let singleProductModule: HTMLElement | undefined;
|
||||||
|
for (; current; current = current.parentElement) {
|
||||||
if (isMainResultsBoundary(current)) break;
|
if (isMainResultsBoundary(current)) break;
|
||||||
const explicitModule = hasExplicitAdMetadata(current);
|
const explicitModule = hasExplicitAdMetadata(current);
|
||||||
const brandedSponsoredModule =
|
const brandedSponsoredModule =
|
||||||
current !== card && hasSponsoredDisclosure(current) && hasBrandCreative(current);
|
current !== card && hasSponsoredDisclosure(current) && hasBrandCreative(current);
|
||||||
const singleProductSponsored =
|
const singleProductSponsored =
|
||||||
current !== card && hasSponsoredDisclosure(current) && uniqueAsinsIn(current) === 1;
|
current !== card && hasSponsoredDisclosure(current) && uniqueAsinsIn(current) === 1;
|
||||||
if (explicitModule || brandedSponsoredModule || singleProductSponsored)
|
if (explicitModule || brandedSponsoredModule) return current;
|
||||||
return current;
|
if (singleProductSponsored && !singleProductModule) singleProductModule = current;
|
||||||
}
|
}
|
||||||
return card;
|
return singleProductModule || card;
|
||||||
};
|
};
|
||||||
|
|
||||||
const classifyAd = (card: HTMLElement, module: HTMLElement) => {
|
const classifyAd = (card: HTMLElement, module: HTMLElement) => {
|
||||||
@ -235,7 +236,8 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
|||||||
(other, otherIndex) =>
|
(other, otherIndex) =>
|
||||||
index !== otherIndex &&
|
index !== otherIndex &&
|
||||||
card.contains(other) &&
|
card.contains(other) &&
|
||||||
card.dataset.asin === other.dataset.asin,
|
parseAsin(card, card.querySelector<HTMLAnchorElement>('a[href]')?.href) ===
|
||||||
|
parseAsin(other, other.querySelector<HTMLAnchorElement>('a[href]')?.href),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.sort((left, right) => {
|
.sort((left, right) => {
|
||||||
@ -252,6 +254,7 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
|||||||
const placementRanks = new Map<HTMLElement, number>();
|
const placementRanks = new Map<HTMLElement, number>();
|
||||||
const adRanks = new Map<AmazonAdType, number>();
|
const adRanks = new Map<AmazonAdType, number>();
|
||||||
const moduleProductIndexes = new Map<HTMLElement, number>();
|
const moduleProductIndexes = new Map<HTMLElement, number>();
|
||||||
|
const moduleAsins = new Map<HTMLElement, Set<string>>();
|
||||||
let nextPlacementRank = 1;
|
let nextPlacementRank = 1;
|
||||||
|
|
||||||
return cards.reduce<CollectedItem[]>((items, card) => {
|
return cards.reduce<CollectedItem[]>((items, card) => {
|
||||||
@ -283,6 +286,12 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
|||||||
|
|
||||||
const module = findAdModule(card);
|
const module = findAdModule(card);
|
||||||
const classification = classifyAd(card, module);
|
const classification = classifyAd(card, module);
|
||||||
|
if (classification.adType !== 'organic') {
|
||||||
|
const seenAsins = moduleAsins.get(module) || new Set<string>();
|
||||||
|
if (seenAsins.has(asin)) return items;
|
||||||
|
seenAsins.add(asin);
|
||||||
|
moduleAsins.set(module, seenAsins);
|
||||||
|
}
|
||||||
let placementRank: number | undefined;
|
let placementRank: number | undefined;
|
||||||
let placementId: string | undefined;
|
let placementId: string | undefined;
|
||||||
let adRank: number | undefined;
|
let adRank: number | undefined;
|
||||||
@ -308,8 +317,7 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
|||||||
const afterLastOrganic =
|
const afterLastOrganic =
|
||||||
lastOrganicCandidate &&
|
lastOrganicCandidate &&
|
||||||
Boolean(
|
Boolean(
|
||||||
module.compareDocumentPosition(lastOrganicCandidate) &
|
module.compareDocumentPosition(lastOrganicCandidate) & Node.DOCUMENT_POSITION_PRECEDING,
|
||||||
Node.DOCUMENT_POSITION_PRECEDING,
|
|
||||||
);
|
);
|
||||||
placement = beforeFirstOrganic
|
placement = beforeFirstOrganic
|
||||||
? 'topOfSearch'
|
? 'topOfSearch'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user