How I Built a Twitter Auto-Poster Bot using Laravel
Tags: laravel, twitter, automation, dusk
Published: 2020-02-14 07:23:55

In this tutorial, I will demonstrate how I created a twitter-bot for auto-posting on Twitter using the powers of Laravel Zero and Laravel Dusk. 

The Bot is very simple it takes the current weather details for a city from the OpenWeatherMap API, forms a nice tweet out of different variables returned by the API and tweets the weather updates it every hour. 

Here is the twitter account:- 

Let's see how I built it, step by step.

Step 1: Create a new <a href="https://laravel-zero.com/" target="_blank">Laravel Zero</a> Project

Laravel Zero is built out of Laravel and it's a microframework for building console-based applications. Perfect for our requirements.

 
First, download the laravel-zero installer if you don't already have it on your machine 

```sh
composer global require "laravel-zero/installer"
```

Once you have the installer, you can create a new project using it

```sh
laravel-zero new twitterBot
```

Step 2: Install Laravel-Console-Dusk 

The next step is to install the Laravel-Console-Dusk Dependency on the project by running the following command inside the project

```sh
php twitterBot app:install console-dusk
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/53kbsap5q5y7yh1voltu.png)


Step 3: Create a New Console Command

 
Next, we need to generate a new Laravel Zero Console Command, we will be utilizing this Command as an instruction to our Bot to do the job.

```sh
php twitterBot make:command postTweet
```


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w38k7of8bp2135unjbdt.png)

Here is the code that I wrote for getting current weather updates from OpenWeatherMap API and posting it on twitter. 


```php
<?php

namespace App\Commands;

use Carbon\Carbon;
use Illuminate\Support\Str;
use Illuminate\Console\Scheduling\Schedule;
use LaravelZero\Framework\Commands\Command;

class PostTweet extends Command
{
    /**
     * The signature of the command.
     *
     * @var string
     */
    protected $signature = 'post:tweet';

    /**
     * The description of the command.
     *
     * @var string
     */
    protected $description = 'This commands posts new tweet on Twitter Timeline';

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $weather_tweet = $this->getTweetText();

        $this->postTweetOnTwitter($weather_tweet);
    }


    /**
     * This function gets current weather info and returns string 
     * 
     * @return string
     */
    public function getTweetText(){
        $client = new \GuzzleHttp\Client();
        $request = $client->get('https://api.openweathermap.org/data/2.5/weather?id=1262180&units=metric&appid=6c743793a5539486877ce02335831dc3');
        $response = $request->getBody();

        //Weather Data
        $data = json_decode($response);


        //Tweet String
        $weather_tweet = "Current Temperature ".$data->main->temp."°С , \nwind ".$data->wind->speed." m/s. clouds ".$data->clouds->all." %,\nat ".Carbon::now('Asia/Kolkata')->toDateTimeString()." \n#Nagpur #NagpurWeather ";

        return $weather_tweet;
    }

    /** 
     * Post tweet on twitter using Dusk
     * 
     */
    public function postTweetOnTwitter($tweet){
        $this->browse(function ($browser) use($tweet)  {

            $browser->visit('https://twitter.com/login')
                    ->pause(4000);


            $browser->type('session[username_or_email]', env('twitter_username'))
                    ->type('session[password]', env('twitter_password'))
                    ->pause(1000)
                    ->click('div[role="button"]')
                    ->pause(4000);

                if($browser->element('#challenge_response') != null){
                        $browser->value('#challenge_response', env('challenge_response'))
                                ->click('#email_challenge_submit')
                                ->pause(3000);
                }

                //Post Tweet
                $browser->assertSee('Home')
                    ->pause(2000)
                    ->visit('https://twitter.com/compose/tweet')
                    ->pause(3000)
                    ->click('.public-DraftStyleDefault-block')
                    ->keys(".public-DraftStyleDefault-block", $tweet)
                    ->pause(4000)
                    ->click('div[data-testid="tweetButton"]')
                    ->pause(3000);
         
        });
    }

    /**
     * Define the command's schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule $schedule
     * @return void
     */
    public function schedule(Schedule $schedule): void
    {
        $schedule->command(static::class)->everyThirtyMinutes();
    }
}
```

The handle() will get invoked on running the following command


```sh
php twitterBot post:tweet
```

handle() method is doing two jobs.

1. getTweetText(): This method makes a call to OpenWeatherMap API via Guzzle and forms a tweet from the different variables returned by the API.

2. postTweetOnTwitter(): This method makes use of Dusk to open the browser, login into twitter and post the latest weather update.

That's All.


In the schedule method, we have scheduled the command to run for every thirty minutes. 

Step 4: Deploy on Server and Configure Cron


As the final part of creating this bot, we want to run this code automatically. The project is deployed on a DigitalOcean Droplet and the following command is added to the list of cron jobs.


```sh
* * * * * php /home/twitterBot/twitterbot schedule:run >> /dev/null 2>&1
```

Here is the working video of the Bot.

{% vimeo 391426116 %}