Как создать автоматизацию твитов с помощью скрипта Google Apps из Google Sheet

Вы подписались на какого-нибудь крутого создателя или разработчика в Твиттере, у которого много подписчиков. Вы хотите пойти по их пути, став также творцом. Одна из самых важных вещей, которые вы должны делать, — это постоянно создавать контент для вашего подписчика и будущего подписчика, чтобы они считали ваш аккаунт достойным подписки.

Затем вы замечаете, что не так просто постоянно твитить каждый день, может быть день, когда вы слишком заняты или просто ленитесь открывать свою учетную запись. Тогда вам интересно, как люди, на которых вы подписаны, продолжают публиковать сообщения целыми днями без остановки?

Ответ — автоматизация

Большинство из них автоматизируют свой твит, ретвитнув старый твит или подготовив шаблон, в котором твит будет автоматически создан в зависимости от установленного времени. Существует множество программ для автоматизации Twitter. Я лично использовал Zapier для автоматизации своих ежедневных твитов, пока моя бесплатная учетная запись не была остановлена. Но я считаю, что вы можете найти другие инструменты, предоставляющие ту же услугу.

но эй, вы программист, вы можете написать код, который может это сделать, верно?

Что ж, именно это я и сделал, и в этой статье я поделюсь с вами тем, как я пишу автоматизацию твитов с помощью Google Apps Script и Google Sheet. Я создал шаблон твита и треда, и скрипт автоматически создаст твит или тред на основе шаблона, который я поместил в Google Sheet.

Мы рассмотрим шаг за шагом, как это сделать. это сэкономит вам более 100 часов исследований, просто следуя этому руководству.

Создать учетную запись разработчика в Твиттере

Первый шаг — создать учетную запись разработчика Twitter. Для этого вам необходимо перейти на портал разработчиков Twitter по адресу https://developer.twitter.com и зарегистрироваться, чтобы получить доступ к Twitter API.

После того, как вы зарегистрируетесь, заполнив всю информацию, вы можете перейти на портал Панель управления, чтобы начать создание нового проекта.

Создать новый проект в Твиттере

Твиттер управляет доступом к API с точки зрения проектов и приложений. В общем, проекты позволяют вам организовать свою работу в зависимости от того, как вы собираетесь использовать Twitter API, чтобы вы могли эффективно управлять своим доступом к API и отслеживать его использование. Каждый проект может содержать одно или несколько приложений в зависимости от вашего уровня доступа.

В этом руководстве мы создадим новую автоматизацию вызовов проекта, выполнив следующие действия.

  1. Нажмите «Создать проект».

2. Назовите свой проект, подойдет любое имя. Нажмите "Далее

3. Выберите вариант использования. Подходит любой вариант использования. Нажмите "Далее

4. Опишите проект. Нажмите "Далее

5. Настройте имя приложения. Нажмите "Далее

6. В разделе «Ключи и токены» скопируйте ключи и токены API на свой локальный компьютер. Просто отметим, что мы не будем использовать ключи и токены на этой странице, потому что они предназначены для OAuth1, позже мы создадим новые для OAuth2.

После просмотра всей этой информации вы увидите эту страницу, если вы нажмете «Настройки приложения».

Мы остановимся здесь, но вернемся позже на этой странице.

Создать Google Таблицу

Создайте любую таблицу Google. мы организуем твиты в каждой строке, и для каждой строки у нас может быть несколько твитов, которые позже можно будет создать как ветку твиттера. См. пример ниже

Как видите, в первой строке у нас есть только один шаблон твита — «Первый твит» в ячейке A1. Позже скрипт опубликует один твит из этого шаблона. Вторая строка содержит два твита в ячейках A2 и B2. Эти два шаблона твитов будут созданы как ветка Twitter, где пользователь нажмет кнопку «Дополнительно», чтобы увидеть больше ответа. Это поможет увеличить вашу вовлеченность.

