質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Twitter

Twitterは、140文字以内の「ツイート」と呼ばれる短文を投稿できるサービスです。Twitter上のほぼ全ての機能に対応するAPIが存在し、その関連サービスが多く公開されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

1回答

2289閲覧

sPythonからJSONファイルで画像付きツイートを自動化する方法

unity_level1

総合スコア8

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Twitter

Twitterは、140文字以内の「ツイート」と呼ばれる短文を投稿できるサービスです。Twitter上のほぼ全ての機能に対応するAPIが存在し、その関連サービスが多く公開されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2020/11/18 07:20

編集2020/11/19 02:56

PythonでJSONに記載した内容をTwitterに投稿するための処理を記載したのですが、下記のようなエラーが発生してしまい
上手く実行が行えない状況です。

当方プログラム初心者のため、Python、JSONの理解が及んでいないです。(本プログラムも理解できていない部分が結構あります)
お手数ですが、お分かりになる方がおりましたら、ご教示いただけますと幸いです。

追記(2020/11/18):
追加でエラーが発生してしまったため、そちらも合わせてご教示いただけますと非常に助かります。
お手数ですがよろしくお願いいたします。

追記2(2020/11/19):
確認したい内容とご教示いただきましたスクリプトをスクリプト内に追記させていただきましたので、お手数ですが、
ご教示いただけますと幸いです。
※ご教示いただきましたスクリプトはそのまま記載しました。convert_url(url)のurlをJSONで定義したimg_urlやファイルのパスを直書きしたり試したのですが、
Image upload failedを解消することができませんでした。

実行環境

■Google Colaboratory
■JSON -ここにツイート内容、画像を定義
■Python -JSONを使用して、Tweetする処理

※JSON、Pythonファイル共にGoogle Colaboratory内で記述しており、Googleドライブをマウントなどはしてません。

JSON内容

JSONファイル名:tweetcontent.json
ファイルパス:/content/sample_data/tweetcontent.json

JSON内容 ※ファイルパスはドライブのファイルパスになるため、対象ファイルのURLと記載させていただきます

{ "contents":[ { "img_url":"対象ファイルのURL", "tweet_text":"画像名" }, { "img_url":"対象ファイルのURL", "tweet_text":"画像名" }, { "img_url":"対象ファイルのURL", "tweet_text":"画像名" }, { "img_url":"対象ファイルのURL", "tweet_text":"画像名" } ] }

Python内容

Pythonファイル名:TwitterBot.ipynb ※Colaboratory内のため、.pyではありません

import json from requests_oauthlib import OAuth1Session #urlを使用するためのモジュール import urllib.request import re       # <-------追加 #下記TwitterのAPIキー、アクセスキーのため記載しておりません CONSUMER_KEY = '****************************' CONSUMER_SECRET = '****************************' ACCESS_TOKEN = '****************************' ACCESS_TOKEN_SECRET = '****************************' #Twitterアクセスキーを変数へ格納 twitter = OAuth1Session(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET) # url変換に使用する正規表現 pattern = re.compile(r".*/file/./(.*)/.*") # <-------追加 #メディアアップロードに使用するURL url_media = "https://upload.twitter.com/1.1/media/upload.json" #テキストアップロードに使用するURL url_text = "https://api.twitter.com/1.1/statuses/update.json" # Googleドライブ上のリンクを、twitter API等で直接取得できるurlに変換する関数 <-------追加 def convert_url(url): a = re.search(pattern, url) try: return "https://drive.google.com/uc?export=view&id=%s" % a.group(1) except (AttributeError, IndexError) as e: # パターンマッチしない場合はメッセージを出して、渡されたurlをそのまま返す。 print("[%s]はパターンにマッチしないため、そのまま返します。" % url) return url #jsonファイルからツイート本文と画像urlを取得 def get_tweet_content(json_file_path): #テキストファイルを読み込む file = open(json_file_path, 'r', encoding='utf-8') #開いたファイルをjson.load関数でJSONとして読み込む json_data = json.load(file) #JSONとして読み込んだfile変数が格納されたjson_data変数に、jsonデータを格納 #random.choice()でリストからランダムに要素を一つ取得 return random.choice(json_data["contents"]) #画像をTwitterにアップロードし、media_idをリターン #img_urlはJSONで指定した画像オブジェクト def upload__media(img_url): #urlをオープンする res = unllib.request.urlopen(img_url) img_data = res.read() img_files = {'media': img_data} res_media = twitter.post(url_media, files=img_files) if res_media.status_code == 200: return json.loads(res_media.text)['media_id'] else: print('Image upload failed: %s', res_media.text) exit() #ツイート本文とアップロード済みの画像のmedia_idを引数にツイート def post_tweet(tweet_text, media_id): params = {'status': tweet_text, 'media_ids': media_id} res = twitter.post(url_text, params=params) if res.status_code == 200: print('Auto Tweet Succeeded.') else: print('Failed. : %d' % res.status_code) def main(): json_file_path = '/content/sample_data/tweetcontent.json' tweet_content = get_tweet_content(json_file_path) media_id = upload_media(tweet_content['img_url']) post_tweet(tweet_content['tweet_text'], media_id) ※下記実行時にエラー発生 if __name__ == '__main__': main()

