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.

186 lines
5.5 KiB

  1. const puppeteer = require('puppeteer');
  2. const fs = require('fs').promises;
  3. const FACEBOOK_URL = '<%POSTURL%>';
  4. const isLoggedIn = async (page) => {
  5. const current_url_cookies = await page.cookies();
  6. if(current_url_cookies.filter(x=>x.name == 'c_user').length == 0){
  7. throw 'Not Login';
  8. }
  9. };
  10. const loginWithSession = async (cookies, page) => {
  11. await page.setCookie(...cookies);
  12. await page.goto(FACEBOOK_URL, { waitUntil: 'networkidle2' });
  13. await isLoggedIn(page).catch((error) => {
  14. throw error;
  15. });
  16. }
  17. const loginWithCredentials = async (username, password, page) => {
  18. //console.log('Logging into Facebook using credentials for', username);
  19. await page.goto(FACEBOOK_URL, {
  20. waitUntil: 'networkidle2',
  21. });
  22. await page.waitForSelector('input[name=email]');
  23. await page.click('input[name=email]');
  24. await page.type('input[name=email]', username);
  25. await page.waitForSelector('input[name=pass]');
  26. await page.click('input[name=pass]');
  27. await page.type('input[name=pass]', password);
  28. const cookieBanner = 'div[data-testid="cookie-policy-banner"]';
  29. if (await page.$(cookieBanner) !== null) {
  30. //console.log('Facebook cookie banner found');
  31. await page.evaluate((selector) => {
  32. const elements = document.querySelectorAll(selector);
  33. for (let i = 0; i < elements.length; i += 1) {
  34. elements[i].parentNode.removeChild(elements[i]);
  35. }
  36. }, cookieBanner);
  37. }
  38. await page.waitForSelector("div[aria-label='Accessible login button']");
  39. await page.click("div[aria-label='Accessible login button']");
  40. await page.waitForNavigation();
  41. await isLoggedIn(page).catch((error) => {
  42. console.error('App is not logged into Facebook');
  43. throw error;
  44. });
  45. }
  46. const getDefaultBrowser = async (headless) => {
  47. const browser = await puppeteer.launch({
  48. headless: false,
  49. devtools: false,
  50. args: ['--no-sandbox', '--disable-setuid-sandbox',"--disable-notifications"],
  51. });
  52. const context = browser.defaultBrowserContext();
  53. context.overridePermissions(FACEBOOK_URL, []);
  54. return browser;
  55. };
  56. const getDefaultPage = async (browser) => {
  57. const page = await browser.newPage();
  58. await page.setViewport({ width: 1920, height: 1000 });
  59. return page;
  60. };
  61. (async () => {
  62. const browser = await getDefaultBrowser(true);
  63. const page = await getDefaultPage(browser);
  64. const username = '<%ACCOUNT%>';
  65. const password = '<%ENTERCODE%>';
  66. // Load cookies from previous session
  67. const cookies = await fs.readFile('cookies.js')
  68. .then((facebookCookies) => JSON.parse(facebookCookies))
  69. .catch((error) => {
  70. console.error(`Unable to load FB cookies file: ${error}`);
  71. return {};
  72. });
  73. // use for debug
  74. //await page.cookies().then(async (freshCookies) => {
  75. //console.log(JSON.stringify(freshCookies, null, 2));
  76. //});
  77. // Use our cookies to login. If it fails fallback to username and password login.
  78. if (cookies && Object.keys(cookies).length) {
  79. await loginWithSession(cookies, page).catch(async (error) => {
  80. console.error(`Unable to login using session: ${error}`);
  81. await loginWithCredentials(username, password, page);
  82. });
  83. } else {
  84. await loginWithCredentials(username, password, page);
  85. }
  86. // Save our freshest cookies that contain our Facebook session
  87. await page.cookies().then( async(freshCookies) => {
  88. await fs.writeFile('cookies.js', JSON.stringify(freshCookies, null, 2)).catch(async (error)=>{
  89. await fs.access('cookies.js', fs.F_OK);
  90. await fs.writeFile('cookies.js', JSON.stringify(freshCookies, null, 2));
  91. });
  92. });
  93. await page.waitForSelector("div[aria-label='可對此貼文採取的動作']");
  94. await page.click("div[aria-label='可對此貼文採取的動作']");
  95. await page.waitForXPath('//span[contains(text(), "編輯貼文")]'); //
  96. const linkEx = await page.$x('//span[contains(text(), "編輯貼文")]');
  97. if (linkEx.length > 0) {
  98. await linkEx[0].click();
  99. }
  100. await page.waitForSelector("div[aria-label='移除貼文附件']");
  101. await page.click("div[aria-label='移除貼文附件']");
  102. await page.waitForSelector("div[aria-label='相片/影片']");
  103. //await page.click("div[aria-label='相片/影片']");
  104. try{
  105. const [fileChooser] = await Promise.all([
  106. page.waitForFileChooser(),
  107. page.click("div[aria-label='相片/影片']")
  108. ]);
  109. await fileChooser.cancel() ;
  110. }
  111. catch(e)
  112. {
  113. console.error(`Unable Get Dialog: ${e}`);
  114. }
  115. // get the ElementHandle of the selector above
  116. // aria-label="附加相片或影片"
  117. //const inputUploadHandles = await page.$x("//input[contains(@accept,'video')]");
  118. // const inputUploadHandle = inputUploadHandles[0];
  119. await page.waitForXPath('//input[@multiple]');
  120. await page.waitForTimeout(2000);
  121. var inputUploadHandles = await page.$x('//input[@multiple]');
  122. var inputUploadHandle = inputUploadHandles[0];
  123. // prepare file to upload, I'm using test_to_upload.jpg file on same directory as this script
  124. // Photo by Ave Calvar Martinez from Pexels https://www.pexels.com/photo/lighthouse-3361704/
  125. const files = await Promise.all(<%UPLOAD_MEDIA_JSONARRAY%>);
  126. // Sets the value of the file input to fileToUpload
  127. await inputUploadHandle.uploadFile(...files);
  128. await inputUploadHandle.evaluate(upload => upload.dispatchEvent(new Event('change')));
  129. await page.waitForTimeout(4000);
  130. await page.waitForSelector("div[aria-label='儲存']");
  131. await page.click("div[aria-label='儲存']");
  132. await page.waitForTimeout(10000);
  133. console.log('OK');// Necessary, RPA success status check
  134. await page.close();
  135. await browser.close();
  136. })();