Идея заключается в том, что скрипт будет перебирать каждую строку в течение определенного времени и твитить все шаблоны в строке. Например, вы хотите создавать твит каждые 8 ​​часов, тогда в первый час он будет твитить строку 1, а следующие 8 часов — вторую строку. Если текущая строка не содержит твитов, то скрипт просто сбросит счетчик и вернется к первой строке

При этом после запуска скрипта все, что вам нужно сделать, это добавить больше шаблонов в лист Google, а скрипт позаботится обо всем остальном.

Создать скрипт Google Apps

На листе Google создайте скрипт приложений, нажав в меню Расширения → Сценарий приложений. Новая страница будет показана, как показано ниже

Вы можете назвать проект любым именем. На данный момент я назову свою как Twitter Automation. Здесь мы будем писать наш код.

Каждый скрипт Google Apps содержит идентификатор как идентификацию скрипта или проекта. Нам понадобится идентификатор нашего скрипта приложений для следующего шага, поэтому давайте возьмем его сейчас.

На странице Apps Script перейдите к настройкам проекта (значок шестеренки слева). Страница ниже будет показана, и вы можете увидеть свой идентификатор сценария, как мой.

Настройка потока OAuth2 в Twitter

Мы почти готовы писать код. Но перед этим нам нужно настроить OAuth2 в наших твиттер-приложениях. Вернитесь на портал разработчика Twitter и перейдите в настройки приложения.

Если вы прокрутите немного вниз, вы увидите раздел настроек аутентификации пользователя. нажмите кнопку Настроить, и вам будет показана страница, где вам нужно указать некоторую информацию.

На этой странице нам нужно ввести три важные данные:

(1) первый — это Тип приложения, то есть просто выбор между Нативным приложением или Веб-приложением, автоматическим приложением или ботом. Мы можем выбрать второй, так как он больше подходит для нашего сценария.

(2) Второй — это URI обратного вызова, это URI, на который будет перенаправлена ​​учетная запись Twitter, которая будет нашей личной учетной записью, после процесса предоставления разрешения. Здесь будет использоваться ваш идентификатор сценария Google Apps из предыдущего раздела. URI, который мы введем, находится ниже

https://script.google.com/macros/d/YOUR_SCRIPT_ID/usercallback.

вы можете заменить YOUR_SCRIPT_ID идентификатором вашего скрипта

(3) Третий — это URL-адрес веб-сайта, то есть любой веб-сайт для Приложения. вы можете дать свой личный сайт.

После того, как вы отправите эти три информации, вы можете нажать кнопку «Далее», и вам будет показана страница ниже, содержащая две информации: идентификатор клиента и секрет клиента. Эти две секретные данные потребуются для вашего сценария, и вы сможете безопасно сохранить их позже в своем сценарии приложений. А пока просто скопируйте их оба на свой локальный компьютер.

Установка библиотеки OAuth2 в сценарии приложений

Теперь мы готовы написать код, но перед этим мы установим библиотеку OAuth2 в наш скрипт приложения. Установка библиотеки в Apps Script в первый раз немного сложна. Но вам нужно получить идентификатор сценария библиотеки. После этого вы нажимаете кнопку Библиотеки в редакторе сценариев приложений и вставляете идентификатор библиотеки, нажимаете Поиск и нажимаете Добавить. Для библиотеки OAuth2 идентификатор сценария — 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF.

Если библиотека успешно добавлена, вы увидите OAuth2 в разделе библиотеки.

Начать писать код

есть три основные функции, которые нам нужно создать

  1. Функция для извлечения шаблона твита из листа
  2. Функция для создания службы OAuth2
  3. Функция для отправки твита в учетную запись Twitter

Также необходимо добавить другие необходимые функции, мы рассмотрим их позже в подразделе ниже, чтобы помочь вам понять каждую часть кода.

Получить шаблон твита из Google Sheet

Вот код для захвата шаблона твита из листа Google.

/**
 * Fetch the tweet from the google sheet
 * @param row row of the sheet, start from 1
 * @param col column of the sheet, start from 1
 * @return text of the tweet
 */
function fetchTweet(row,col){
  const sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  const tweetSheet = sheets.find((sheet)=>sheet.getName() == 'Sheet1');
  return tweetSheet.getRange(row,col).getValue().toString();
}