エラー内容 


※JSONに記載された内容を読み取れていないと考えております。

NameError Traceback (most recent call last)
<ipython-input-25-174f78df48e2> in <module>()
1 if name == 'main':
----> 2 main()

1 frames
<ipython-input-24-d2f2ce4bbe66> in main()
1 def main():
2 json_file_path = '/content/sample_data/tweetcontent.json'
----> 3 tweet_content = get_tweet_content(json_file_path)
4 media_id = upload_media(tweet_content['img_url'])
5 post_tweet(tweet_content['tweet_text'], media_id)

<ipython-input-21-8d70d6a47637> in get_tweet_content(json_file_path)
6 #JSONとして読み込んだfile変数が格納されたjson_data変数に、jsonデータを格納
7 #random.choice()でリストからランダムに要素を一つ取得
----> 8 return random.choice(json_data["contents"])

NameError: name 'random' is not defined

参照リンク

PythonとJSONで画像付きツイートを自動化する

追加で発生したエラー

上記のエラーの「NameError: name 'random' is not defined」は解消でき、ツイートもテキストツイートは成功しました。

ですが、画像ツイートが下記のエラーにより、失敗してしまいます。
お手数ですが、引き続きご教示いただけますと幸いです。
宜しくお願い致します。

■一回目実行
画像投稿失敗ログ:
GoogleDriveをマウントしました→セッションがクラッシュしました

↓ 下記ログが出力

Image upload failed: %s {"request":"/1.1/media/upload.json","error":"media type unrecognized."}
Auto Tweet Succeeded.

■二回目実行
一回目実行後再実行すると下記のエラーが発生再発します。


NameError Traceback (most recent call last)
<ipython-input-1-0f1ead28e8c2> in <module>()
1 if name == 'main':
----> 2 main()

NameError: name 'main' is not defined

確認したい内容

・convert_url(url)の引数urlはreturnされた「"https://drive.google.com/uc?export=view&id=%s" % a.group(1)」の値が記載されている認識でよろしいでしょうか。認識が間違っている場合、引数にはどの値(ファイルパス指定、JSONに記載したファイルパスの変数を指定など)を定義するべきでしょうか。
・main()関数にはconvert_url(url)を呼び出す関数がないようですが、こちらの関数はどのように呼び出せばよろしいでしょうか。
・main()関数に記載したjson_file_pathにjsonファイルのパスを直指定しているのですが、こちらはjsonファイル名を記載するのが正しいのでしょうか。
・Pythonの実行方法として、定義された関数をmainから実行していくという認識であっているのでしょうか。※初歩的な質問で申し訳ございません

