Skip to content

Commit 4a3b432

Browse files
committed
Chapter 13 Examples Updated for the Twitter v2 APIs
Both the v1.1 and v2 examples are posted and the folder names are updated accordingly.
1 parent ef249c1 commit 4a3b432

File tree

91 files changed

+8019
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+8019
-0
lines changed
File renamed without changes.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Upgrading from Twitter v1.1 to Twitter v2
2+
3+
On August 18, 2022, we discovered that **new** Twitter developer accounts cannot access the Twitter version 1.1 APIs on which we based Chapter 13, Data Mining Twitter, and two case studies in Chapter 17, Big Data: Hadoop, Spark, NoSQL and IoT.
4+
5+
Twitter users who already had Twitter developer accounts can still access the Twitter version 1.1 APIs, but most students and some instructors will not fall into this category.
6+
7+
We’ve already rewritten Chapter 13 to the Twitter version 2 APIs and will be rewriting the two Twitter-based Chapter 17 case studies soon.
8+
9+
The updated chapter is posted on the book's webpage:
10+
https://deitel.com/intro-to-python-for-computer-science-and-data-science/
11+
12+
Once completed, we’ll post updated versions of:
13+
* the Chapter 17 Twitter-based case studies
14+
* the instructor materials to the Pearson Instructor Resource Center (IRC), which is accessible only to qualified instructors.
15+
16+
Questions? Please email [email protected].
File renamed without changes.
File renamed without changes.
File renamed without changes.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Upgrading from Twitter v1.1 to Twitter v2
2+
3+
On August 18, 2022, we discovered that **new** Twitter developer accounts cannot access the Twitter version 1.1 APIs on which we based Chapter 13, Data Mining Twitter, and two case studies in Chapter 17, Big Data: Hadoop, Spark, NoSQL and IoT.
4+
5+
Twitter users who already had Twitter developer accounts can still access the Twitter version 1.1 APIs, but most students and some instructors will not fall into this category.
6+
7+
We’ve already rewritten Chapter 13 to the Twitter version 2 APIs and will be rewriting the two Twitter-based Chapter 17 case studies soon.
8+
9+
The updated chapter is posted on the book's webpage:
10+
https://deitel.com/intro-to-python-for-computer-science-and-data-science/
11+
12+
Once completed, we’ll post updated versions of:
13+
* the Chapter 17 Twitter-based case studies
14+
* the instructor materials to the Pearson Instructor Resource Center (IRC), which is accessible only to qualified instructors.
15+
16+
Questions? Please email [email protected].