Служба OAuth2

Следующая часть — это код для создания службы OAuth.

/**
 * Create the OAuth2 Twitter Service
 * @return OAuth2 service
 */
function getService(){
  var userProps = PropertiesService.getUserProperties();
  pkceChallengeVerifier();
  return OAuth2.createService('twitter')
        .setAuthorizationBaseUrl('https://twitter.com/i/oauth2/authorize')
        .setTokenUrl('https://api.twitter.com/2/oauth2/token?code_verifier=' + userProps.getProperty("code_verifier"))
// Set the client ID and secret.
        .setClientId(CLIENT_ID)
        .setClientSecret(CLIENT_SECRET)
        .setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
        .setPropertyStore(userProps)
        // Set the scopes to request (space-separated for Twitter services).
        .setScope('users.read tweet.read offline.access tweet.write')
  
        // Add parameters in the authorization url
        .setParam('response_type', 'code')
        .setParam('code_challenge_method', 'S256')
        .setParam('code_challenge', userProps.getProperty("code_challenge"))
.setTokenHeaders({
          'Authorization': 'Basic ' + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET),
          'Content-Type': 'application/x-www-form-urlencoded'
        })
}

для функции getService() требуются 2 функции: pkceChallengerVerifier() для создания запроса и проверки разрешения сценария на доступ к учетной записи Twitter и authCallback() в качестве обратного вызова из Twitter после того, как учетная запись предоставит доступ к нашему сценарию. getService() также нужны две константы CLIENT_ID и CLIENT_SECRET, которые представляют собой две информации, которые мы получили из настроек приложения Twitter в предыдущем разделе.

Еще одна важная часть — область применения OAuth2. Чтобы отправить твит через учетную запись Twitter, нам нужно установить область действия OAuth2 с помощью user.read tweet.read tweet.write. Если вы заметили, я также добавил offline.access , эта область необходима, так что нам нужно сделать только один раз процесс предоставления доступа.

Здесь содержание pkceChallengerVerifier()

/**
 * Generate PKCE Challenge Verifier for Permission for OAuth2 Twitter Service
 */
function pkceChallengeVerifier(){
  var userProps = PropertiesService.getUserProperties();
  if(!userProps.getProperty('code_verifier')){
    var verifier = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
    for(var i =0;i<128 ;i++){
      verifier += possible.charAt(Math.floor(Math.random() * possible.length));
    }
var sha256hash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, verifier);
var challenge = Utilities.base64Encode(sha256hash)
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '')
userProps.setProperty("code_verifier", verifier)
    userProps.setProperty("code_challenge", challenge)
  }
}

Вот содержание для authCallback()

/**
 * Handles the OAuth callback.
 */
function authCallback(request) {
  var service = getService();
  var authorized = service.handleCallback(request);
  if (authorized) {
    return HtmlService.createHtmlOutput('Success!');
  } else {
    return HtmlService.createHtmlOutput('Denied');
  }
}

дополнительная функция reset() также важна, если вы хотите изменить объем услуги. Вам необходимо сбросить службу, прежде чем запрашивать новую область

/**
 * Reset the OAuth2 Twitter Service
 */
function reset() {
  getService().reset();
PropertiesService.getUserProperties().deleteProperty("code_challenge");
PropertiesService.getUserProperties().deleteProperty("code_verifier");
}

Отправить шаблон твита в twitter API

Вот функция sendTweet

/**
 * Send the Tweet
 * @Param tweet Text to tweet
 * @Param replyTo id of the tweet to reply
 * @return the ID of the current Tweet
 */
