mirror of
https://github.com/primedigitaltech/azon_seeker.git
synced 2026-10-05 15:22:59 +08:00
fix: ignore hidden Amazon sponsored products
This commit is contained in:
parent
3f34ed8341
commit
2ad58b6f9c
@ -78,6 +78,19 @@ const html = `
|
||||
<a href="/dp/B000000010"><img src="https://example.com/hidden-aria.jpg" /></a>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="featured-from-amazon-brands">
|
||||
<span>Featured from Amazon brands</span>
|
||||
<article data-asin="B000000011">
|
||||
<h3
|
||||
aria-label="Sponsored Ad - hidden brand-banner product"
|
||||
style="position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0)"
|
||||
>Hidden brand-banner product</h3>
|
||||
<a href="/sspa/click?url=%2Fdp%2FB000000011">
|
||||
<img src="https://example.com/visible-brand-hero.jpg" />
|
||||
</a>
|
||||
</article>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<aside id="rightResultsATF" data-component-type="sponsored-display">
|
||||
@ -127,6 +140,7 @@ async function main() {
|
||||
assert.equal(items.filter((item) => item.asin === 'B000000008').length, 1);
|
||||
assert.equal(byAsin.has('B000000009'), false);
|
||||
assert.equal(byAsin.has('B000000010'), false);
|
||||
assert.equal(byAsin.has('B000000011'), false);
|
||||
assert.deepEqual(
|
||||
items.map((item) => item.pageRank),
|
||||
[1, 2, 3, 4, 5, 6, 7, 8],
|
||||
|
||||
@ -42,7 +42,12 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
style.visibility === 'hidden' ||
|
||||
style.visibility === 'collapse' ||
|
||||
style.opacity === '0' ||
|
||||
style.getPropertyValue('content-visibility') === 'hidden')
|
||||
style.getPropertyValue('content-visibility') === 'hidden' ||
|
||||
(style.clip !== 'auto' && style.clip !== '') ||
|
||||
(style.clipPath !== 'none' && style.clipPath !== '') ||
|
||||
(style.overflow === 'hidden' &&
|
||||
Number.parseFloat(style.width) <= 1 &&
|
||||
Number.parseFloat(style.height) <= 1))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@ -85,10 +90,11 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
|
||||
const hasSponsoredDisclosure = (node: Element) => {
|
||||
const candidates = [
|
||||
node,
|
||||
...Array.from(node.querySelectorAll('[aria-label], [title], span, a')),
|
||||
];
|
||||
...(node.matches('[aria-label], [title], span') ? [node] : []),
|
||||
...Array.from(node.querySelectorAll('[aria-label], [title], span')),
|
||||
].filter((candidate): candidate is HTMLElement => candidate instanceof HTMLElement);
|
||||
return candidates.some((candidate) => {
|
||||
if (!isVisible(candidate)) return false;
|
||||
const accessibleLabels = [
|
||||
candidate.getAttribute('aria-label'),
|
||||
candidate.getAttribute('title'),
|
||||
@ -98,21 +104,10 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return /^(Sponsored|赞助)(?:\b|\s|$)/i.test(text(candidate));
|
||||
return candidate.matches('span') && /^(Sponsored|赞助)(?:\b|\s|$)/i.test(text(candidate));
|
||||
});
|
||||
};
|
||||
|
||||
const hasSponsoredLink = (node: Element) =>
|
||||
Array.from(node.querySelectorAll<HTMLAnchorElement>('a[href]')).some((anchor) => {
|
||||
const href = decodeRepeatedly(anchor.href).toLowerCase();
|
||||
return (
|
||||
href.includes('/sspa/click') ||
|
||||
href.includes('/gp/slredirect') ||
|
||||
href.includes('adid=') ||
|
||||
href.includes('qualifier=')
|
||||
);
|
||||
});
|
||||
|
||||
const metadata = (node: Element) =>
|
||||
[
|
||||
node.getAttribute('data-component-type'),
|
||||
@ -176,13 +171,7 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
'aside, #rightResultsATF, .s-right-column, [data-cel-widget*="right"], [data-component-type*="sidebar"]',
|
||||
),
|
||||
);
|
||||
const sponsored =
|
||||
hasSponsoredDisclosure(card) ||
|
||||
hasSponsoredDisclosure(module) ||
|
||||
hasSponsoredLink(card) ||
|
||||
hasSponsoredLink(module) ||
|
||||
hasExplicitAdMetadata(card) ||
|
||||
hasExplicitAdMetadata(module);
|
||||
const sponsored = hasSponsoredDisclosure(card) || hasSponsoredDisclosure(module);
|
||||
|
||||
if (!sponsored) {
|
||||
return {
|
||||
@ -205,7 +194,7 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
adFormat: module.querySelector('video') ? ('video' as const) : ('standard' as const),
|
||||
};
|
||||
}
|
||||
if (hasSponsoredDisclosure(card) || hasSponsoredLink(card)) {
|
||||
if (hasSponsoredDisclosure(card)) {
|
||||
return {
|
||||
adType: 'sponsoredProducts' as const,
|
||||
placement: 'middleOfSearch' as const,
|
||||
@ -249,6 +238,11 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
});
|
||||
|
||||
const cards = Array.from(candidateSet)
|
||||
.filter((card) => {
|
||||
const titleNode = card.querySelector<HTMLElement>('h2[aria-label], h2, h3[aria-label], h3');
|
||||
const imageNode = card.querySelector<HTMLImageElement>('img.s-image, img[src]');
|
||||
return Boolean(titleNode && imageNode && isVisible(titleNode) && isVisible(imageNode));
|
||||
})
|
||||
.filter(
|
||||
(card, index, all) =>
|
||||
!all.some(
|
||||
@ -284,6 +278,7 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
|
||||
const titleNode = card.querySelector<HTMLElement>('h2[aria-label], h2, h3[aria-label], h3');
|
||||
const imageNode = card.querySelector<HTMLImageElement>('img.s-image, img[src]');
|
||||
if (!titleNode || !imageNode || !isVisible(titleNode) || !isVisible(imageNode)) return items;
|
||||
const title =
|
||||
titleNode?.getAttribute('aria-label')?.trim() ||
|
||||
text(titleNode) ||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user