examples/ch13_TwitterV2/keys.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bearer_token = 'YourBearerToken'
2+
mapquest_key = 'YourAPIKey'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# locationlistener.py
2+
"""Receives tweets matching a search string and stores a list of
3+
dictionaries containing each tweet's username/text/location."""
4+
import tweepy
5+
from tweetutilities import get_tweet_content
6+
7+
class LocationListener(tweepy.StreamingClient):
8+
"""Handles incoming Tweet stream to get location data."""
9+
10+
def __init__(self, bearer_token, counts_dict,
11+
tweets_list, topic, limit=10):
12+
"""Configure the LocationListener."""
13+
self.tweets_list = tweets_list
14+
self.counts_dict = counts_dict
15+
self.topic = topic
16+
self.TWEET_LIMIT = limit
17+
super().__init__(bearer_token, wait_on_rate_limit=True)
18+
19+
def on_response(self, response):
20+
"""Called when Twitter pushes a new tweet to you."""
21+
22+
# get tweet's username, text and location
23+
tweet_data = get_tweet_content(response)
24+
25+
# ignore retweets and tweets that do not contain the topic
26+
if (tweet_data['text'].startswith('RT') or
27+
self.topic.lower() not in tweet_data['text'].lower()):
28+
return
29+
30+
self.counts_dict['total_tweets'] += 1 # it's an original tweet
31+
32+
# ignore tweets with no location
33+
if not tweet_data.get('location'):
34+
return
35+
36+
self.counts_dict['locations'] += 1 # user account has location
37+
self.tweets_list.append(tweet_data) # store the tweet
38+
print(f"{tweet_data['username']}: {tweet_data['text']}\n")
39+
40+
# if TWEET_LIMIT is reached, terminate streaming
41+
if self.counts_dict['locations'] == self.TWEET_LIMIT:
42+
self.disconnect()
43+
44+
45+
46+
##########################################################################
47+
# (C) Copyright 2022 by Deitel & Associates, Inc. and #
48+
# Pearson Education, Inc. All Rights Reserved. #
49+
# #
50+
# DISCLAIMER: The authors and publisher of this book have used their #
51+
# best efforts in preparing the book. These efforts include the #
52+
# development, research, and testing of the theories and programs #
53+
# to determine their effectiveness. The authors and publisher make #
54+
# no warranty of any kind, expressed or implied, with regard to these #
55+
# programs or to the documentation contained in these books. The authors #
56+
# and publisher shall not be liable in any event for incidental or #
57+
# consequential damages in connection with, or arising out of, the #
58+
# furnishing, performance, or use of these programs. #
59+
##########################################################################
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# sentimentlisener.py
2+
"""Searches for tweets that match a search string and tallies
3+
the number of positive, neutral and negative tweets."""
4+
import keys
5+
import preprocessor as p
6+
import sys
7+
from textblob import TextBlob
8+
import tweepy
9+
10+
class SentimentListener(tweepy.StreamingClient):
11+
"""Handles incoming Tweet stream."""
12+
13+
def __init__(self, bearer_token, sentiment_dict, topic, limit=10):
14+
"""Configure the SentimentListener."""
15+
self.sentiment_dict = sentiment_dict
16+
self.tweet_count = 0
17+
self.topic = topic
18+
self.TWEET_LIMIT = limit
19+
20+
# set tweet-preprocessor to remove URLs/reserved words
21+
p.set_options(p.OPT.URL, p.OPT.RESERVED)
22+
super().__init__(bearer_token, wait_on_rate_limit=True)
23+
24+
def on_response(self, response):
25+
"""Called when Twitter pushes a new tweet to you."""
26+
27+
# if the tweet is not a retweet
28+
if not response.data.text.startswith('RT'):
29+
text = p.clean(response.data.text) # clean the tweet
30+
31+
# ignore tweet if the topic is not in the tweet text
32+
if self.topic.lower() not in text.lower():
33+
return
34+
35+
# update self.sentiment_dict with the polarity
36+
blob = TextBlob(text)
37+
if blob.sentiment.polarity > 0:
38+
sentiment = '+'
39+
self.sentiment_dict['positive'] += 1
40+
elif blob.sentiment.polarity == 0:
41+
sentiment = ' '
42+
self.sentiment_dict['neutral'] += 1
43+
else:
44+
sentiment = '-'
45+
self.sentiment_dict['negative'] += 1
46+
47+
# display the tweet
48+
username = response.includes['users'][0].username
49+
print(f'{sentiment} {username}: {text}\n')
50+
51+
self.tweet_count += 1 # track number of tweets processed
52+
53+
# if TWEET_LIMIT is reached, terminate streaming
54+
if self.tweet_count == self.TWEET_LIMIT:
55+
self.disconnect()
56+
57+
def main():
58+
# get search term and number of tweets
59+
search_key = sys.argv[1]
60+
limit = int(sys.argv[2]) # number of tweets to tally
61+
62+
# set up the sentiment dictionary
63+
sentiment_dict = {'positive': 0, 'neutral': 0, 'negative': 0}
64+
65+
# create the StreamingClient subclass object
66+
sentiment_listener = SentimentListener(keys.bearer_token,
67+
sentiment_dict, search_key, limit)
68+
69+
# redirect sys.stderr to sys.stdout
70+
sys.stderr = sys.stdout
71+
72+
# delete existing stream rules
73+
rules = sentiment_listener.get_rules().data
74+
rule_ids = [rule.id for rule in rules]
75+
sentiment_listener.delete_rules(rule_ids)
76+
77+
# create stream rule
78+
sentiment_listener.add_rules(
79+
tweepy.StreamRule(f'{search_key} lang:en'))
80+
81+
# start filtering English tweets containing search_key
82+
sentiment_listener.filter(expansions=['author_id'])
83+
84+
print(f'Tweet sentiment for "{search_key}"')
85+
print('Positive:', sentiment_dict['positive'])
86+
print(' Neutral:', sentiment_dict['neutral'])
87+
print('Negative:', sentiment_dict['negative'])
88+
89+
# call main if this file is executed as a script
90+
if __name__ == '__main__':
91+
main()
92+
93+
##########################################################################
94+
# (C) Copyright 2022 by Deitel & Associates, Inc. and #
95+
# Pearson Education, Inc. All Rights Reserved. #
96+
# #
97+
# DISCLAIMER: The authors and publisher of this book have used their #
98+
# best efforts in preparing the book. These efforts include the #
99+
# development, research, and testing of the theories and programs #
100+
# to determine their effectiveness. The authors and publisher make #
101+
# no warranty of any kind, expressed or implied, with regard to these #
102+
# programs or to the documentation contained in these books. The authors #
103+
# and publisher shall not be liable in any event for incidental or #
104+
# consequential damages in connection with, or arising out of, the #
105+
# furnishing, performance, or use of these programs. #
106+
##########################################################################

0 commit comments

Comments
 (0)