Соединение Twitter API прервано с Twython

Я пытаюсь загрузить подписчиков в твиттере из списка учетных записей. моя функция (которая использует twython) работает довольно хорошо для коротких списков учетных записей, но вызывает ошибку для более длинных списков. это не проблема RateLimit, так как моя функция спит до следующего временного интервала, если достигнут предел скорости. ошибка в этом

twythonerror: («Соединение прервано», ошибка (10054, ''))

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

    del twapi
    sleep(nap[afternoon])
    afternoon = afternoon + 1
    twapi = Twython(app_key=app_key, app_secret=app_secret,
                oauth_token=oauth_token, oauth_token_secret=oauth_token_secret)

сон — это список интервалов в секундах, а полдень — индекс. несмотря на это предложение, у меня все еще та же проблема. кажется, что сон не решает проблему. Может кто-нибудь помочь мне?

вот и вся фикция

def download_follower(serie_lst):
    """Creates account named txt files containing followers ids. Uses for loop on accounts names list."""
    nap = [1, 2, 4, 8, 16, 32, 64, 128]    
    afternoon = 0

    for exemplar in serie_lst:

        #username from serie_lst entries
        account_name = exemplar

        twapi = Twython(app_key=app_key, app_secret=app_secret,
                        oauth_token=oauth_token, oauth_token_secret=oauth_token_secret)

        try:
            #initializations
            del twapi
            if afternoon >= 7:
                afternoon =0

            sleep(nap[afternoon])
            afternoon = afternoon + 1
            twapi = Twython(app_key=app_key, app_secret=app_secret,
                        oauth_token=oauth_token, oauth_token_secret=oauth_token_secret)
            next_cursor = -1
            result = {}
            result["screen_name"] = ""
            result["followers"] = []
            iteration = 0
            file_name = ""

            #user info
            user = twapi.lookup_user(screen_name = account_name)

            #store user name
            result['screen_name'] = account_name

            #loop until all cursored results are stored
            while (next_cursor != 0):
                sleep(random.randrange(start = 1, stop = 15, step = 1))
                call_result = twapi.get_followers_ids(screen_name = account_name, cursor = next_cursor)
                #loop over each entry of followers id and append each     entry to results_follower    
                for i in call_result["ids"]:
                    result["followers"].append(i)
                next_cursor = call_result["next_cursor"] #new next_cursor
                iteration = iteration + 1
                if (iteration > 13): #skip sleep if all cursored pages are processed
                    error_msg = localtime()
                    error_msg = "".join([str(error_msg.tm_mon), "/", str(error_msg.tm_mday), "/", str(error_msg.tm_year), " at ", str(error_msg.tm_hour), ":", str(error_msg.tm_min)])
                    error_msg ="".join(["Twitter API Request Rate Limit hit on ", error_msg, ", wait..."])
                    print(error_msg)
                    del error_msg
                    sleep(901) #15min + 1sec
                    iteration = 0

            #output file
            file_name = "".join([account_name, ".txt"])

            #print output
            out_file = open(file_name, "w") #open file "account_name.txt"
            #out_file.write(str(result["followers"])) #standard format
            for i in result["followers"]: #R friendly table format
                out_file.write(str(i))
                out_file.write("\n")
            out_file.close()

        except twython.TwythonRateLimitError:
            #wait
            error_msg = localtime()
            error_msg = "".join([str(error_msg.tm_mon), "/", str(error_msg.tm_mday), "/", str(error_msg.tm_year), " at ", str(error_msg.tm_hour), ":", str(error_msg.tm_min)])
            error_msg ="".join(["Twitter API Request Rate Limit hit on ", error_msg, ", wait..."])
            print(error_msg)
            del error_msg
            del twapi
            sleep(901) #15min + 1sec

            #initializations
            if afternoon >= 7:
                afternoon =0

            sleep(nap[afternoon])
            afternoon = afternoon + 1
            twapi = Twython(app_key=app_key, app_secret=app_secret,
                        oauth_token=oauth_token, oauth_token_secret=oauth_token_secret)
            next_cursor = -1
            result = {}
            result["screen_name"] = ""
            result["followers"] = []
            iteration = 0
            file_name = ""

            #user info
            user = twapi.lookup_user(screen_name = account_name)

            #store user name
            result['screen_name'] = account_name

            #loop until all cursored results are stored
            while (next_cursor != 0):
                sleep(random.randrange(start = 1, stop = 15, step = 1))
                call_result = twapi.get_followers_ids(screen_name = account_name, cursor = next_cursor)
                #loop over each entry of followers id and append each entry to results_follower    
                for i in call_result["ids"]:
                    result["followers"].append(i)
                next_cursor = call_result["next_cursor"] #new next_cursor
                iteration = iteration + 1
                if (iteration > 13): #skip sleep if all cursored pages are processed
                    error_msg = localtime()
                    error_msg = "".join([str(error_msg.tm_mon), "/", str(error_msg.tm_mday), "/", str(error_msg.tm_year), " at ", str(error_msg.tm_hour), ":", str(error_msg.tm_min)])
                    error_msg = "".join(["Twitter API Request Rate Limit hit on ", error_msg, ", wait..."])
                    print(error_msg)
                    del error_msg
                    sleep(901) #15min + 1sec
                    iteration = 0

            #output file
            file_name = "".join([account_name, ".txt"])

            #print output
            out_file = open(file_name, "w") #open file "account_name.txt"
            #out_file.write(str(result["followers"])) #standard format
            for i in result["followers"]: #R friendly table format
                out_file.write(str(i))
                out_file.write("\n")
            out_file.close()