function sendTweet(tweet,replyTo){
  var payload = {
    text:tweet
  }
if(replyTo){
    payload['reply'] = {
      in_reply_to_tweet_id:replyTo
    }
  }
  var service = getService();
   if (service.hasAccess()) {
    var url = `https://api.twitter.com/2/tweets`;
    var response = UrlFetchApp.fetch(url, {
      method:'POST',
      'contentType': 'application/json',
      headers: {
        Authorization: 'Bearer ' + service.getAccessToken()
      },
      muteHttpExceptions: true,
      payload: JSON.stringify(payload)
    });
    var result = JSON.parse(response.getContentText());
    return result.data.id;
  } else {
    var authorizationUrl = service.getAuthorizationUrl();
    Logger.log('Open the following URL and re-run the script: %s',
      authorizationUrl);
  }
}

Эта функция отправит запрос HTTP POST в Twitter API Library для публикации твита в учетной записи Twitter. Сначала он проверит, есть ли у службы доступ, и распечатает URL-адрес авторизации, если доступа нет.

Основная функция

со всем готовым основным функционалом мы можем создать основную функцию, которая будет управлять логикой нашей автоматизации. Идея состоит в том, чтобы иметь глобальный счетчик, который будет проходить через строку каждый раз, когда скрипт публикует твит, и увеличивать счетчик для следующего раунда. вот основная функция

/**
 * Entry point to send the tweet
 */
function dailyTweet(){
  //get the counter, which is to be row
  var counter = PropertiesService.getUserProperties().getProperty('counter')
  if(!counter) {
    counter = 1
  }
  else{
    //parse to Integer because it's stored as string
    counter = parseInt(counter)
  }
var row = counter;
  var col = 1;
//get the first tweet
  var tweet = fetchTweet(row,col);
  var replyTo = undefined
  //loop while tweet is available, it could be thread
  while(tweet != ""){
    replyTo = sendTweet(tweet,replyTo);
    Logger.log(`tweet '${tweet} has been send with ID ${replyTo}'`);
    tweet = fetchTweet(row,++col);
  }
if(!replyTo && tweet == ""){
    //meaning no tweet, reset the counter
    counter = 0;
    Logger.log("No tweet, counter is reset");
  }
  //increament the counter and save it
  counter ++;
  PropertiesService.getUserProperties().setProperty('counter',counter);
  
}

Полный код

const CLIENT_ID = ''
const CLIENT_SECRET = ''
/**
 * Create the OAuth2 Twitter Service
 * @return OAuth2 service
 */
function getService(){
  var userProps = PropertiesService.getUserProperties();
  pkceChallengeVerifier();
  return OAuth2.createService('twitter')
        .setAuthorizationBaseUrl('https://twitter.com/i/oauth2/authorize')
        .setTokenUrl('https://api.twitter.com/2/oauth2/token?code_verifier=' + userProps.getProperty("code_verifier"))
// Set the client ID and secret.
        .setClientId(CLIENT_ID)
        .setClientSecret(CLIENT_SECRET)
        .setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
        .setPropertyStore(userProps)
        // Set the scopes to request (space-separated for Twitter services).
        .setScope('users.read tweet.read offline.access tweet.write')
  
        // Add parameters in the authorization url
        .setParam('response_type', 'code')
        .setParam('code_challenge_method', 'S256')
        .setParam('code_challenge', userProps.getProperty("code_challenge"))
.setTokenHeaders({
          'Authorization': 'Basic ' + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET),
          'Content-Type': 'application/x-www-form-urlencoded'
        })
}
/**
 * Reset the OAuth2 Twitter Service
 */
function reset() {
  getService().reset();
  PropertiesService.getUserProperties().deleteProperty("code_challenge");
  PropertiesService.getUserProperties().deleteProperty("code_verifier");
}
/**
 * Generate PKCE Challenge Verifier for Permission for OAuth2 Twitter Service
 */
function pkceChallengeVerifier(){
  var userProps = PropertiesService.getUserProperties();
  if(!userProps.getProperty('code_verifier')){
    var verifier = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
    for(var i =0;i<128 ;i++){
      verifier += possible.charAt(Math.floor(Math.random() * possible.length));
    }
var sha256hash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, verifier);
var challenge = Utilities.base64Encode(sha256hash)
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '')
userProps.setProperty("code_verifier", verifier)
    userProps.setProperty("code_challenge", challenge)
  }
}
/**
 * Handles the OAuth callback.
 */
