hir0sys
@hir0sys

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

pythonでのtweepyを使用した動作時に443が発生する

Q&A

Closed

初めまして。
現在、tweepyを使用したCUIでのTwitterの自動動作を作成しています。
動作内容ですが、検索、フォロー、リツイート、ブロックを行います。

自身のアカウントのKEY4種では問題なく動作するのですが、
@ekzemplaro 様の記事
Twitter の OAuth認証 (Python3)
https://qiita.com/ekzemplaro/items/a622ddf20cb841d03450
を参考に別アカウントでアクセストークンを取得し、動作させようとしたところ


DEBUG:requests_oauthlib.oauth1_auth:Updated body: None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.twitter.com:443
DEBUG:urllib3.connectionpool:https://api.twitter.com:443 "GET /1.1/search/tweets.json?q=%......


というエラーが出力され、動作しません。
Qiitaでの投稿が初めてのため、どの部分を提示することで回答者様の問題特定の手がかりになるのかが分からず、追加で質問をさせてしまうことご容赦ください。

以上、よろしくお願いします。

import tweepy
import schedule,time,datetime
import logging
import csv
import gspread
import json
import random
import configparser
import sys
ng_user = []
ng_word = []
chk_flg = 0
waitTime = 1
def main():
    global chk_flg
    global block_list
    tweet_list = []
    block_list = []
    #トークン
    CONSUMER_KEY = 
    CONSUMER_SECRET = 
    #ini読込
    ini = configparser.ConfigParser()
    ini.read('./config.ini', 'UTF-8')
    ACCESS_TOKEN = ini['user_data']['ACCESS_TOKEN']
    ACCESS_SECRET = ini['user_data']['ACCESS_SECRET']
    #スプレッドシート接続
    from oauth2client.service_account import ServiceAccountCredentials 
    scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
    credentials = ServiceAccountCredentials.from_json_keyfile_name('', scope)
    gc = gspread.authorize(credentials)
    SPREADSHEET_KEY = 
    #ユーザーリスト取得
    worksheet = gc.open_by_key(SPREADSHEET_KEY).worksheet('') 
    try:
        cell = worksheet.find(ACCESS_TOKEN)
    except:
        print('')
        sys.exit()
    user_data = worksheet.row_values(cell.row)
    #NG_word,NG_List取得
    worksheet = gc.open_by_key(SPREADSHEET_KEY).worksheet('') 
    ng_word = worksheet.col_values(1)
    ng_user = worksheet.col_values(2)
    #リスト重複削除
    tweet_list = set(tweet_list)
    block_list = set(block_list)
    #csv読込-Tweet
    with open(".csv")as rf:
        csv.reader(rf)
        for row in rf:
            tweet_list.add(str(row))
    rf.close
    #csv読込-block
    with open(".csv")as rf:
        csv.reader(rf)
        for row in rf:
            block_list.add(str(row).replace("\n",""))   
    #情報取得
    StartTime_h = user_data[2]
    StartTime_m = user_data[3]
    StartTime_S = user_data[4]
    EndTime_h = user_data[5]
    EndTime_m = user_data[6]
    EndTime_s = user_data[7]
    Fav = user_data[8]
    RT = user_data[9]
    Follow = user_data[10]
    Rep = user_data[11]
    SearchWord = user_data[12]
    LimitDate = user_data[13]
    #稼働時間設定
    chkTime = datetime.datetime.now()
    today8am = chkTime.replace(hour=int(StartTime_h), minute=int(StartTime_m), second=int(StartTime_S), microsecond=0)
    today23pm = chkTime.replace(hour=int(EndTime_h), minute=int(EndTime_m), second=int(EndTime_s), microsecond=0)
    if ((chkTime > today8am) and (chkTime < today23pm)):
        rtCount = 0
        foCount = 0
        auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
        auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
        api = tweepy.API(auth,wait_on_rate_limit=True,wait_on_rate_limit_notify=True)
        #自身のフォロー取得
        follow_id = api.friends_ids()
        #検索ワード
        if waitTime == 1:
            search_results = api.search(q=""), count=random.randint(5,12))
        else:
            search_results = api.search(q=""), count=random.randint(5,12))
        logging.info(""))
        for result in search_results:
            #NGWordチェック
            for chkStr in ng_word:
                if chkStr in result.text:
                    chk_flg = 1
                    print('NGワード発見しました:' + chkStr)
                    if str(result.user._json['screen_name']) not in block_list:
                        api.create_block(result.user._json['screen_name'])
                        print(str(result.user._json['name'])+'(@'+str(result.user._json['screen_name'])+')'+'をブロックしました。')
                        block_list.add(str(result.user._json['screen_name']))
            #NGUserチェック
            if (result.user._json['screen_name'] in ng_user) and chk_flg == 0:
                chk_flg = 1
                print('NGユーザーです。' + result.user._json['screen_name'])
                if str(result.user._json['screen_name']) not in block_list:
                    api.create_block(result.user._json['screen_name'])
                    print(str(result.user._json['name'])+'(@'+str(result.user._json['screen_name'])+')'+'をブロックしました。')
                    block_list.add(str(result.user._json['screen_name']))
            if chk_flg == 0:
                tweet_id = result.id
                user_id = result.user._json['id']
                try:
                    if not((str(tweet_id) + "\n") in tweet_list):
                        #メイン処理
                        if RT == 0:
                            api.retweet(tweet_id) #RT
                        if Fav == 0:
                            api.create_favorite(tweet_id) #いいね
                            tweet_list.add(str(tweet_id))
                        if (user_id not in follow_id) and (Follow == 0):
                            api.create_friendship(user_id) #フォロー
                except Exception as e:
                    print(e.reason)
                    if 'To protect our users from spam and other malicious activity, this account is temporarily locked' in e.reason:
                        print('アカウントがロックされました。処理を中断します。')
                        logging.info('アカウントがロックされました。処理を中断します。')
                        exit()
                    else:
                        print(e.reason)
                        logging.info(e.reason)
                        print(user_id)
            chk_flg = 0
        #csvファイル上書き-Tweet
        with open("", 'w') as f:
            for ele in tweet_list:
                f.write(str(ele).replace("\n","") + "\n")
        f.close
        tweet_list.clear()
        #csvファイル上書き-block
        with open("", 'w') as f:
            for ele in block_list:
                f.write(str(ele).replace("\n","") + "\n")
        f.close
        block_list.clear()
        #ツイート投稿部分
        tweetText = chkTime.strftime("%Y/%m/%d %H:%M:%S")+"\n"
        tweetText = tweetText + 
        tweetText = tweetText + 
        tweetText = tweetText + 
    else:
        print('現在の時刻は動作停止中です。')                    
        print("現在の日時:",chkTime)
        logging.info('現在の時刻は動作停止中です。')

