Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.9k views
in Technique[技术] by (71.8m points)

python - KeyError During Twitter Filtered Stream Using Tweepy

I am currently running into a KeyError issue that I cannot figure out in the below code. The aim of the programme is to stream a particular users tweets using Tweepy and then send an email containing that tweet whenever those users post about a specified keyword. It has been working perfectly and has been receiving a number of tweets and sending the emails however every now and then it throw up this error: KeyError: 'user' relating to the line: 'Identity': data['user']['screen_name']

The error is listed below the code for reference. I'm sure I can use the .get() function somewhere or even use an except to try and handle the KeyError but I cannot figure out how to do this in my codes context?

import json
import yaml


from tweepy import API, OAuthHandler, Stream, StreamListener

from emailService import Email

consumer_key = ''
consumer_secret = ''
access_token = ''
access_token_secret = ''
recipient_email = ''

with open("config.yaml", 'r') as stream:
    config = yaml.safe_load(stream)


class StdOutListener(StreamListener):
    """ A listener handles tweets that are received from the stream.
    This is a basic listener that just prints received tweets to stdout.
    """
    def __init__(self, config):
        super().__init__()
        self.config = config

    def on_status(self, status):

        data = json.loads(status)


        try:
            extended = data['extended_tweet']

            tweetData = {
                'Identity': data['user']['screen_name'],
                'message': extended['full_text'],
                'urls': list(map(lambda url: url['expanded_url'], data['entities']['urls']))
            }

        except:

            tweetData = {
                'Identity': data['user']['screen_name'],
                'message': data['text'],
                'urls': list(map(lambda url: url['expanded_url'], data['entities']['urls']))
            }

        return tweetData

    def _sendEmail(self, tweetData):
        subject = f'Twitter Keyword Match: {tweetData["Identity"]}'
        message = self._composeEmailMessage(tweetData)

        Email().send(recipient_email, subject, message)


    def _composeEmailMessage(self, tweetData):
        message = f'''
New Twitter Keyword Match:

@{tweetData['Identity']}: {tweetData["message"]}

'''

        for url in tweetData['urls']:
            message += url + '
'

        return message

    def on_data(self, data):
        tweetData = self.on_status(data)
        print(f'@{tweetData["Identity"]} tweeted: {tweetData["message"]}
')

        if tweetData['Identity'] in self.config:
            matchedWords = [keyword for keyword in self.config[tweetData['Identity']] if keyword in tweetData['message']]

            if len(matchedWords):
                print(matchedWords, 'Keyword match found. Sending email.
')
                self._sendEmail(tweetData)

        return True

    def on_error(self, status):
        print('STREAM ERROR:', status)


class TwitterAlerts:
    def __init__(self, config):
        self.config = config
        self.auth = self._createAuth()
        self.api = API(self.auth)
        self.stream = self._createStream(config)

        self.generateInitMsg()

    def generateInitMsg(self):
        maxUsernameLen = len(max(list(self.config.keys()) + ['USERNAME'], key = len))
        print('Twitter keyword alert service initialized
')
        print('USERNAME', ' '*(maxUsernameLen - 8), ':', "[KEYWORDS]")
        for username, keywords in self.config.items():
            print(username, ' '*(maxUsernameLen - len(username)), ':', keywords)
        print('')

    def _createAuth(self):
        auth = OAuthHandler(consumer_key, consumer_secret)
        auth.set_access_token(access_token, access_token_secret)
        return auth

    def getUser(self, username):
        return self.api.get_user(username)

    def _createStream(self, config):
        listener = StdOutListener(config)
        return Stream(self.auth, listener)

    def startFilter(self):
        # convert usernames to ids
        userIds = list(map(lambda username: str(self.getUser(username).id), self.config.keys()))
        # create listener for all userids in config
        self.stream.filter(follow = userIds)


TwitterAlerts(config['usernames']).startFilter()

Error: Traceback (most recent call last): File "/Users/CraftyBadger/Desktop/PycharmProjects/TwitterUserKeywordAlertMonitor/index.py", line 33, in on_status extended = data['extended_tweet'] KeyError: 'extended_tweet'

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/six.py", line 703, in reraise raise value File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/tweepy/streaming.py", line 289, in _run self._read_loop(resp) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/tweepy/streaming.py", line 351, in _read_loop self._data(next_status_obj) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/tweepy/streaming.py", line 323, in _data if self.listener.on_data(data) is False: File "/Users/CraftyBadger/Desktop/PycharmProjects/TwitterUserKeywordAlertMonitor/index.py", line 70, in on_data tweetData = self.on_status(data) File "/Users/CraftyBadger/Desktop/PycharmProjects/TwitterUserKeywordAlertMonitor/index.py", line 44, in on_status 'Identity': data['user']['screen_name'], KeyError: 'user'


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神解答

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...