ITスキル

python使ってTwitter画面から投稿してみる

2月からツイッターのAPIの利用が有料化されるってことになると、結構痛手なので、急遽画面から投稿するプログラムを作成してみた。

Webサイトの操作には、seleniumライブラリとGoogleDriveのセットアップが必要です。手順はこちらの記事で解説しています。

pythonでWebページの操作をする前に、Chromeのデベロッパーツールの使い方を簡単に説明している記事があるので、こちらをみて頂いてからの方が理解は深まると思います。

なお、記事は独学で学んだ内容を記載していて、最低限の知識がないと理解が進まない可能性もあります。短期間でpythonの基礎を習得する方法はこちらの記事で紹介しているので、参考にしてみてください。

ツイートまでの処理の流れ

ちょっと長いですが、やっているのは、

  1. Twitterにログイン画面へアクセス
  2. ユーザID入力
  3. パスワード入力
  4. 投稿するメッセージ入力(今回は”test”と入力)
  5. ツイートボタンクリック
  6. Twitter画面クローズ

これだけです。皆さんが普段ツイートしている操作をpythonで自動化しているだけです。

pythonコード全体

import requests
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

#ログインユーザとパスワード
USER_NAME="*********"
PASS_WORD="************"

#ChromeDriverの格納パスを指定
driver_path = r"chromedriver"

#Webdriver起動
driver = webdriver.Chrome(driver_path)

##### ツイッターのログイン画面へアクセス#####
driver.get("https://twitter.com/i/flow/login")

#画面表示まで5秒ほど待機
time.sleep(5)

##### ユーザ情報入力 #####
#ユーザ名入力ボックスを探す
TextBox = driver.find_elements(By.TAG_NAME, "input")
for i in range(len(TextBox)):
    box_name=TextBox[i].get_attribute("autocomplete")

    if box_name == "username":
        TextBox[i].send_keys(USER_NAME)
        TextBox[i].send_keys(Keys.ENTER)
        break

time.sleep(5)

##### パスワードの入力 #####
#画面のソース再読み込み
driver.current_url

#パスワード入力のボックスを探す
TextBox = driver.find_elements(By.TAG_NAME, "input")

for i in range(len(TextBox)):
    box_name=TextBox[i].get_attribute("name")

    if box_name == "password":
        TextBox[i].send_keys(PASS_WORD)
        TextBox[i].send_keys(Keys.ENTER)
        break

time.sleep(5)

##### ツイート欄にテキスト入力 #####
#ページ読み直し
driver.current_url

#入力欄検索
InputText=driver.find_element(By.CLASS_NAME,"DraftEditor-editorContainer")
InputText=InputText.find_element(By.TAG_NAME,"span")

#テキスト入力
InputText.send_keys("test")


##### 「ツイートする」ボタンクリック #####
taglist=driver.find_elements(By.TAG_NAME,"div")

for i in range(len(taglist)):
    
    role=taglist[i].get_attribute("role")
    dataid=taglist[i].get_attribute("data-testid")
    if role == "button" and dataid == "tweetButtonInline":
        button=taglist[i].find_element(By.TAG_NAME,"span")
        button=button.find_element(By.TAG_NAME,"span")
        button.click()
        break

##### ブラウザをクローズ #####
driver.quit()

それぞれ個別に解説しますね。

各処理の解説

コードを各処理に分けて解説しています。先頭のライブラリインポートやユーザID、パスワードの設定部は割愛しています。

ログイン画面表示

Twitterのログイン画面へのアクセスです。chromeDriver を使ってアクセスします。driverのget関数にアクセスするURLを渡すことで、デベロッパーモードでブラウザが開きます。

開き切るまで時間がかかると、後続の処理が先走ってしまうので、sleepで時間を稼いでいます。単位は秒で数値を指定します。どの程度sleepするかはPCスペックにもよるので各人での判断になります。

#ChromeDriverの格納パスを指定
driver_path = r"chromedriver"

#Webdriver起動
driver = webdriver.Chrome(driver_path)

##### ツイッターのログイン画面へアクセス#####
driver.get("https://twitter.com/i/flow/login")

#画面表示まで5秒ほど待機
time.sleep(5)

ユーザID入力

ログイン画面にアクセスすると同時にdriverの中にソース情報が格納されます。操作はこのdriverに対して行います。

ユーザID入力のステップは

  1. ユーザID入力用のエディットボックスを探す
  2. 見つけたエディットボックスにユーザIDを入力する
  3. 次へボタンを押してパスワード入力画面に移動する

の3ステップです

##### ユーザ情報入力 #####
#ユーザID入力用のエディットボックスを探す
TextBox = driver.find_elements(By.TAG_NAME, "input")
for i in range(len(TextBox)):
    box_name=TextBox[i].get_attribute("autocomplete")

    if box_name == "username":
        #見つけたエディットボックスにユーザIDを入力する
        TextBox[i].send_keys(USER_NAME)
        #次へボタンを押してパスワード入力画面に移動する
        TextBox[i].send_keys(Keys.ENTER)
        break