def job():
    global waitTime
    log_folder = '{0}.log'.format(datetime.date.today())
    now=datetime.datetime.now()
    main()
    print("処理が完了しました。日時:" + now.strftime("%Y/%m/%d %H:%M:%S"))
    logging.info("処理が完了しました。日時:" + now.strftime("%Y/%m/%d %H:%M:%S"))
    waitTime = random.randint(25,45)
    print(str(waitTime) + '分待機します。')
schedule.every(1).minutes.do(job)
while True:
    logging.basicConfig(filename='main.log', level=logging.DEBUG)
    schedule.run_pending()
    time.sleep(waitTime*60)

ソースここまで

0

3Answer

DEBUG:requests_oauthlib.oauth1_auth:Updated body: None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.twitter.com:443
DEBUG:urllib3.connectionpool:https://api.twitter.com:443 "GET /1.1/search/tweets.json?q=%......

これはエラーとは関係ないログのようです。 このログから分かることは https://api.twitter.com:443GET /1.1/search/tweets.json?q=%...... リクエストを試みたことだけです。

443はエラーコードではなく HTTPS で通信を行う際のデフォルトのポート番号です。 https://api.twitter.com:443 はポート番号を明示した形の URL であり、 https://api.twitter.com と同じ意味になります。

他にログは出ていませんか? DEBUG: で始まる行は動作を逐一報告する詳細度の高いログで、分かりやすい手がかりになることはあまりありません。問題があれば WARN:ERROR: で始まる行にヒントがあるはずです。

またソースコードを公開できるのであれば(トークンの類を伏せ字にして)貼っていただけると答えやすいです。

