You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
5.5 KiB
187 lines
5.5 KiB
const puppeteer = require('puppeteer');
|
|
const fs = require('fs').promises;
|
|
|
|
|
|
const FACEBOOK_URL = '<%POSTURL%>';
|
|
|
|
|
|
const isLoggedIn = async (page) => {
|
|
|
|
const current_url_cookies = await page.cookies();
|
|
if(current_url_cookies.filter(x=>x.name == 'c_user').length == 0){
|
|
|
|
throw 'Not Login';
|
|
}
|
|
};
|
|
|
|
const loginWithSession = async (cookies, page) => {
|
|
|
|
await page.setCookie(...cookies);
|
|
await page.goto(FACEBOOK_URL, { waitUntil: 'networkidle2' });
|
|
await isLoggedIn(page).catch((error) => {
|
|
|
|
throw error;
|
|
});
|
|
}
|
|
|
|
|
|
const loginWithCredentials = async (username, password, page) => {
|
|
//console.log('Logging into Facebook using credentials for', username);
|
|
|
|
await page.goto(FACEBOOK_URL, {
|
|
waitUntil: 'networkidle2',
|
|
});
|
|
|
|
await page.waitForSelector('input[name=email]');
|
|
await page.click('input[name=email]');
|
|
await page.type('input[name=email]', username);
|
|
|
|
await page.waitForSelector('input[name=pass]');
|
|
await page.click('input[name=pass]');
|
|
await page.type('input[name=pass]', password);
|
|
|
|
const cookieBanner = 'div[data-testid="cookie-policy-banner"]';
|
|
if (await page.$(cookieBanner) !== null) {
|
|
//console.log('Facebook cookie banner found');
|
|
await page.evaluate((selector) => {
|
|
const elements = document.querySelectorAll(selector);
|
|
for (let i = 0; i < elements.length; i += 1) {
|
|
elements[i].parentNode.removeChild(elements[i]);
|
|
}
|
|
}, cookieBanner);
|
|
}
|
|
|
|
await page.waitForSelector("div[aria-label='Accessible login button']");
|
|
await page.click("div[aria-label='Accessible login button']");
|
|
await page.waitForNavigation();
|
|
await isLoggedIn(page).catch((error) => {
|
|
console.error('App is not logged into Facebook');
|
|
throw error;
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getDefaultBrowser = async (headless) => {
|
|
const browser = await puppeteer.launch({
|
|
headless: false,
|
|
devtools: false,
|
|
args: ['--no-sandbox', '--disable-setuid-sandbox',"--disable-notifications"],
|
|
});
|
|
const context = browser.defaultBrowserContext();
|
|
context.overridePermissions(FACEBOOK_URL, []);
|
|
return browser;
|
|
};
|
|
|
|
const getDefaultPage = async (browser) => {
|
|
const page = await browser.newPage();
|
|
await page.setViewport({ width: 1920, height: 1000 });
|
|
return page;
|
|
};
|
|
|
|
(async () => {
|
|
const browser = await getDefaultBrowser(true);
|
|
const page = await getDefaultPage(browser);
|
|
const username = '<%ACCOUNT%>';
|
|
const password = '<%ENTERCODE%>';
|
|
|
|
// Load cookies from previous session
|
|
const cookies = await fs.readFile('cookies.js')
|
|
.then((facebookCookies) => JSON.parse(facebookCookies))
|
|
.catch((error) => {
|
|
console.error(`Unable to load FB cookies file: ${error}`);
|
|
return {};
|
|
});
|
|
// use for debug
|
|
//await page.cookies().then(async (freshCookies) => {
|
|
//console.log(JSON.stringify(freshCookies, null, 2));
|
|
//});
|
|
|
|
// Use our cookies to login. If it fails fallback to username and password login.
|
|
if (cookies && Object.keys(cookies).length) {
|
|
await loginWithSession(cookies, page).catch(async (error) => {
|
|
console.error(`Unable to login using session: ${error}`);
|
|
await loginWithCredentials(username, password, page);
|
|
});
|
|
} else {
|
|
await loginWithCredentials(username, password, page);
|
|
}
|
|
|
|
// Save our freshest cookies that contain our Facebook session
|
|
await page.cookies().then( async(freshCookies) => {
|
|
await fs.writeFile('cookies.js', JSON.stringify(freshCookies, null, 2)).catch(async (error)=>{
|
|
|
|
await fs.access('cookies.js', fs.F_OK);
|
|
await fs.writeFile('cookies.js', JSON.stringify(freshCookies, null, 2));
|
|
});
|
|
});
|
|
|
|
|
|
await page.waitForSelector("div[aria-label='可對此貼文採取的動作']");
|
|
await page.click("div[aria-label='可對此貼文採取的動作']");
|
|
|
|
|
|
await page.waitForXPath('//span[contains(text(), "編輯貼文")]'); //
|
|
const linkEx = await page.$x('//span[contains(text(), "編輯貼文")]');
|
|
|
|
|
|
if (linkEx.length > 0) {
|
|
await linkEx[0].click();
|
|
}
|
|
|
|
|
|
|
|
await page.waitForSelector("div[aria-label='移除貼文附件']");
|
|
await page.click("div[aria-label='移除貼文附件']");
|
|
|
|
await page.waitForSelector("div[aria-label='相片/影片']");
|
|
//await page.click("div[aria-label='相片/影片']");
|
|
|
|
try{
|
|
const [fileChooser] = await Promise.all([
|
|
page.waitForFileChooser(),
|
|
page.click("div[aria-label='相片/影片']")
|
|
]);
|
|
await fileChooser.cancel() ;
|
|
}
|
|
catch(e)
|
|
{
|
|
console.error(`Unable Get Dialog: ${e}`);
|
|
}
|
|
|
|
|
|
// get the ElementHandle of the selector above
|
|
// aria-label="附加相片或影片"
|
|
//const inputUploadHandles = await page.$x("//input[contains(@accept,'video')]");
|
|
// const inputUploadHandle = inputUploadHandles[0];
|
|
await page.waitForXPath('//input[@multiple]');
|
|
await page.waitForTimeout(2000);
|
|
var inputUploadHandles = await page.$x('//input[@multiple]');
|
|
var inputUploadHandle = inputUploadHandles[0];
|
|
|
|
|
|
// prepare file to upload, I'm using test_to_upload.jpg file on same directory as this script
|
|
// Photo by Ave Calvar Martinez from Pexels https://www.pexels.com/photo/lighthouse-3361704/
|
|
|
|
const files = await Promise.all(<%UPLOAD_MEDIA_JSONARRAY%>);
|
|
|
|
// Sets the value of the file input to fileToUpload
|
|
await inputUploadHandle.uploadFile(...files);
|
|
|
|
await inputUploadHandle.evaluate(upload => upload.dispatchEvent(new Event('change')));
|
|
|
|
|
|
await page.waitForTimeout(4000);
|
|
await page.waitForSelector("div[aria-label='儲存']");
|
|
await page.click("div[aria-label='儲存']");
|
|
await page.waitForTimeout(10000);
|
|
|
|
console.log('OK');// Necessary, RPA success status check
|
|
|
|
await page.close();
|
|
await browser.close();
|
|
|
|
})();
|