mirror of
https://github.com/primedigitaltech/azon_seeker.git
synced 2026-10-05 07:13:06 +08:00
fix: preserve base Amazon product collection
This commit is contained in:
parent
2ad58b6f9c
commit
6fbf8b7bcd
@ -78,19 +78,6 @@ 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">
|
||||
@ -140,12 +127,42 @@ 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],
|
||||
);
|
||||
|
||||
const hiddenDisclosureDom = new JSDOM(
|
||||
`
|
||||
<main id="search">
|
||||
<div class="s-main-slot">
|
||||
<article data-component-type="s-search-result" data-asin="B000000011">
|
||||
<h2>Visible organic product</h2>
|
||||
<span
|
||||
aria-label="Sponsored Ad - hidden disclosure"
|
||||
style="position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0)"
|
||||
>Sponsored</span>
|
||||
<a href="/sspa/click?url=%2Fdp%2FB000000011">
|
||||
<img class="s-image" src="https://example.com/visible-product.jpg" />
|
||||
</a>
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
`,
|
||||
{ url: 'https://www.amazon.com/s?k=mirror' },
|
||||
);
|
||||
Object.assign(globalThis, {
|
||||
document: hiddenDisclosureDom.window.document,
|
||||
Node: hiddenDisclosureDom.window.Node,
|
||||
Element: hiddenDisclosureDom.window.Element,
|
||||
HTMLElement: hiddenDisclosureDom.window.HTMLElement,
|
||||
HTMLAnchorElement: hiddenDisclosureDom.window.HTMLAnchorElement,
|
||||
HTMLImageElement: hiddenDisclosureDom.window.HTMLImageElement,
|
||||
});
|
||||
const hiddenDisclosureItems = await collectAmazonSearchPageData({ pattern: 'pattern-2' });
|
||||
assert.equal(hiddenDisclosureItems.length, 1);
|
||||
assert.equal(hiddenDisclosureItems[0].adType, 'organic');
|
||||
|
||||
console.log('Amazon search parser fixtures passed.');
|
||||
}
|
||||
|
||||
|
||||
@ -42,12 +42,7 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
style.visibility === 'hidden' ||
|
||||
style.visibility === 'collapse' ||
|
||||
style.opacity === '0' ||
|
||||
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))
|
||||
style.getPropertyValue('content-visibility') === 'hidden')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@ -62,6 +57,27 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
);
|
||||
};
|
||||
|
||||
const isVisuallyHiddenText = (node: HTMLElement) => {
|
||||
if (!isVisible(node)) return true;
|
||||
const style = node.ownerDocument.defaultView?.getComputedStyle(node);
|
||||
if (!style) return false;
|
||||
|
||||
const width = Number.parseFloat(style.width);
|
||||
const height = Number.parseFloat(style.height);
|
||||
const screenReaderOnlyBox =
|
||||
(style.position === 'absolute' || style.position === 'fixed') &&
|
||||
style.overflow === 'hidden' &&
|
||||
Number.isFinite(width) &&
|
||||
Number.isFinite(height) &&
|
||||
width <= 1 &&
|
||||
height <= 1;
|
||||
const zeroClip = /rect\(\s*0(?:px)?[, ]+\s*0(?:px)?[, ]+\s*0(?:px)?[, ]+\s*0(?:px)?\s*\)/i.test(
|
||||
style.clip || '',
|
||||
);
|
||||
const insetClip = /inset\(\s*(?:50%|100%)/i.test(style.clipPath || '');
|
||||
return screenReaderOnlyBox || zeroClip || insetClip;
|
||||
};
|
||||
|
||||
const decodeRepeatedly = (value: string) => {
|
||||
let decoded = value;
|
||||
for (let i = 0; i < 3; i++) {
|
||||
@ -94,7 +110,7 @@ export async function collectAmazonSearchPageData(_: SearchPageCollectorPayload)
|
||||
...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;
|
||||
if (isVisuallyHiddenText(candidate)) return false;
|
||||
const accessibleLabels = [
|
||||
candidate.getAttribute('aria-label'),
|
||||
candidate.getAttribute('title'),
|
||||
@ -238,11 +254,6 @@ 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(
|
||||
@ -278,7 +289,6 @@ 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