Streaming API Tweepy не распознает твиты с разных устройств.

Это действительно странный и конкретный вопрос. Я разрабатываю твиттер-бота, на который пользователи могут твитнуть цитаты, а бот, в свою очередь, будет принимать эти твиты и создавать вдохновляющую картинку, соответствующую их цитате. Так, например, я бы написал в Твиттере: @fake_quotes_bot «Я умру себя голодом, пока они не послушают» - Ганди. Что ж, тогда он берет эту цитату и человека рядом с дефисом и генерирует изображение.

Переходя от общих слов, я только что запрограммировал фильтр цитирования, чтобы бот мог получать котировки наиболее эффективным способом. Так, например, это бесполезно: @fake_quotes_bot "Привет, это" '"" цитата "- человек. В этом фильтре цитирования, если пользователь неправильно цитирует свой твит (как видно), мой бот автоматически ответит на инструкции о том, как правильно структурировать их твит. И после запуска бота в PyCharm на моем рабочем столе, а затем чириканья боту с другой учетной записью, все работает отлично. Сообщения об ошибках встречаются, и если твит правильно составлен, он одобряет Проблема возникает, однако, когда я затем отправляю твит с другого устройства, кроме настольного компьютера, на котором работает бот. Логика, которая, казалось бы, отлично работала, когда твиттер с рабочего стола, теперь не работает, когда получение твита, скажем, через iPhone. Независимо от того, какой твит я отправляю туда, бот получает одно и то же сообщение об ошибке.

Вот мой код:

import tweepy
import json

consumer_key, consumer_secret = ###, ###
access_token, access_token_secret = ###, ###

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)

api = tweepy.API(auth)


def Data_Analysis(tweet, tweet_data):
    def Data_Write():
        print("DATA FOR THIS TWEET:", tweet_data, "\n")

    def Quote_Filter():

        print("INCOMING TWEET: " + "  > " + str(tweet) + " <   " + " FROM: @" +
              str(tweet_data.get('user', '').get('screen_name', '')) + "/" + tweet_data.get('user', '').get('name', ''))

        def Profanity_Filter():
            pass

        def Person_Filter():
            #WIP for now
            print("Filtering people...", end=" ")
            print("SUCCESSFUL")
            print("APPROVED TWEET: " + tweet)
            print("APPROVED TWEET DATA:", tweet_data, "\n")

        def Quotation_Marks_Filter():

            print("Filtering quotation marks...", end=" ")

            # Filters out tweets that contain quotes
            if '"' in tweet or "'" in tweet:
                double_quote_count = tweet.count('"')
                single_quote_count = tweet.count("'")

                # Double Quotes quote
                if double_quote_count > 0 and single_quote_count == 0:
                    if double_quote_count > 2:
                        api.update_status("@" + str(tweet_data.get('user', '').get('screen_name', '')) +
                                          " ERROR: Please refrain from using too many quotation marks.",
                                          tweet_data.get('id'))

                        print("ERROR: Please refrain from using too many quotation marks. \n")
                    elif double_quote_count == 1:
                        api.update_status("@" + str(tweet_data.get('user', '').get('screen_name', '')) +
                                          " ERROR: Only a singular quote was entered.",
                                          tweet_data.get('id'))

                        print("ERROR: Only a singular quote was entered. \n")
                    # Pass through to other filter
                    else:
                        print("SUCCESSFUL")
                        Person_Filter()

                # Single quotes quote
                elif double_quote_count == 0 and single_quote_count > 0:
                    if single_quote_count > 2:
                        api.update_status("@" + str(tweet_data.get('user', '').get('screen_name', '')) +
                                          " ERROR: Please refrain from using too many quotation marks.",
                                          tweet_data.get('id'))

                        print("ERROR: Please refrain from using too many quotation marks. \n")
                    elif single_quote_count == 1:
                        api.update_status("@" + str(tweet_data.get('user', '').get('screen_name', '')) +
                                          " ERROR: Only a singular quote was entered.",
                                          tweet_data.get('id'))

                        print("ERROR: Only a singular quote was entered. \n")
                    # Pass through to other filter
                    else:
                        print("SUCCESSFUL")
                        Person_Filter()

                # If a quote has two types of quotes
                else:
                    # Filter if there are too many quotes per character
                    if double_quote_count > 2:
                        api.update_status("@" + str(tweet_data.get('user', '').get('screen_name', '')) +
                                          " ERROR: If you are implementing a quote within a quote or are abbreviating,"
                                          "please refrain from using more than two instances of a double quote."
                                          , tweet_data.get('id'))

                        print("ERROR: If you are implementing a quote within a quote or are abbreviating,"
                              "please refrain from using more than two instances of a double quote. \n")
                    elif double_quote_count == 1:
                        api.update_status("@" + str(tweet_data.get('user', '').get('screen_name', '')) +
                                          " ERROR: Could not identify the quote. If you are implementing a quote "
                                          "within a quote or are abbreviating,  please use two instances of the "
                                          "double quote.",
                                          tweet_data.get('id'))

                        print("ERROR: Could not identify the quote. If you are implementing a quote "
                              "within a quote or are abbreviating,  please use two instances of the "
                              "double quote. \n")

                    # If it's correct in its number, then figure out its beginning and ending quotes to pull text
                    else:
                        quote_indexes = []
                        quote_chars = []

                        indices = [index for index, value in enumerate(tweet) if value == '"']
                        for i in indices:
                            quote_indexes.append(i)
                            quote_chars.append('"')

                        indices = [index for index, value in enumerate(tweet) if value == "'"]
                        for i in indices:
                            quote_indexes.append(i)
                            quote_chars.append("'")

                        beginning_quote = quote_indexes.index(min(quote_indexes))
                        ending_quote = quote_indexes.index(max(quote_indexes))

                        # If the starting and ending quotes are similar (I.E. " and ") then pass through to other filter
                        if quote_chars[beginning_quote] == quote_chars[ending_quote]:
                            print("SUCCESSFUL")
                            Person_Filter()

                        # Do not align
                        else:
                            api.update_status("@" + str(tweet_data.get('user', '').get('screen_name', '')) +
                                              " ERROR: The beginning and endings quotes do not align.",
                                              tweet_data.get('id'))

                            print("ERROR: The beginning and endings quotes do not align. \n")

            # No quote found
            elif '"' or "'" not in tweet:
                grab_user = tweet_data.get('user', '').get('screen_name', '')

                if grab_user == "fake_quotes_bot":
                    # If I were to test this on my own twitter handle, it would get stuck in an auto-reply loop.
                    # Which will probably ban me.
                    print("PASSING UNDER MY OWN SCREEN NAME... \n")

                if grab_user != "fake_quotes_bot":
                    api.update_status("@" + str(tweet_data.get('user', '').get('screen_name', '')) +
                                      " ERROR: This tweet does not contain a quote. Be sure to use quotation marks.",
                                      tweet_data.get('id'))

                    print("ERROR: This tweet does not contain a quote. Be sure to use quotation marks. \n")

        def Retweet_Filter():

            print("Filtering retweets...", end=" ")

            # Filters out tweets that are retweets
            if "RT" in tweet[0:3]:
                print("RETWEET. SKIPPING... \n")
            else:
                print("SUCCESSFUL")
                Quotation_Marks_Filter()

        Retweet_Filter()

    Quote_Filter()


class StreamListener(tweepy.StreamListener):

    def on_data(self, data):
        tweet_data = json.loads(data)
        if "extended_tweet" in tweet_data:
            tweet = tweet_data['extended_tweet']['full_text']
            Data_Analysis(tweet, tweet_data)

        else:
            try:
                tweet = tweet_data['text']
                Data_Analysis(tweet, tweet_data)
            except KeyError:
                print("ERROR: Failed to retrieve tweet. \n")


print("BOT IS NOW RUNNING. SEARCHING FOR TWEETS...\n")

Listener = StreamListener()
Stream = tweepy.Stream(auth=api.auth, listener=Listener, tweet_mode='extended')
Stream.filter(track=['@fake_quotes_bot'])

Вывод твита с того же рабочего стола:

INCOMING TWEET:   > @fake_quotes_bot "hello, stackoverflow!" <    FROM: @bulletinaction/BulletInAction
Filtering retweets... SUCCESSFUL
Filtering quotation marks... SUCCESSFUL
Filtering people... SUCCESSFUL
APPROVED TWEET: @fake_quotes_bot "hello, stackoverflow!"
APPROVED TWEET DATA: {###data###} 

Выведите, если бы я отправил твит через свой телефон:

INCOMING TWEET:   > @fake_quotes_bot “heyyo, stackoverflow” <    FROM: @bulletinaction/BulletInAction
Filtering retweets... SUCCESSFUL
Filtering quotation marks... ERROR: This tweet does not contain a quote. Be sure to use quotation marks. 

Вот видео на YouTube с запущенным кодом, поскольку я уверен, что это очень странный вопрос: https://www.youtube.com/watch?v=skErnva4ePc&feature=youtu.be


person BulletInAction    schedule 23.05.2018    source источник


Ответы (1)


В вашем телефоне вместо кавычек используются двойные кавычки слева и справа:

"   U+0022 QUOTATION MARK
“   U+201C LEFT DOUBLE QUOTATION MARK
”   U+201D RIGHT DOUBLE QUOTATION MARK

(от: Есть разные типы двойных кавычек в utf-8 (PHP, str_replace)?)

Так что просто замените текст твита перед тестами:

tweet = tweet_data['extended_tweet']['full_text'] # as you did, then :
tweet = tweet.replaceAll("[\\u2018\\u2019]", "'")
tweet = tweet.replaceAll("[\\u201C\\u201D]", "\"");

(от: Преобразование цитат и апострофов слов MS)

person JeffProd    schedule 23.05.2018
comment
Большое спасибо. Зная предоставленную вами информацию (что цитаты имеют около 10-20 различных применений в Unicode по сравнению со стандартными кавычками ASCII), я немного покопался и обнаружил unidecode библиотеки. Просто передавая tweet: tweet = unidecode (tweet), он преобразует любые проблемные символы Unicode в стандартный ASCII, чтобы затем следовать моей логике. - person BulletInAction; 24.05.2018