function authCallback(request) {
  var service = getService();
  var authorized = service.handleCallback(request);
  if (authorized) {
    return HtmlService.createHtmlOutput('Success!');
  } else {
    return HtmlService.createHtmlOutput('Denied');
  }
}
/**
 * Send the Tweet
 * @Param tweet Text to tweet
 * @Param replyTo id of the tweet to reply
 * @return the ID of the current Tweet
 */
function sendTweet(tweet,replyTo){
  var payload = {
    text:tweet
  }
if(replyTo){
    payload['reply'] = {
      in_reply_to_tweet_id:replyTo
    }
  }
var service = getService();
   if (service.hasAccess()) {
    // https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-by-username-username
    var url = `https://api.twitter.com/2/tweets`;
    var response = UrlFetchApp.fetch(url, {
      method:'POST',
      'contentType': 'application/json',
      headers: {
        Authorization: 'Bearer ' + service.getAccessToken()
      },
      muteHttpExceptions: true,
      payload: JSON.stringify(payload)
    });
    var result = JSON.parse(response.getContentText());
    return result.data.id;
  } else {
    var authorizationUrl = service.getAuthorizationUrl();
    Logger.log('Open the following URL and re-run the script: %s',
      authorizationUrl);
  }
}
/**
 * Entry point to send the tweet
 */
function dailyTweet(){
  //get the counter, which is to be row
  var counter = PropertiesService.getUserProperties().getProperty('counter')
  if(!counter) {
    counter = 1
  }
  else{
    //parse to Integer because it's stored as string
    counter = parseInt(counter)
  }
var row = counter;
  var col = 1;
//get the first tweet
  var tweet = fetchTweet(row,col);
  var replyTo = undefined
  //loop while tweet is available, it could be thread
  while(tweet != ""){
    replyTo = sendTweet(tweet,replyTo);
    Logger.log(`tweet '${tweet} has been send with ID ${replyTo}'`);
    tweet = fetchTweet(row,++col);
  }
if(!replyTo && tweet == ""){
    //meaning no tweet, reset the counter
    counter = 0;
    Logger.log("No tweet, counter is reset");
  }
  //increament the counter and save it
  counter ++;
  PropertiesService.getUserProperties().setProperty('counter',counter);
  
}
/**
 * Fetch the tweet from the google sheet
 * @param row row of the sheet, start from 1
 * @param col column of the sheet, start from 1
 * @return text of the tweet
 */
function fetchTweet(row,col){
  const sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  const tweetSheet = sheets.find((sheet)=>sheet.getName() == 'tweet');
  return tweetSheet.getRange(row,col).getValue().toString();
}

Тестирование скрипта

Важно убедиться, что наш скрипт действительно работает. Как только вы напишете весь код, вы можете сохранить проект. При сохранении проекта список функций доступен на панели инструментов редактора вместе с кнопкой Выполнить. Попробуйте запустить dailyTweet() и посмотреть, действительно ли твит опубликован в вашем аккаунте

может быть несколько запросов на доступ от скрипта к вашей учетной записи google для доступа к листу google, вы можете просто предоставить разрешение, чтобы ваш скрипт мог работать идеально

Создание триггера

После того, как мы убедились, что dailyTweet() работает, пришло время решить, когда запускать эту функцию. Мы можем использовать функцию триггера скрипта приложений. Перейдите на левую сторону и нажмите меню Триггер.

нажмите Добавить триггер в левом нижнем углу, и вам будет показано диалоговое окно для выбора способа запуска функции dailyTweet. Вы должны выбрать Time-driven в Select источнике события, а остальное решать вам.

Заключение

Создание автоматизированного сценария твита — один из способов повысить вашу учетную запись в Твиттере. Теперь, когда у вас запущен скрипт, вы можете добавить любой шаблон в Google Sheet в любое время, и пусть скрипт сделает все остальное.

если у вас есть какие-либо вопросы или вы думаете, что есть что добавить к этой статье, дайте мне знать в разделе комментариев

не забудьте подписаться на меня в твиттере @asyarif_