Created
August 31, 2023 19:48
-
-
Save diegodukao/627f427647f5649c78ace26f249195c4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const puppeteer = require('puppeteer'); // v13.0.0 or later | |
(async () => { | |
const browser = await puppeteer.launch(); | |
const page = await browser.newPage(); | |
const timeout = 5000; | |
page.setDefaultTimeout(timeout); | |
{ | |
const targetPage = page; | |
await targetPage.setViewport({ | |
width: 2545, | |
height: 764 | |
}) | |
} | |
{ | |
const targetPage = page; | |
const promises = []; | |
promises.push(targetPage.waitForNavigation()); | |
await targetPage.goto('https://br.in-edit.tv/film/453'); | |
await Promise.all(promises); | |
} | |
{ | |
const targetPage = page; | |
await scrollIntoViewIfNeeded([ | |
[ | |
'aria/CATÁLOGO' | |
], | |
[ | |
'div.main-menu > a:nth-of-type(1)' | |
], | |
[ | |
'xpath///*[@id="__layout"]/div/header/div/div/div[2]/div[1]/a[1]' | |
], | |
[ | |
'pierce/div.main-menu > a:nth-of-type(1)' | |
] | |
], targetPage, timeout); | |
const element = await waitForSelectors([ | |
[ | |
'aria/CATÁLOGO' | |
], | |
[ | |
'div.main-menu > a:nth-of-type(1)' | |
], | |
[ | |
'xpath///*[@id="__layout"]/div/header/div/div/div[2]/div[1]/a[1]' | |
], | |
[ | |
'pierce/div.main-menu > a:nth-of-type(1)' | |
] | |
], targetPage, { timeout, visible: true }); | |
await element.click({ | |
offset: { | |
x: 45.5, | |
y: 17.5, | |
}, | |
}); | |
} | |
{ | |
const targetPage = page; | |
await scrollIntoViewIfNeeded([ | |
[ | |
'div.gradient' | |
], | |
[ | |
'xpath///*[@data-test="film-item"]/div/a/div[4]' | |
], | |
[ | |
'pierce/div.gradient' | |
] | |
], targetPage, timeout); | |
const element = await waitForSelectors([ | |
[ | |
'div.gradient' | |
], | |
[ | |
'xpath///*[@data-test="film-item"]/div/a/div[4]' | |
], | |
[ | |
'pierce/div.gradient' | |
] | |
], targetPage, { timeout, visible: true }); | |
await element.click({ | |
offset: { | |
x: 136, | |
y: 38.5, | |
}, | |
}); | |
} | |
{ | |
const targetPage = page; | |
await scrollIntoViewIfNeeded([ | |
[ | |
'aria/Seleção TV' | |
], | |
[ | |
'footer div:nth-of-type(1) > a:nth-of-type(2)' | |
], | |
[ | |
'xpath///*[@id="__layout"]/div/footer/div/div[1]/div[1]/div[2]/div/div[1]/a[2]' | |
], | |
[ | |
'pierce/footer div:nth-of-type(1) > a:nth-of-type(2)' | |
] | |
], targetPage, timeout); | |
const element = await waitForSelectors([ | |
[ | |
'aria/Seleção TV' | |
], | |
[ | |
'footer div:nth-of-type(1) > a:nth-of-type(2)' | |
], | |
[ | |
'xpath///*[@id="__layout"]/div/footer/div/div[1]/div[1]/div[2]/div/div[1]/a[2]' | |
], | |
[ | |
'pierce/footer div:nth-of-type(1) > a:nth-of-type(2)' | |
] | |
], targetPage, { timeout, visible: true }); | |
await element.click({ | |
offset: { | |
x: 88.25, | |
y: 7.5, | |
}, | |
}); | |
} | |
{ | |
const targetPage = page; | |
await scrollIntoViewIfNeeded([ | |
[ | |
'div.page-selecciontv > div > div > div > div:nth-of-type(1) a' | |
], | |
[ | |
'xpath///*[@id="__layout"]/div/div[1]/div/div/div/div[1]/div[1]/a' | |
], | |
[ | |
'pierce/div.page-selecciontv > div > div > div > div:nth-of-type(1) a' | |
] | |
], targetPage, timeout); | |
const element = await waitForSelectors([ | |
[ | |
'div.page-selecciontv > div > div > div > div:nth-of-type(1) a' | |
], | |
[ | |
'xpath///*[@id="__layout"]/div/div[1]/div/div/div/div[1]/div[1]/a' | |
], | |
[ | |
'pierce/div.page-selecciontv > div > div > div > div:nth-of-type(1) a' | |
] | |
], targetPage, { timeout, visible: true }); | |
await element.click({ | |
offset: { | |
x: 199.5, | |
y: 12.875, | |
}, | |
}); | |
} | |
await browser.close(); | |
async function waitForSelectors(selectors, frame, options) { | |
for (const selector of selectors) { | |
try { | |
return await waitForSelector(selector, frame, options); | |
} catch (err) { | |
console.error(err); | |
} | |
} | |
throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); | |
} | |
async function scrollIntoViewIfNeeded(selectors, frame, timeout) { | |
const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); | |
if (!element) { | |
throw new Error( | |
'The element could not be found.' | |
); | |
} | |
await waitForConnected(element, timeout); | |
const isInViewport = await element.isIntersectingViewport({threshold: 0}); | |
if (isInViewport) { | |
return; | |
} | |
await element.evaluate(element => { | |
element.scrollIntoView({ | |
block: 'center', | |
inline: 'center', | |
behavior: 'auto', | |
}); | |
}); | |
await waitForInViewport(element, timeout); | |
} | |
async function waitForConnected(element, timeout) { | |
await waitForFunction(async () => { | |
return await element.getProperty('isConnected'); | |
}, timeout); | |
} | |
async function waitForInViewport(element, timeout) { | |
await waitForFunction(async () => { | |
return await element.isIntersectingViewport({threshold: 0}); | |
}, timeout); | |
} | |
async function waitForSelector(selector, frame, options) { | |
if (!Array.isArray(selector)) { | |
selector = [selector]; | |
} | |
if (!selector.length) { | |
throw new Error('Empty selector provided to waitForSelector'); | |
} | |
let element = null; | |
for (let i = 0; i < selector.length; i++) { | |
const part = selector[i]; | |
if (element) { | |
element = await element.waitForSelector(part, options); | |
} else { | |
element = await frame.waitForSelector(part, options); | |
} | |
if (!element) { | |
throw new Error('Could not find element: ' + selector.join('>>')); | |
} | |
if (i < selector.length - 1) { | |
element = (await element.evaluateHandle(el => el.shadowRoot ? el.shadowRoot : el)).asElement(); | |
} | |
} | |
if (!element) { | |
throw new Error('Could not find element: ' + selector.join('|')); | |
} | |
return element; | |
} | |
async function waitForElement(step, frame, timeout) { | |
const { | |
count = 1, | |
operator = '>=', | |
visible = true, | |
properties, | |
attributes, | |
} = step; | |
const compFn = { | |
'==': (a, b) => a === b, | |
'>=': (a, b) => a >= b, | |
'<=': (a, b) => a <= b, | |
}[operator]; | |
await waitForFunction(async () => { | |
const elements = await querySelectorsAll(step.selectors, frame); | |
let result = compFn(elements.length, count); | |
const elementsHandle = await frame.evaluateHandle((...elements) => { | |
return elements; | |
}, ...elements); | |
await Promise.all(elements.map((element) => element.dispose())); | |
if (result && (properties || attributes)) { | |
result = await elementsHandle.evaluate( | |
(elements, properties, attributes) => { | |
for (const element of elements) { | |
if (attributes) { | |
for (const [name, value] of Object.entries(attributes)) { | |
if (element.getAttribute(name) !== value) { | |
return false; | |
} | |
} | |
} | |
if (properties) { | |
if (!isDeepMatch(properties, element)) { | |
return false; | |
} | |
} | |
} | |
return true; | |
function isDeepMatch(a, b) { | |
if (a === b) { | |
return true; | |
} | |
if ((a && !b) || (!a && b)) { | |
return false; | |
} | |
if (!(a instanceof Object) || !(b instanceof Object)) { | |
return false; | |
} | |
for (const [key, value] of Object.entries(a)) { | |
if (!isDeepMatch(value, b[key])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
}, | |
properties, | |
attributes | |
); | |
} | |
await elementsHandle.dispose(); | |
return result === visible; | |
}, timeout); | |
} | |
async function querySelectorsAll(selectors, frame) { | |
for (const selector of selectors) { | |
const result = await querySelectorAll(selector, frame); | |
if (result.length) { | |
return result; | |
} | |
} | |
return []; | |
} | |
async function querySelectorAll(selector, frame) { | |
if (!Array.isArray(selector)) { | |
selector = [selector]; | |
} | |
if (!selector.length) { | |
throw new Error('Empty selector provided to querySelectorAll'); | |
} | |
let elements = []; | |
for (let i = 0; i < selector.length; i++) { | |
const part = selector[i]; | |
if (i === 0) { | |
elements = await frame.$$(part); | |
} else { | |
const tmpElements = elements; | |
elements = []; | |
for (const el of tmpElements) { | |
elements.push(...(await el.$$(part))); | |
} | |
} | |
if (elements.length === 0) { | |
return []; | |
} | |
if (i < selector.length - 1) { | |
const tmpElements = []; | |
for (const el of elements) { | |
const newEl = (await el.evaluateHandle(el => el.shadowRoot ? el.shadowRoot : el)).asElement(); | |
if (newEl) { | |
tmpElements.push(newEl); | |
} | |
} | |
elements = tmpElements; | |
} | |
} | |
return elements; | |
} | |
async function waitForFunction(fn, timeout) { | |
let isActive = true; | |
const timeoutId = setTimeout(() => { | |
isActive = false; | |
}, timeout); | |
while (isActive) { | |
const result = await fn(); | |
if (result) { | |
clearTimeout(timeoutId); | |
return; | |
} | |
await new Promise(resolve => setTimeout(resolve, 100)); | |
} | |
throw new Error('Timed out'); | |
} | |
async function changeSelectElement(element, value) { | |
await element.select(value); | |
await element.evaluateHandle((e) => { | |
e.blur(); | |
e.focus(); | |
}); | |
} | |
async function changeElementValue(element, value) { | |
await element.focus(); | |
await element.evaluate((input, value) => { | |
input.value = value; | |
input.dispatchEvent(new Event('input', { bubbles: true })); | |
input.dispatchEvent(new Event('change', { bubbles: true })); | |
}, value); | |
} | |
async function typeIntoElement(element, value) { | |
const textToType = await element.evaluate((input, newValue) => { | |
if ( | |
newValue.length <= input.value.length || | |
!newValue.startsWith(input.value) | |
) { | |
input.value = ''; | |
return newValue; | |
} | |
const originalValue = input.value; | |
input.value = ''; | |
input.value = originalValue; | |
return newValue.substring(originalValue.length); | |
}, value); | |
await element.type(textToType); | |
} | |
})().catch(err => { | |
console.error(err); | |
process.exit(1); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment