回答編集履歴

10

修正

2020/11/19 05:38

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -248,7 +248,7 @@
248
248
 
249
249
  yesかnoかでいえばnoです。
250
250
 
251
- convert_url(url)の引数urlには、JSONに記載されている、googleドライブ上のファイルへのパス(img_url)が渡されます。
251
+ convert_url(url)の引数urlには、tweetcontent.json内に記載されている、googleドライブ上のファイルへのパス(img_url)が渡されます。
252
252
 
253
253
 
254
254
 
@@ -260,11 +260,11 @@
260
260
 
261
261
 
262
262
 
263
- convert_url(url)の引数urlには、JSONに記載されている、googleドライブ上のファイルへのパスを渡すべきです。
263
+ convert_url(url)の引数urlには、tweetcontent.jsonに記載されている、googleドライブ上のファイルへのパスを渡すべきです。
264
-
265
-
266
-
264
+
265
+
266
+
267
- なお、回答のコードは「JSONに記載されたgoogleドライブへのパス」をconvert_url関数に渡すようにしています。
267
+ 回答のコードは「tweetcontent.jsonに記載されたgoogleドライブ上のファイルへのパス」をconvert_url関数に渡すようにしています。
268
268
 
269
269
 
270
270
 

9

修正

2020/11/19 05:38

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -260,11 +260,11 @@
260
260
 
261
261
 
262
262
 
263
- convert_url(url)の引数urlには、JSONに記載されている、googleドライブ上のファイルへのパス「JSONに記載したファイルパス」を渡すべきです。
263
+ convert_url(url)の引数urlには、JSONに記載されている、googleドライブ上のファイルへのパスを渡すべきです。
264
-
265
-
266
-
264
+
265
+
266
+
267
- なお、回答のコードは、元質問のコードをなるべく変えないように「JSONに記載されたgoogleドライブへのパス」をconvert_url関数に渡すようにしています。
267
+ なお、回答のコードは「JSONに記載されたgoogleドライブへのパス」をconvert_url関数に渡すようにしています。
268
268
 
269
269
 
270
270
 

8

修正

2020/11/19 05:32

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -260,9 +260,11 @@
260
260
 
261
261
 
262
262
 
263
- 引数には、JSONに記載したgoogleドライブへのパス(url)がされていればよいの、元質問のコードから変える必要はありません
263
+ convert_url(url)の引数urlには、JSONに記載されている、googleドライブ上のファイルへのパス「JSONに記載したファイルパス」をすべき
264
+
265
+
266
+
264
-
267
+ なお、回答のコードは、元質問のコードをなるべく変えないように「JSONに記載されたgoogleドライブへのパス」をconvert_url関数に渡すようにしています。
265
-
266
268
 
267
269
 
268
270
 

7

修正

2020/11/19 03:57

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -418,7 +418,7 @@
418
418
 
419
419
  def add(a,b):
420
420
 
421
- print("main関数を呼び出しました")
421
+ print("add関数を呼び出しました")
422
422
 
423
423
  return a + b
424
424
 
@@ -452,7 +452,7 @@
452
452
 
453
453
  def add(a,b):
454
454
 
455
- print("main関数を呼び出しました")
455
+ print("add関数を呼び出しました")
456
456
 
457
457
  return a + b
458
458
 
@@ -470,8 +470,8 @@
470
470
 
471
471
  if __name__ == '__main__':
472
472
 
473
- print('実行:__name__==__main__')
473
+ print('実行: IF __name__ = =__main__:')
474
-
475
-
476
-
474
+
475
+
476
+
477
- ```
477
+ ```

6

修正

2020/11/19 03:54

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -248,7 +248,7 @@
248
248
 
249
249
  yesかnoかでいえばnoです。
250
250
 
251
- convert_url(url)の引数urlは、JSONに記載したgoogleドライブへのパス(url)が渡されます。
251
+ convert_url(url)の引数urlは、JSONに記載されている、googleドライブ上のファイルへのパス(img_url)が渡されます。
252
252
 
253
253
 
254
254
 

5

修正

2020/11/19 03:52

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -276,13 +276,17 @@
276
276
 
277
277
  コメントを追加しました。
278
278
 
279
- 回答コード全文には最初から、upload_media関数内にconvert_url(url)を呼び出すコードを入れておりましたが、
279
+ 回答コード全文には最初から、upload_media関数内にconvert_url(url)を呼び出すコードを入れておりましたが、
280
280
 
281
281
  「# <----追加」というコメントを入れ忘れておりました。
282
282
 
283
283
 
284
284
 
285
+ main()からconvert_url(url)を呼ぶのではなく、
286
+
285
- upload_media関数内に、convert_url(url)を呼び出していますので、main()で呼ぶ必要はありません
287
+ upload_media関数の中からconvert_url(url)を呼び出しています。
288
+
289
+
286
290
 
287
291
 
288
292
 
@@ -296,7 +300,7 @@
296
300
 
297
301
  回答コードは、自分のテスト環境用のjsonファイルパスを記載してしまっていたので、元質問のファイルパスに修正しました。
298
302
 
299
- 元質問のコードのように、jsonファイルのパスを直指定で問題ありません。
303
+ 元質問のコードのように、jsonファイルのパスを直指定するやり方で問題ありません。
300
304
 
301
305
 
302
306
 
@@ -310,7 +314,7 @@
310
314
 
311
315
 
312
316
 
313
- importを無視しての話になりますがpythonでは上から順番に読み取られ、実行できる部分があれば上から実行されます。
317
+ importを無視しての話になりますがpythonでは上から順番に読み取られ、実行できる部分があれば上から実行されます。
314
318
 
315
319
  ただし、関数定義部分(def)やクラス定義部分(class)等は、読み取られるだけで実行されません。
316
320
 

4

追加

2020/11/19 03:50

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -222,7 +222,7 @@
222
222
 
223
223
  def main():
224
224
 
225
- json_file_path = 'contents.json'
225
+ json_file_path = '/content/sample_data/tweetcontent.json' # ファイルパスを修正しました。
226
226
 
227
227
  tweet_content = get_tweet_content(json_file_path)
228
228
 
@@ -237,3 +237,237 @@
237
237
  main()
238
238
 
