├── LICENSE ├── index.js └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Tomasz Baranowicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | const puppeteer = require('puppeteer'); 3 | const username = 'xxxxx' 4 | const password = 'xxxxx' 5 | 6 | let browser = null; 7 | let page = null; 8 | 9 | (async () => { 10 | browser = await puppeteer.launch({ headless: false }); 11 | 12 | page = await browser.newPage(); 13 | page.setViewport({ 14 | width: 1280, 15 | height: 800, 16 | isMobile: false 17 | }); 18 | 19 | await page.goto('https://twitter.com/login', {waitUntil: 'networkidle2'}); 20 | 21 | //LOGIN 22 | await page.type('input[name="session[username_or_email]"]',username,{delay: 25}); 23 | await page.type('input[name="session[password]"]',password,{delay: 25}); 24 | await page.click('div[data-testid="LoginForm_Login_Button"]'); 25 | 26 | //SEARCH TERM 27 | await page.waitFor('input[data-testid="SearchBox_Search_Input"]'); 28 | await page.type('input[data-testid="SearchBox_Search_Input"]', '#tesla', {delay:25}); 29 | await page.keyboard.press('Enter'); 30 | await page.waitFor(2000) 31 | 32 | //SCROLL DOWN + GET AUTHORS 33 | let authorsSet = new Set() 34 | try { 35 | let previousHeight; 36 | for (let i = 0; i < 10; i++) { 37 | const elementHandles = await page.$$('a.css-4rbku5.css-18t94o4.css-1dbjc4n.r-sdzlij.r-1loqt21.r-1adg3ll.r-ahm1il.r-1udh08x.r-o7ynqc.r-6416eg.r-13qz1uu'); 38 | const propertyJsHandles = await Promise.all( 39 | elementHandles.map(handle => handle.getProperty('href')) 40 | ); 41 | const urls = await Promise.all( 42 | propertyJsHandles.map(handle => handle.jsonValue()) 43 | ); 44 | 45 | urls.forEach(item => authorsSet.add(item)) 46 | 47 | previousHeight = await page.evaluate('document.body.scrollHeight'); 48 | await page.evaluate('window.scrollTo(0, document.body.scrollHeight)'); 49 | await page.waitForFunction(`document.body.scrollHeight > ${previousHeight}`); 50 | await page.waitFor(2000); 51 | } 52 | } catch(e) {console.log(e); } 53 | 54 | console.log("-----") 55 | console.log(authorsSet); 56 | 57 | // VISIT ALL AUTHORS AND CLICK FOLLOW BUTTON 58 | const urls = Array.from(authorsSet) 59 | for (let i = 0; i < urls.length; i++) { 60 | try { 61 | const url = urls[i]; 62 | console.log(url); 63 | await page.goto(`${url}`); 64 | 65 | await page.waitFor(2000) 66 | await page.click('div[class="css-18t94o4 css-1dbjc4n r-1niwhzg r-p1n3y5 r-sdzlij r-1phboty r-rs99b7 r-1w2pmg r-1vuscfd r-1dhvaqw r-1fneopy r-o7ynqc r-6416eg r-lrvibr"]') 67 | await page.waitFor(2000) 68 | await page.goBack(); 69 | } 70 | catch(error) { 71 | console.error(error); 72 | } 73 | } 74 | })(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twitter-bot", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Tom Baranowicz", 10 | "license": "ISC", 11 | "dependencies": { 12 | "puppeteer": "^3.0.0" 13 | } 14 | } 15 | --------------------------------------------------------------------------------