ユーザID入力用のエディットボックスを探す

ユーザ情報の入力するエディットボックスは、inputタグなので、driver内をfind_elements(BY.TAG_NAME,"input")で検索します。inputタグは大抵複数あるので、find_elementではなく、find_elementsを使っています。

取得したinputタグはfor文で一つずつ属性をチェックしています。ユーザ情報を入力するinputタグには、autocomplete属性の値がusernameになっている特徴がありそうでしたので、そのinputタグを探しています。

見つけたエディットボックスにユーザIDを入力する

発見したinputタグにユーザIDを入力します。入力はsend_kyesを使用しています。

次へボタンを押してパスワード入力画面に移動する

ユーザIDを入力したらパスワードの入力になります。Twitterのログイン画面はユーザIDとパスワードが別の画面になるので、ユーザIDを入力後「次へ」ボタンをクリックします。

「次へ」ボタンの検索もユーザID入力項目と同じように要素検索しても良いのですが、Enterを押すことが「次へ」ボタンクリックと同じ動作なので、ログイン画面に対してEnterキーの信号を送信することで、「次へ」ボタンのクリックの代用としています。

Enterキーはsend_keys(Keys.ENTER)で実装できます。

for繰り返し分の終了

ユーザIDの入力が完了したので、残りのinputタグのリサーチは不要になります。for文から抜けて次のパスワード入力処理に移ります。for文から抜けるには break を使います。

別のコーディング

今回inputタグの検索で、find_elementsを使って複数のinputタグの調査を行いましたが、画面に1つしかinputタグがない場合や、一つ目のinputタグを探したい場合は、find_elementが使えます。

#ユーザ名入力ボックスを探す
TextBox = driver.find_element(By.TAG_NAME, "input")
TextBox.send_keys(USER_NAME)
TextBox.send_keys(Keys.ENTER)

TwitterのユーザID入力画面は、inputタグが1つしかないので、上記コードでも実装できます。こちらの方がコード数が少なくてシンプルですね。

ログインパスワードの入力

パスワード入力画面に遷移したら、パスワードを入力します。基本的な考え方は、ユーザID入力と同じです。

##### パスワードの入力 #####
#ページの再読み込み
driver.current_url

#パスワード入力のボックスを探す
TextBox = driver.find_elements(By.TAG_NAME, "input")

for i in range(len(TextBox)):
    box_name=TextBox[i].get_attribute("name")

    if box_name == "password":
        #パスワードを入力してログイン
        TextBox[i].send_keys(PASS_WORD)
        TextBox[i].send_keys(Keys.ENTER)
        break

ページの再読み込み

ページの遷移後は、そのページのソースを認識していないので、ページのソースの読み込みを行います。

パスワード入力ボックスを探す

ユーザID同様、inputタグを探します。パスワード入力の画面では、inputタグが2つあったので、どちらのinputタグにパスワードを入力するべきか属性を見て判定が必要になります。

今回は、name属性がpasswordのタグで特定できそうなので、get_attributeでname属性を調べています。

パスワード入力してログインする

inputタグを見つけたらパスワードを入力してログインします。ユーザID入力と同様にsend_keyを使います。

メッセージ入力

ログインに成功すると、ホーム画面に移動します。この画面を読み取ってtestとツイートをしてみます。

デベロッパーツールでタグ検索

ツイートメッセージを入力するボックスのソースをデベロッパーツールで確認します。

タグは<div><span><br> で構成されているところを指していますね。

divタグとclass属性の特定可否確認

divのclass属性を使って位置を拾えるかfind_elementsで拾えるか確認します。0件なので、うまく拾えなさそうです。

Items=driver.find_elements(By.CLASS_NAME,"public-DraftStyleDefault-block public-DraftStyleDefault-ltr")
print(len(Items))
0

では、divタグの属性として、classの値をget_attributeで拾えるかを確認します。

Items=driver.find_elements(By.TAG_NAME,"div")

for Item in Items:
    Attre=Item.get_attribute("class")
    if Attre == "public-DraftStyleDefault-block public-DraftStyleDefault-ltr":
        Item.send_keys("test")
        break

これだと、正しく拾えて、send_keysで”test”を呟くことができています。ただ、これだと、divタグの数だけfor文で繰り返しているので非効率です。

そこで、親階層のclassを拾えるか1階層ずつ上がって確認します

DraftEditor-editorContainer」の所で認識ができました。class=””は無視します。。

Items=driver.find_elements(By.CLASS_NAME,"public-DraftStyleDefault-block public-DraftStyleDefault-ltr")
print(len(Items))

Items=driver.find_elements(By.CLASS_NAME,"notranslate public-DraftEditor-content")
print(len(Items))