person mbiella    schedule 20.02.2017    source источник
comment
Какие значения в nap? Каково начальное значение afternoon? Вам нужно предоставить больше контекста, чтобы это было понятно.   -  person asongtoruin    schedule 20.02.2017
comment
nap = [1,2,4,8,16,32,64,128], а после полудня инициализируется 0 и при необходимости устанавливается обратно на 0. эта часть проверена, проблема в том, что, несмотря на то, что программа спит между каждым вызовом, сервер продолжает закрывать соединение   -  person mbiella    schedule 21.02.2017
comment
Почему вы используете такие короткие перерывы? Если это проблема ограничения скорости, то этих значений, вероятно, не будет достаточно, чтобы попасть в следующее окно, если похоже, ограничения указаны за 15-минутный период.   -  person asongtoruin    schedule 21.02.2017
comment
Кроме того, почему вы удаляете свое соединение каждые несколько секунд? Вы должны иметь возможность оставить соединение открытым, но, я думаю, подождите, чтобы сделать следующий запрос.   -  person asongtoruin    schedule 21.02.2017
comment
это не проблема RateLimit. чтобы моя функция не спала в течение 900 секунд (15 минут). у меня были проблемы с RateLimit, но я уже решил их. на этот раз проблема другого рода. возможно, твиттер-сервер рассматривает мои вызовы как атаку типа «отказ в обслуживании», поэтому я заставляю свою функцию спать в разные промежутки времени и удаляю соединение по той же причине (как предлагается здесь --> stackoverflow.com/questions/27333671/ )   -  person mbiella    schedule 21.02.2017
comment
Можете ли вы предоставить больше вашего кода? Из этого небольшого раздела трудно понять, что происходит.   -  person asongtoruin    schedule 21.02.2017
comment
@asongtoruin я добавил всю функцию. я знаю, что это выглядит плохо, но я новичок в мире python. Спасибо за помощь!   -  person mbiella    schedule 21.02.2017
comment
Вы случайно воспроизвели свой код при копировании (#initialisations и далее) или это действительно часть того, что вы написали?   -  person asongtoruin    schedule 21.02.2017
comment
Кроме того, вы уверены в использовании Twython? Я думаю, что Tweepy лучше справляется с курсорами, и я мог бы помочь вам лучше с этим.   -  person asongtoruin    schedule 21.02.2017
comment
я не случайно реплицировал инициализации, они на самом деле в коде. Я знаю, это совсем не элегантно! я предпочитаю использовать twython только потому, что использую его с самого начала, я не знаю различий между twython и tweepy. во всяком случае, я не понял, почему, даже если моя функция спит, у меня все еще есть эта гребаная ошибка! я буду плакать весь день!   -  person mbiella    schedule 22.02.2017
comment
Я думаю, что репликация вашей инициализации может быть причиной ошибки, даже если она спит - как только она попадает в RateLimitError в первый раз, в ней нет подвоха. Я разработал решение в Tweepy, которое сейчас только тестирую. Я дам вам знать, если оно сработает, если это поможет?   -  person asongtoruin    schedule 22.02.2017
comment
большое спасибо!! ваше решение обязательно будет полезным! дайте мне знать.   -  person mbiella    schedule 22.02.2017
comment
Вам нужны имена подписчиков или просто идентификаторы?   -  person asongtoruin    schedule 22.02.2017
comment
пока только идентификаторы. если нужно, позже я сам буду управлять именами пользователей...   -  person mbiella    schedule 22.02.2017


Ответы (1)


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

import tweepy
from datetime import datetime


def download_followers(user, api):
    all_followers = []
    try:
        for page in tweepy.Cursor(api.followers_ids, screen_name=user).pages():
            all_followers.extend(map(str, page))
        return all_followers
    except tweepy.TweepError:
        print('Could not access user {}. Skipping...'.format(user))

# Include your keys below:
consumer_key = 'YOUR_KEY'
consumer_secret = 'YOUR_KEY'
access_token = 'YOUR_KEY'
access_token_secret = 'YOUR_KEY'

# Set up tweepy API, with handling of rate limits
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
main_api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)