239
239
  ```
240
+
241
+
242
+
243
+
244
+
245
+ > ・convert_url(url)の引数urlはreturnされた「"https://drive.google.com/uc?export=view&id=%s" % a.group(1)」の値が記載されている認識でよろしいでしょうか。
246
+
247
+
248
+
249
+ yesかnoかでいえばnoです。
250
+
251
+ convert_url(url)の引数urlは、JSONに記載したgoogleドライブへのパス(url)が渡されます。
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+ > 認識が間違っている場合、引数にはどの値(ファイルパス指定、JSONに記載したファイルパスの変数を指定など)を定義するべきでしょうか。
260
+
261
+
262
+
263
+ 引数には、JSONに記載したgoogleドライブへのパス(url)が渡されていればよいので、元質問のコードから変える必要はありません。
264
+
265
+
266
+
267
+
268
+
269
+
270
+
271
+
272
+
273
+ > ・main()関数にはconvert_url(url)を呼び出す関数がないようですが、こちらの関数はどのように呼び出せばよろしいでしょうか。
274
+
275
+
276
+
277
+ コメントを追加しました。
278
+
279
+ 回答コード全文には最初から、upload_media関数内に、convert_url(url)を呼び出すコードを入れておりましたが、
280
+
281
+ 「# <----追加」というコメントを入れ忘れておりました。
282
+
283
+
284
+
285
+ upload_media関数内に、convert_url(url)を呼び出していますので、main()で呼ぶ必要はありません。
286
+
287
+
288
+
289
+
290
+
291
+
292
+
293
+ > ・main()関数に記載したjson_file_pathにjsonファイルのパスを直指定しているのですが、こちらはjsonファイル名を記載するのが正しいのでしょうか。
294
+
295
+
296
+
297
+ 回答コードは、自分のテスト環境用のjsonファイルパスを記載してしまっていたので、元質問のファイルパスに修正しました。
298
+
299
+ 元質問のコードのように、jsonファイルのパスを直指定で問題ありません。
300
+
301
+
302
+
303
+
304
+
305
+ > ・Pythonの実行方法として、定義された関数をmainから実行していくという認識であっているのでしょうか。※初歩的な質問で申し訳ございません
306
+
307
+
308
+
309
+ 特にmainから実行していくという制約はありません。
310
+
311
+
312
+
313
+ importを無視しての話になりますが、pythonでは上から順番に読み取られ、実行できる部分があれば上から実行されます。
314
+
315
+ ただし、関数定義部分(def)やクラス定義部分(class)等は、読み取られるだけで実行されません。
316
+
317
+ (※importを読み取ったときの挙動等、細かい点まで考慮すると上記の説明は完全に正確というわけではありませんが、雰囲気としてそういうものだと考えてくだされば結構です)
318
+
319
+
320
+
321
+ 例:
322
+
323
+
324
+
325
+ [1]
326
+
327
+
328
+
329
+ ```
330
+
331
+ def sub(a,b):
332
+
333
+ print("sub関数を呼び出しました")
334
+
335
+ return a - b
336
+
337
+
338
+
339
+ def main(a,b):
340
+
341
+ print("main関数を呼び出しました")
342
+
343
+ return a + b
344
+
345
+
346
+
347
+ # 関数等定義以外で一番最初に現れる行なので、ここから実行される。
348
+
349
+ if __name__ == '__main__':
350
+
351
+ # main()が最初でなくてよい
352
+
353
+ print(sub(1,2))
354
+
355
+ print(main(1,2))
356
+
357
+
358
+
359
+ ```
360
+
361
+
362
+
363
+ [2]
364
+
365
+
366
+
367
+ ```
368
+
369
+ def sub(a,b):
370
+
371
+ print("sub関数を呼び出しました")
372
+
373
+ return a - b
374
+
375
+
376
+
377
+ def main(a,b):
378
+
379
+ print("main関数を呼び出しました")
380
+
381
+ return a + b
382
+
383
+
384
+
385
+ # if __name__ == '__main__':がなくても
386
+
387
+ # 関数定義以外で一番最初に現れる行なので、ここから実行される。
388
+
389
+ print(sub(1,2))
390
+
391
+ print(main(1,2))
392
+
393
+
394
+
395
+ ```
396
+
397
+
398
+
399
+ [3]
400
+
401
+
402
+
403
+ ```
404
+
405
+ def sub(a,b):
406
+
407
+ print("sub関数を呼び出しました")
408
+
409
+ return a - b
410
+
411
+
412
+
413
+ # mainという名前の関数は存在する必要はない
414
+
415
+ def add(a,b):
416
+
417
+ print("main関数を呼び出しました")
418
+
419
+ return a + b
420
+
421
+
422
+
423
+
424
+
425
+ if __name__ == '__main__':
426
+
427
+ print(sub(1,2))
428
+
429
+ print(add(1,2))
430
+
431
+ ```
432
+
433
+
434
+
435
+ [4]
436
+
437
+
438
+
439
+ ```
440
+
441
+ def sub(a,b):
442
+
443
+ print("sub関数を呼び出しました")
444
+
445
+ return a - b
446
+
447
+
448
+
449
+ def add(a,b):
450
+
451
+ print("main関数を呼び出しました")
452
+
453
+ return a + b
454
+
455
+
456
+
457
+ # 関数定義以外で一番最初に現れる行なので、ここから実行される。
458
+
459
+ print(sub(1,2))
460
+
461
+ print(add(1,2))
462
+
463
+
464
+
465
+ # ここより下は上の2行が実行された後評価され、実行される。
466
+
467
+ if __name__ == '__main__':
468
+
469
+ print('実行:__name__==__main__')
470
+
471
+
472
+
473
+ ```

3

追加

2020/11/19 03:47

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -70,7 +70,7 @@
70
70
 
71
71
  import json
72
72
 
73
- import random
73
+ import random # <-------回答追加時当初から追加しています
74
74
 
75
75
  import re # <-------追加
76
76
 
@@ -170,9 +170,9 @@
170
170
 
171
171
  def upload_media(img_url): #===========================
172
172
 
173
- # urlを変換する
173
+ # urlを変換する # <-------回答追加時当初から追加しています
174
-
174
+
175
- img_url = convert_url(img_url) # <-------追加
175
+ img_url = convert_url(img_url) # <-------回答追加時当初から追加しています
176
176
 
177
177
  #urlをオープンする
178
178
 

2

コメントを追加

2020/11/19 03:08

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -172,7 +172,7 @@
172
172
 
173
173
  # urlを変換する
174
174
 
175
- img_url = convert_url(img_url)
175
+ img_url = convert_url(img_url) # <-------追加
176
176
 
177
177
  #urlをオープンする
178
178
 

1

追記

2020/11/19 03:06

投稿

sfdust
sfdust

スコア1137

test CHANGED
@@ -3,3 +3,237 @@
3
3
  import random
4
4
 
5
5
  とすればよいのではないでしょうか。
6
+
7
+
8
+
9
+ ------------
10
+
11
+ 追記
12
+
13
+
14
+
15
+ まず、上記のコードで正常に動かないところを修正します。
16
+
17
+ 具体的には、
18
+
19
+ ```
20
+
21
+ def upload__media(img_url):
22
+
23
+ ```
24
+
25
+  を
26
+
27
+ ```
28
+
29
+ def upload_media(img_url):
30
+
31
+ ```
32
+
33
+ に変えます。(uploadとdataの間のアンダーバーを2つから1つに変える。)
34
+
35
+
36
+
37
+ その上で、/content/sample_data/tweetcontent.json の中の "img_url":の「対象ファイルのURL」を、
38
+
39
+ ネット上の自由に使用可能な素材へのリンクに変えてテストしたところ、
40
+
41
+ 自分の環境では正常に画像ツイートできました。
42
+
43
+
44
+
45
+ ためしに「対象ファイルのURL」を自分のGoogle Drive上の画像ファイルへのリンクに変えたところ、
46
+
47
+ 質問者さんと同じ
48
+
49
+ Image upload failed: %s {"request":"/1.1/media/upload.json","error":"media type unrecognized."}
50
+
51
+
52
+
53
+ というエラーが出ました。
54
+
55
+
56
+
57
+ したがって、Google Driveの「リンクの取得」で取得したリンクそのままでは、twitter APIからは画像データを正常に取得できないと推測されます。
58
+
59
+
60
+
61
+ そこで下のコードでは、[stackoverrun](https://stackoverflow.com/questions/10311092/displaying-files-e-g-images-stored-in-google-drive-on-a-website) の内容を参考に、urlを取得できる形に変換する関数(convert_url)を追加しています。
62
+
63
+
64
+
65
+ 全文
66
+
67
+
68
+
69
+ ```
70
+
71
+ import json
72
+
73
+ import random
74
+
75
+ import re # <-------追加
76
+
77
+ from requests_oauthlib import OAuth1Session
78
+
79
+ #urlを使用するためのモジュール
80
+
81
+ import urllib.request
82
+
83
+
84
+
85
+ # url変換に使用する正規表現
86
+
87
+ pattern = re.compile(r".*/file/./(.*)/.*") # <-------追加
88
+
89
+
90
+
91
+ #下記TwitterのAPIキー、アクセスキーのため記載しておりません
92
+
93
+ CONSUMER_KEY = '****************************'
94
+
95
+ CONSUMER_SECRET = '****************************'
96
+
97
+ ACCESS_TOKEN = '****************************'
98
+
99
+ ACCESS_TOKEN_SECRET = '****************************'
100
+
101
+
102
+
103
+ #Twitterアクセスキーを変数へ格納
104
+
105
+ twitter = OAuth1Session(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
106
+
107
+
108
+
109
+ #メディアアップロードに使用するURL
110
+
111
+ url_media = "https://upload.twitter.com/1.1/media/upload.json"
112
+
113
+
114
+
115
+ #テキストアップロードに使用するURL
116
+
117
+ url_text = "https://api.twitter.com/1.1/statuses/update.json"
118
+
119
+
120
+
121
+
122
+
123
+ # Googleドライブ上のリンクを、twitter API等で直接取得できるurlに変換する関数 <-------追加
124
+
125
+ def convert_url(url):
126
+
127
+ a = re.search(pattern, url)
128
+
129
+ try:
130
+
131
+ return "https://drive.google.com/uc?export=view&id=%s" % a.group(1)
132
+
133
+ except (AttributeError, IndexError) as e:
134
+
135
+ # パターンマッチしない場合はメッセージを出して、渡されたurlをそのまま返す。
136
+
137
+ print("[%s]はパターンにマッチしないため、そのまま返します。" % url)
138
+
139
+ return url
140
+
141
+
142
+
143
+
144
+
145
+ #jsonファイルからツイート本文と画像urlを取得
146
+
147
+ def get_tweet_content(json_file_path):
148
+
149
+ #テキストファイルを読み込む
150
+
151
+ file = open(json_file_path, 'r', encoding='utf-8')
152
+
153
+ #開いたファイルをjson.load関数でJSONとして読み込む
154
+
155
+ json_data = json.load(file)
156
+
157
+ #JSONとして読み込んだfile変数が格納されたjson_data変数に、jsonデータを格納
158
+
159
+ #random.choice()でリストからランダムに要素を一つ取得
160
+
161
+ return random.choice(json_data["contents"])
162
+
163
+
164
+
165
+
166
+
167
+ #画像をTwitterにアップロードし、media_idをリターン
168
+
169
+ #img_urlはJSONで指定した画像オブジェクト
170
+
171
+ def upload_media(img_url): #===========================
172
+
173
+ # urlを変換する
174
+
175
+ img_url = convert_url(img_url)
176
+
177
+ #urlをオープンする
178
+
179
+ res = urllib.request.urlopen(img_url) #=========================
180
+
181
+ img_data = res.read()
182
+
183
+ img_files = {'media': img_data}
184
+
185
+ res_media = twitter.post(url_media, files=img_files)
186
+
187
+
188
+
189
+ if res_media.status_code == 200:
190
+
191
+ return json.loads(res_media.text)['media_id']
192
+
193
+ else:
194
+
195
+ print('Image upload failed: %s', res_media.text)
196
+
197
+ exit()
198
+
199
+
200
+
201
+
202
+
203
+ #ツイート本文とアップロード済みの画像のmedia_idを引数にツイート
204
+
205
+ def post_tweet(tweet_text, media_id):
206
+
207
+ params = {'status': tweet_text, 'media_ids': media_id}
208
+
209
+ res = twitter.post(url_text, params=params)
210
+
211
+ if res.status_code == 200:
212
+
213
+ print('Auto Tweet Succeeded.')
214
+
215
+ else:
216
+
217
+ print('Failed. : %d' % res.status_code)
218
+
219
+
220
+
221
+
222
+
223
+ def main():
224
+
225
+ json_file_path = 'contents.json'
226
+
227
+ tweet_content = get_tweet_content(json_file_path)
228
+
229
+ media_id = upload_media(tweet_content['img_url'])
230
+
231
+ post_tweet(tweet_content['tweet_text'], media_id)
232
+
233
+
234
+
235
+ if __name__ == '__main__':
236
+
237
+ main()
238
+
239
+ ```