0Like

Comments

  1. @hir0sys

    Questioner

    回答ありがとうございます。
    ソースコードの公開を追記で行いました。
    ログの確認を行いましたが、WARNやERRORの文字列が存在しません。
    '''
    DEBUG:requests_oauthlib.oauth1_auth:Updated url: https://api.twitter.com/1.1/search/tweets.json?q=~
    '''
    のURLをクリックした際に
    {"errors":[{"code":215,"message":"Bad Authentication data."}]}
    と表示されるため、443もエラーコードと勘違いしておりました。申し訳ありません。

「Bad Authentication data.」とある通り認証情報が不正となっていてエラーとなっています。
ばっとソースを見た感じだとiniファイルからtokenを取得して通信を行っているようですが、ACCESS_TOKENの有効期限が切れているためエラーが発生しているように見受けられました。

ACCESS_TOKENは有効期限が1時間くらいで設定されていますので、必要に応じて更新してあげなければいけません。REFRESH_TOKENを取得して、そこからACCESS_TOKENを更新してやりたいことをやるような流れになります。

よく分からなければOAuthについて勉強されることをお勧めします。

0Like

Comments

  1. @hir0sys

    Questioner

    回答ありがとうございます。
    結果的にトークン以前の型異常だったため、そもそも・・・というところではありましたが
    REFRESH_TOKEN についての知識が増えたためよかったです。

Twitter API の認証情報は HTTP ヘッダで送信するものです。よって https://api.twitter.com/1.1/search/tweets.json?q=... の URL に認証情報は含まれませんから、クリックしてブラウザで開くと必ず Bad Authentication data になります。ここからはプログラムのエラーの原因は分かりません。ご自身のアクセストークンでは動くということなので、アクセストークンまわりの問題だとは思いますが。

以下のような感じでプログラムを単純化してみて最低限の Twitter API 呼び出しが成功するか確認するといいと思います。

import tweepy
import configparser

CONSUMER_KEY = キー
CONSUMER_SECRET = トークン
ini = configparser.ConfigParser()
ini.read('./config.ini', 'UTF-8')
ACCESS_TOKEN = ini['user_data']['ACCESS_TOKEN']
ACCESS_SECRET = ini['user_data']['ACCESS_SECRET']

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
api = tweepy.API(auth,wait_on_rate_limit=True,wait_on_rate_limit_notify=True)
follow_id = api.friends_ids()

# follow_id が取得できたか確認
# もし取得できているなら search 他が動くかも順次確認していく
# 認証に失敗したら tweepy.TweepError が送出されるはず
print(follow_id)

@tasogarei Twitter API 1.1 のアクセストークンはユーザーが明示的に無効化しない限り失効しないのでリフレッシュする必要はありません、というよりクライアントからはリフレッシュできません。リフレッシュトークンが仕様化された OAuth 2.0 ではなく OAuth 1.0a を使っているためです。

How long does an access token last?

Access tokens are not explicitly expired. An access token will be invalidated if a user explicitly revokes an application in the their Twitter account settings, or if Twitter suspends an application. If an application is suspended, there will be a note in the Twitter app dashboard stating that it has been suspended.

0Like

Comments

  1. @hir0sys

    Questioner

    結論から申しますと、問題はトークンではなくGoogleスプレッドシートから取得してきた文字列が原因でした。
    0,1で動作フラグを作っていたのですが、数値として記載していたものの、取得した際に文字列型に変更されていました。
    '''
    if RT == 0:
    api.retweet(tweet_id) #RT
    if Fav == 0:
    api.create_favorite(tweet_id) #いいね
    tweet_list.add(str(tweet_id))
    if (user_id not in follow_id) and (Follow == 0):
    api.create_friendship(user_id) #フォロー
    '''


    '''
    if RT == "0":
    api.retweet(tweet_id) #RT
    if Fav == "0":
    api.create_favorite(tweet_id) #いいね
    tweet_list.add(str(tweet_id))
    if (user_id not in follow_id) and (Follow == "0"):
    api.create_friendship(user_id) #フォロー
    '''
    これで解決しました。
    些細なことでお騒がせしましてすいませんでした。

Your answer might help someone💌