# List of usernames to get followers for
lookup_users = ['asongtoruin', 'mbiella']

for username in lookup_users:
    user_followers = download_followers(username, main_api)
    if user_followers:
        with open(username + '.txt', 'w') as outfile:
            outfile.write('\n'.join(user_followers))
        print('Finished outputting: {} at {}'.format(username, datetime.now().strftime('%Y/%m/%d %H:%M:%S')))

Tweepy достаточно умен, чтобы знать, когда он достиг предела скорости, когда мы используем wait_on_rate_limit=True, и проверяет, как долго ему нужно спать, прежде чем он сможет начать снова. Используя wait_on_rate_limit_notify=True, мы позволяем ему указать, как долго он будет ждать, пока он не сможет получить страницу подписчиков (с помощью этого метода на основе идентификатора кажется, что есть 5000 идентификаторов на страницу).

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

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

Rate limit reached. Sleeping for: 593
Finished outputting: asongtoruin at 2017/02/22 11:43:12
Could not access user mbiella. Skipping...

С идентификаторами подписчиков asongtoruin (он же я), сохраненными как asongtoruin.txt

Есть одна возможная проблема, заключающаяся в том, что наши страницы подписчиков начинаются с самых новых. Это может (хотя я недостаточно хорошо понимаю API, чтобы с уверенностью сказать) привести к проблемам с нашим выходным набором данных, если между нашими вызовами будут добавлены новые пользователи, поскольку мы можем как пропустить этих пользователей, так и закончить с дубликатами в нашем наборе данных. Если дубликаты становятся проблемой, вы можете изменить return all_followers на return set(all_followers).

person asongtoruin    schedule 22.02.2017
comment
О, и вы можете установить tweepy с pip install tweepy, как и ожидали. - person asongtoruin; 22.02.2017
comment
Замечательно!! я многому научился из вашего ответа (и объяснения)! большое спасибо @asongtoruin! - person mbiella; 22.02.2017
comment
@mbiella не волнуйся, приятель! Я тоже многое понял, изучая это, так что это помогло нам обоим :) - person asongtoruin; 22.02.2017