長くなってしまい申し訳ございませんが、宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

random モジュールがないというエラーメッセージなので、冒頭で
import random
とすればよいのではないでしょうか。


追記

まず、上記のコードで正常に動かないところを修正します。
具体的には、

def upload__media(img_url):

 を

def upload_media(img_url):

に変えます。(uploadとdataの間のアンダーバーを2つから1つに変える。)

その上で、/content/sample_data/tweetcontent.json の中の "img_url":の「対象ファイルのURL」を、
ネット上の自由に使用可能な素材へのリンクに変えてテストしたところ、
自分の環境では正常に画像ツイートできました。

ためしに「対象ファイルのURL」を自分のGoogle Drive上の画像ファイルへのリンクに変えたところ、
質問者さんと同じ
Image upload failed: %s {"request":"/1.1/media/upload.json","error":"media type unrecognized."}

というエラーが出ました。

したがって、Google Driveの「リンクの取得」で取得したリンクそのままでは、twitter APIからは画像データを正常に取得できないと推測されます。

そこで下のコードでは、stackoverrun の内容を参考に、urlを取得できる形に変換する関数(convert_url)を追加しています。

全文

import json import random # <-------回答追加時当初から追加しています import re # <-------追加 from requests_oauthlib import OAuth1Session #urlを使用するためのモジュール import urllib.request # url変換に使用する正規表現 pattern = re.compile(r".*/file/./(.*)/.*") # <-------追加 #下記TwitterのAPIキー、アクセスキーのため記載しておりません CONSUMER_KEY = '****************************' CONSUMER_SECRET = '****************************' ACCESS_TOKEN = '****************************' ACCESS_TOKEN_SECRET = '****************************' #Twitterアクセスキーを変数へ格納 twitter = OAuth1Session(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET) #メディアアップロードに使用するURL url_media = "https://upload.twitter.com/1.1/media/upload.json" #テキストアップロードに使用するURL url_text = "https://api.twitter.com/1.1/statuses/update.json" # Googleドライブ上のリンクを、twitter API等で直接取得できるurlに変換する関数 <-------追加 def convert_url(url): a = re.search(pattern, url) try: return "https://drive.google.com/uc?export=view&id=%s" % a.group(1) except (AttributeError, IndexError) as e: # パターンマッチしない場合はメッセージを出して、渡されたurlをそのまま返す。 print("[%s]はパターンにマッチしないため、そのまま返します。" % url) return url #jsonファイルからツイート本文と画像urlを取得 def get_tweet_content(json_file_path): #テキストファイルを読み込む file = open(json_file_path, 'r', encoding='utf-8') #開いたファイルをjson.load関数でJSONとして読み込む json_data = json.load(file) #JSONとして読み込んだfile変数が格納されたjson_data変数に、jsonデータを格納 #random.choice()でリストからランダムに要素を一つ取得 return random.choice(json_data["contents"]) #画像をTwitterにアップロードし、media_idをリターン #img_urlはJSONで指定した画像オブジェクト def upload_media(img_url): #=========================== # urlを変換する # <-------回答追加時当初から追加しています img_url = convert_url(img_url) # <-------回答追加時当初から追加しています #urlをオープンする res = urllib.request.urlopen(img_url) #========================= img_data = res.read() img_files = {'media': img_data} res_media = twitter.post(url_media, files=img_files) if res_media.status_code == 200: return json.loads(res_media.text)['media_id'] else: print('Image upload failed: %s', res_media.text) exit() #ツイート本文とアップロード済みの画像のmedia_idを引数にツイート def post_tweet(tweet_text, media_id): params = {'status': tweet_text, 'media_ids': media_id} res = twitter.post(url_text, params=params) if res.status_code == 200: print('Auto Tweet Succeeded.') else: print('Failed. : %d' % res.status_code) def main(): json_file_path = '/content/sample_data/tweetcontent.json' # ファイルパスを修正しました。 tweet_content = get_tweet_content(json_file_path) media_id = upload_media(tweet_content['img_url']) post_tweet(tweet_content['tweet_text'], media_id) if __name__ == '__main__': main()

・convert_url(url)の引数urlはreturnされた「"https://drive.google.com/uc?export=view&id=%s" % a.group(1)」の値が記載されている認識でよろしいでしょうか。

yesかnoかでいえばnoです。
convert_url(url)の引数urlには、tweetcontent.json内に記載されている、googleドライブ上のファイルへのパス(img_url)が渡されます。

認識が間違っている場合、引数にはどの値(ファイルパス指定、JSONに記載したファイルパスの変数を指定など)を定義するべきでしょうか。

convert_url(url)の引数urlには、tweetcontent.jsonに記載されている、googleドライブ上のファイルへのパスを渡すべきです。

回答のコードは「tweetcontent.jsonに記載されたgoogleドライブ上のファイルへのパス」をconvert_url関数に渡すようにしています。

・main()関数にはconvert_url(url)を呼び出す関数がないようですが、こちらの関数はどのように呼び出せばよろしいでしょうか。

コメントを追加しました。
回答コード全文には最初から、upload_media関数内にconvert_url(url)を呼び出すコードを入れておりましたが、
「# <----追加」というコメントを入れ忘れておりました。

main()からconvert_url(url)を呼ぶのではなく、
upload_media関数の中からconvert_url(url)を呼び出しています。

・main()関数に記載したjson_file_pathにjsonファイルのパスを直指定しているのですが、こちらはjsonファイル名を記載するのが正しいのでしょうか。

回答コードは、自分のテスト環境用のjsonファイルパスを記載してしまっていたので、元質問のファイルパスに修正しました。
元質問のコードのように、jsonファイルのパスを直指定するやり方で問題ありません。

・Pythonの実行方法として、定義された関数をmainから実行していくという認識であっているのでしょうか。※初歩的な質問で申し訳ございません

特にmainから実行していくという制約はありません。

(importを無視しての話になりますが)pythonでは上から順番に読み取られ、実行できる部分があれば上から実行されます。
ただし、関数定義部分(def)やクラス定義部分(class)等は、読み取られるだけで実行されません。
(※importを読み取ったときの挙動等、細かい点まで考慮すると上記の説明は完全に正確というわけではありませんが、雰囲気としてそういうものだと考えてくだされば結構です)

例:

[1]

def sub(a,b): print("sub関数を呼び出しました") return a - b def main(a,b): print("main関数を呼び出しました") return a + b # 関数等定義以外で一番最初に現れる行なので、ここから実行される。 if __name__ == '__main__': # main()が最初でなくてよい print(sub(1,2)) print(main(1,2))

[2]

def sub(a,b): print("sub関数を呼び出しました") return a - b def main(a,b): print("main関数を呼び出しました") return a + b # if __name__ == '__main__':がなくても # 関数定義以外で一番最初に現れる行なので、ここから実行される。 print(sub(1,2)) print(main(1,2))

[3]

def sub(a,b): print("sub関数を呼び出しました") return a - b # mainという名前の関数は存在する必要はない def add(a,b): print("add関数を呼び出しました") return a + b if __name__ == '__main__': print(sub(1,2)) print(add(1,2))

[4]

def sub(a,b): print("sub関数を呼び出しました") return a - b def add(a,b): print("add関数を呼び出しました") return a + b # 関数定義以外で一番最初に現れる行なので、ここから実行される。 print(sub(1,2)) print(add(1,2)) # ここより下は上の2行が実行された後評価され、実行される。 if __name__ == '__main__': print('実行: IF __name__ = =__main__:')

投稿2020/11/18 07:35

編集2020/11/19 05:38
sfdust

総合スコア1137

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

unity_level1

2020/11/18 08:53

sfdust様 本件、ご回答いただきありがとうございます。 ご教示いただきましたとおり、本エラーはimport randomの抜け漏れによるものでした。 追加で申し訳ないのですが、実行したところ、Twitterに画像をアップロードする部分で、Failedが発生してしまい、文字のみしか投稿ができない状況です。 重ねての質問になってしまい申し訳ございませんが、お分かりの場合、ご教示いただけますと幸いです。 詳細な内容は追記で、質問に記載させていただきます。 お手数ですが、宜しくお願い致します。
sfdust

2020/11/18 15:03

追記しました。
unity_level1

2020/11/19 03:04 編集

sfdust様 重ねて詳細なご回答いただきありがとうございます。 非常に勉強になります。 ご教示いただきました内容を試してみたのですが、やはり同様のエラー「Image upload failed」が発生してしまいました。 おそらく、私のコード理解が浅いことが原因と思われるため、追加の質問になってしまい大変申し訳ないのですが、記述しているコードについてご教示いただけますと幸いです。 確認したい点とご教示いただきましたスクリプトを追記させていただきますので、お手数をおかけしますが、ご確認していただけますと幸いです。 宜しくお願い致します。
sfdust

2020/11/19 05:31 編集

追加した行に「追加した」というコメントをつけていない行がありました。 コメントを追記しておりますので、参考にしてください。 それでも動かない場合は、コピペミスの可能性がありますので、記載した「全文」のソースコードの内容を全部そのままコピペして実行してみてください。 エラーが出た場合は、プログラム実行時の出力を含めて出力された内容全文を記載してください。 (どこまで正常に実行されていてどこでエラーが出たのか把握するために必要です)
unity_level1

2020/11/19 06:29

sfdust様 重ね重ね詳細なご回答いただきありがとうございます。 ご教示いただきました内容で試したところ、うまく画像を投稿することができました。 また、確認事項を全て読ませていただき、わかりやすく非常に勉強になりました。 もう少し基本的な部分からPythonを勉強していきたいと思います。 本件につきまして、本当に助かりました。ありがとうございました。 ※下記につきましては、本事象に直接的に関係するものでないため、もし気が向いたらご回答いただければ幸いです。 最後に二点だけ可能であればご教示いただきたいです。 ※TeraTailのマナーが分かっていないため、別質問として質問するのがマナーの場合はご指摘いただければ幸いです。 一点目: GoogleColaboratory内でJSONファイルを作成しているのですが、ランタイムが更新されると、JSONファイルが削除されてしまいます。この場合、JSONファイルを削除せずに残しておくことは可能なのでしょうか。 二点目: 同様の処理をGoogle App Scriptsから実行しようとしたところ、エラーが発生してしまいます。 おそらく本件と同様にurlを取得できる形に変換する関数を定義する必要があると考えております。 下記で別途質問をしておりますので、こちらにご回答いただけますと幸いです。 https://teratail.com/questions/301733 どうぞ宜しくお願い致します。
sfdust

2020/11/19 10:35

> 一点目:GoogleColaboratory内でJSONファイルを作成しているのですが、ランタイムが更新されると、JSONファイルが削除されてしまいます。この場合、JSONファイルを削除せずに残しておくことは可能なのでしょうか。 Cplaboratoryに、Google driveを紐付け、その中に保存したらどうでしょうか。 https://qiita.com/k_uekado/items/45b76f9a6f920bf0f786
unity_level1

2020/11/20 06:40

sfdust様 本件ご回答いただきありがとうございます。非常に助かります。 ご教示いただきました方法で実施してみましたところ別のエラーが発生してしまいました。 調べたところ、現状の私の知識では解決することが難しかったため、下記にて発生したエラーログを記載させていただき、別途質問をさせていただきました。 大変申し訳ございませんが、よろしければ下記にてご確認いただければ幸いです。 重ね重ねお手数をおかけしますが、何卒宜しくお願い致します。 https://teratail.com/questions/305463?modal=q-comp
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問