Items=driver.find_elements(By.CLASS_NAME,"DraftEditor-editorContainer")
print(len(Items))
0
0
1

テストメッセージ”text”の入力

class属性が「DraftEditor-editorContainer」の所でsend_keyを使って文字列”text”の入力を試みましたが、エラーが発生。この位置からはテキストの入力ができないと言うことっぽいです。

driver.current_url
Item=driver.find_element(By.CLASS_NAME,"DraftEditor-editorContainer")
Item.send_keys("test")
---------------------------------------------------------------------------
ElementNotInteractableException           Traceback (most recent call last)
Input In [59], in <cell line: 16>()
       14 driver.current_url
       15 Item=driver.find_element(By.CLASS_NAME,"DraftEditor-editorContainer")
---> 16 Item.send_keys("test")
:     :    :

と言うことは、入力ができるタグまでターゲットを絞っていく必要があります。現在は、class属性が「DraftEditor-editorContainer」の場所の特定ができている状態です。この子要素に入っていくには、その要素に対してさらにfind_elementを使えば良いです。(divのように複数ある場合はfind_elements)

Item=driver.find_element(By.CLASS_NAME,"DraftEditor-editorContainer")
chItem=Item.find_element(By.TAG_NAME,"XXX")

今回は、子要素にdivがたくさんありますが、最下層には、spanが一つあります。この要素に向けてテキストを送れれば良いので、spanを探します。spanがダメならbrですね

Item=driver.find_element(By.CLASS_NAME,"DraftEditor-editorContainer")
chItem=Item.find_element(By.TAG_NAME,"span")

#Item.send_keys("test")
chItem.send_keys("test")

無事に入力に成功しました。

ちなみに、<br>タグをターゲットにしてテキストを送ってもできますが、複数回実行するとエラーになります。<br>は文字が入力されると属性が変化してしまうようです。

ツイートボタンクリック

最後に「ツイートする」ボタンのクリックです。ログインの時のようにEnterキーでツイートしてくれないので、ボタンを特定してクリックする必要があります。

今回は、role属性が「button」で、data-testidが「tweetButtonInline」のdivタグを探して、その子要素のspanタグに対してクリック操作をしてみます。

クリックは、見つかった要素に対してclick()を実行するだけです。

##### 「ツイートする」ボタンクリック #####
taglist=driver.find_elements(By.TAG_NAME,"div")

for item in taglist:
    atRole=item.get_attribute("role")
    atDataid=item.get_attribute("data-testid")
    if atRole == "button" and atDataid == "tweetButtonInline":
        button=item.find_element(By.TAG_NAME,"span")
        button.click()
        break

ようやくツイートができました。

Twitterクローズ

ツイートを行った後は、再度同じコードで文字の入力をして、ツイートを繰り返すことができます。最終的にツイートが終わったら、クローズをしてブラウザを閉じます。

##### ブラウザをクローズ #####
driver.quit()

まとめ

Twitterにログインしてからメッセージをツイートするところまでのコーディングについて解説しました。

これを一つの関数としてまとめて、実行時にユーザ情報とメッセージを引数で渡すことで、ログインからツイートまでの一連の処理が自動化できます。

TwitterのAPIが有料化されるので、画面から呟く方法を模索した内容を備忘として残しています。

次回は、これを使ってDMMから情報を取得してTwitterに呟くところまでの一連の処理の自動化処理を作ってみます。

おすすめのスクール

今回のコードやseleniumを使った処理は少し難易度が高いかもしれませんが、独学でも習得は可能なレベルです。

ただ、副業やフリーランスエンジニアとして稼ぐことを考えているのであれば、初心者レベルからでも学習ができて、副業やフリーランスエンジニアの独り立ちまでサポートしてくれるテックアカデミーなどのスクールで学ぶのが最短距離です。

いずれは・・・・と言う人は、大抵実現しないまま終わってしまいます。まずは無料体験で自分の考えているキャリアがどれだけ現実的なのかを判断することを強くお勧めします。

テックアカデミー

TechAcademyは、1人ではプログラミング学習が続かない方のための、パーソナルメンターがつく「オンラインブートキャンプ」です。

オンラインブートキャンプの特徴は下記の3つがあります。

  1. スクールに通わなくても、自宅などでオンライン学習できる
  2. わからないことはいつでもチャットでメンターに質問できる
  3. パーソナルメンターがついてオリジナルサービスやオリジナルアプリの公開までサポート

自分のオリジナルサービスやアプリを開発しながらプログラミングを実践的に学んでいただき、 わからないことはいつでも現役エンジニアのメンターに相談することができます。

現在は、6つのコースがありいずれも最短4週間で完結します。

■提供中のコース

  • Webアプリコースコース
  • iPhoneアプリコース
  • Androidアプリコース
  • WordPressコース
  • Webデザインコース
  • アプリUI/UXデザインコース

詳細はこちらをご覧ください。

-ITスキル
-