Search Tweets¶

This project is inspired and led by "How to analyze the sentiment of your own Tweets" by Jessica Garson!

In this project, we pulls the Tweets from a certain Twitter account from the past 7 days and gives you a score to let you know exactly how his/her week has been.

In [1]:
import requests
import pandas as pd
import json
import ast
import yaml

# Before you can connect the Twitter API, 
# you’ll need to set up the URL to ensure it has the right fields so you get the right data back. 
# you can get the particular endpoint on https://developer.twitter.com/en/docs/twitter-api/search-overview
# we are using Recent Search Endpoint for the tweets from specific account on the past 7 days 
def create_twitter_url(handle):         # the parameter handle here is the account username
    max_results = 100
    mrf = "max_results={}".format(max_results)
    q = "query=from:{}".format(handle)
    url = "https://api.twitter.com/2/tweets/search/recent?tweet.fields=lang&{}&{}".format(mrf, q)
    return url

# To access the configuration file you created while setting up config.yaml
def process_yaml():
    with open("config.yaml") as file:
        return yaml.safe_load(file)

# To access the bearer token from your config.yaml file
def create_bearer_token(data):
    return data["search_tweets_v2"]["bearer_token"]

# To format the headers to pass in your bearer_token and url
def twitter_auth_and_connect(bearer_token, url):
    headers = {"Authorization": "Bearer {}".format(bearer_token)}
    response = requests.request("GET", url, headers=headers)
    if response.status_code != 200:
        raise Exception(response.status_code, response.text)
    return response.json()

def no_tweets(res_json):
    if res_json == {"meta": {"result_count": 0}}:
        print("The Twitter handle entered hasn't Tweeted in 7 days.")

def connect_to_azure(data):
    # you can find the endpoint url in your azure project
    azure_url = "https://senti-on-tweet.cognitiveservices.azure.com/" 
    sentiment_url = "{}text/analytics/v2.1/sentiment".format(azure_url)
    # the subscription key we are using here is the API key
    subscription_key = data["azure"]["subscription_key"]
    return sentiment_url, subscription_key

def azure_header(subscription_key):
    return {"Ocp-Apim-Subscription-Key": subscription_key}

def create_document_format(res_json):
    data_only = res_json["data"]
    doc_start = '"documents": {}'.format(data_only)
    str_json = "{" + doc_start + "}"
    dump_doc = json.dumps(str_json)
    doc = json.loads(dump_doc)
    return ast.literal_eval(doc)

def sentiment_scores(headers, sentiment_url, document_format):
    response = requests.post(sentiment_url, headers=headers, json=document_format)
    return response.json()

def mean_score(sentiments):
    sentiment_df = pd.DataFrame(sentiments["documents"])
    return sentiment_df["score"].mean()

def week_logic(week_score):
    if week_score > 0.75 or week_score == 0.75:
        print("This account had a positive week")
    elif week_score > 0.45 or week_score == 0.45:
        print("This account had a neautral week")
    else:
        print("This account had a negative week, I hope it gets better")


# select the paragraph, CTRL + / to (un)comment out the function(s)        
# This is an testing function for providing example results to help you understand the result

def analysis(handle):
    url = create_twitter_url(handle)
    data = process_yaml()
    bearer_token = create_bearer_token(data)
    res_json = twitter_auth_and_connect(bearer_token, url)
    no_tweets(res_json)
    sentiment_url, subscription_key = connect_to_azure(data)
    headers = azure_header(subscription_key)
    document_format = create_document_format(res_json)
    sentiments = sentiment_scores(headers, sentiment_url, document_format)
    week_score = mean_score(sentiments)
    data = pd.DataFrame.from_dict(res_json['data'])
    print("Base on the ", data.shape[0], "tweets this account post from past 7 days, we get a score of ", week_score)
    week_logic(week_score)
    return data



# def main():
#     handle = input("Enter Account Username: ")
#     url = create_twitter_url(handle)
#     data = process_yaml()
#     bearer_token = create_bearer_token(data)
#     res_json = twitter_auth_and_connect(bearer_token, url)
#     no_tweets(res_json)
#     sentiment_url, subscription_key = connect_to_azure(data)
#     headers = azure_header(subscription_key)
#     document_format = create_document_format(res_json)
#     sentiments = sentiment_scores(headers, sentiment_url, document_format)
#     week_score = mean_score(sentiments)
#     print("Base on the ", pd.DataFrame.from_dict(res_json['data']).shape[0], "tweets this account post from past 7 days, we get a score of ", week_score)
#     week_logic(week_score)

# if __name__ == "__main__":
#     main()

There are some examples for you to understand what the result you be

In [ ]:
main()

If you want to digging more about the company, you can uncomment the analysis function and comment the main function.

In [3]:
# settings for the pandas expression
pd.set_option('display.max_colwidth', None)

PUMA Sentiment Analysis¶

In [4]:
puma = analysis("PUMA")
puma
Base on the  25 tweets this account post from past 7 days, we get a score of  0.6810827732086182
This account had a neautral week
Out[4]:
id lang text
0 1428060567428812800 und @EmlynBegley 🤝
1 1427747052474281993 en RT @jgault13: This is awesome. What began as a $4,761 donation has now ballooned to eight times that amount thanks to a number of generous…
2 1427746996023144459 en RT @fast_women: Nope, that wasn't the last update. @puma has agreed to match the donation, so Molly Seidel's run at the @FalmouthRR raised…
3 1427746979661107205 en RT @fast_women: Olympic medalist Molly Seidel served as the starter at today's Falmouth Road Race, and then began the race in last place. F…
4 1427746676358488064 en Last weekend, @ByGollyMolly12 raised $19,044 for @TommysPlace_ by passing 4,761 runners after starting at the very back of the @FalmouthRR. One week after THAT RACE, too 🤯 We're so proud of you Molly – we’ll match the donation to support such an amazing cause. #PUMAFam https://t.co/CMFDxTOffR
5 1427568600454508548 und RT @therealshammgod: 8/21 https://t.co/qfTVLPjzNZ
6 1427292438356545536 en 🖤🤍 @dualipa in the new Suede Mayu 🖤🤍 https://t.co/dQ1ScbqmxY
7 1427276317259706377 en Greatest. Of. All. Time. 🐐 @usainbolt https://t.co/DVxafLzGeB
8 1427187289709481984 en RT @DUALIPA: The latest from @PUMA . New Mayu out tomorrow 🖤 shot by Mario Sorrenti #ad https://t.co/70dLcMYUdH
9 1426983973922693120 en RT @erinasimon: Glad you like our @PUMA RKDO gift package @sjokz!\n\nAppreciate you and thank you for being an awesome esports rep 🔥😃🙌🏽 https…
10 1426950822924111880 und @LILCOBEY 🤝 #PUMAFam
11 1426950461198938113 und #SuedeSunday @MELOD1P 🛸💕 https://t.co/9MmkxeWkqx
12 1426948450361483272 en RT @Oratile011: Top 5 Greatest silhouette ever.
13 1426901382976741377 en Beautiful from every angle 🧡 #SuedeSunday\n📷: formstripes (IG) https://t.co/YaMCoX7sBL
14 1426892392347676672 en RT @HotFreestyle: Nipsey Hussle would’ve been 36 years old today, Happy Birthday & Rest In Peace 🙏🏽🕊🏁 https://t.co/grD03FIVng
15 1426892327377833985 en RT @Genius: reminder from nipsey: you're supposed to be here. #verified https://t.co/KOvUz4ZPzI
16 1426578192219914242 en RT @Kgudie_: Okay my baby just got here 😭😭🤍🤍 https://t.co/VFWZ5qhgp6
17 1426552524199366659 en @iLOVEnewyork83 @andreagrimes Worth it 💚
18 1426543456038658048 en Marble Suede lowkey fire. Michaelangelo where you at? https://t.co/hwonVWM0vD
19 1426483722627559424 en RT @WSeriesRacing: 🔍 a woman's place is 𝐢𝐧 𝐦𝐨𝐭𝐨𝐫𝐬𝐩𝐨𝐫𝐭
20 1426185376809558017 ru PUMA Wild Rider в действии. Движение и бесконечная энергия города в твоих Wild Rider 🤸‍♂️
21 1426084341331988481 ru Задай темп этой игре, оставив соперника ни с чем с ULTRA 1.3 и FUTURE Z 1.2 💥
22 1426083687586832387 ru PUMA Faster Football – это свобода передвижения на поле, чтобы твоя игра была максимально динамичной ⚡
23 1425873053259534339 en PUMA FAM BRINGING HOME THOSE MEDALS. #OnlySeeGreat https://t.co/dlj3EkUkpf
24 1425819369456640002 en 🖤🤍 @dannapaola in Mayze\nhttps://t.co/MsygWDlljW https://t.co/lk2ufCCVOv
In [4]:
text_puma = puma[puma['lang']=='en'].drop(['id', 'lang'], axis=1).drop_duplicates('text')
text_puma.count()
text_puma
Out[4]:
text
0 🖤🤍 @dualipa in the new Suede Mayu 🖤🤍 https://t.co/dQ1ScbqmxY
1 Greatest. Of. All. Time. 🐐 @usainbolt https://t.co/DVxafLzGeB
2 RT @DUALIPA: The latest from @PUMA . New Mayu out tomorrow 🖤 shot by Mario Sorrenti #ad https://t.co/70dLcMYUdH
3 RT @erinasimon: Glad you like our @PUMA RKDO gift package @sjokz!\n\nAppreciate you and thank you for being an awesome esports rep 🔥😃🙌🏽 https…
6 RT @Oratile011: Top 5 Greatest silhouette ever.
7 Beautiful from every angle 🧡 #SuedeSunday\n📷: formstripes (IG) https://t.co/YaMCoX7sBL
8 RT @HotFreestyle: Nipsey Hussle would’ve been 36 years old today, Happy Birthday & Rest In Peace 🙏🏽🕊🏁 https://t.co/grD03FIVng
9 RT @Genius: reminder from nipsey: you're supposed to be here. #verified https://t.co/KOvUz4ZPzI
10 RT @Kgudie_: Okay my baby just got here 😭😭🤍🤍 https://t.co/VFWZ5qhgp6
11 @iLOVEnewyork83 @andreagrimes Worth it 💚
12 Marble Suede lowkey fire. Michaelangelo where you at? https://t.co/hwonVWM0vD
13 RT @WSeriesRacing: 🔍 a woman's place is 𝐢𝐧 𝐦𝐨𝐭𝐨𝐫𝐬𝐩𝐨𝐫𝐭
17 PUMA FAM BRINGING HOME THOSE MEDALS. #OnlySeeGreat https://t.co/dlj3EkUkpf
18 🖤🤍 @dannapaola in Mayze\nhttps://t.co/MsygWDlljW https://t.co/lk2ufCCVOv
19 RT @Bratz: Thursday! 👄👟 @PUMA #bratz https://t.co/vdGDnOExSH
20 RT @Babyyhairz: The Hussle Way \n“Miami Story” August 13\n@PUMA x @themarathonclothing https://t.co/zuWagsy0Yk
22 RT @brkicks: First look at LaMelo Ball’s first signature shoe with Puma called the MB1 😮 @NickDePaula https://t.co/AKzCYxdh6l
23 RT @NickDePaula: The Puma Jet — the brand’s private plane for its athletes — is still one of the best endorsement perks out. \n\nHere’s how L…
In [5]:
retweets_puma = text_puma[text_puma['text'].str.contains('RT')]
retweets_puma
Out[5]:
text
2 RT @DUALIPA: The latest from @PUMA . New Mayu out tomorrow 🖤 shot by Mario Sorrenti #ad https://t.co/70dLcMYUdH
3 RT @erinasimon: Glad you like our @PUMA RKDO gift package @sjokz!\n\nAppreciate you and thank you for being an awesome esports rep 🔥😃🙌🏽 https…
6 RT @Oratile011: Top 5 Greatest silhouette ever.
8 RT @HotFreestyle: Nipsey Hussle would’ve been 36 years old today, Happy Birthday & Rest In Peace 🙏🏽🕊🏁 https://t.co/grD03FIVng
9 RT @Genius: reminder from nipsey: you're supposed to be here. #verified https://t.co/KOvUz4ZPzI
10 RT @Kgudie_: Okay my baby just got here 😭😭🤍🤍 https://t.co/VFWZ5qhgp6
13 RT @WSeriesRacing: 🔍 a woman's place is 𝐢𝐧 𝐦𝐨𝐭𝐨𝐫𝐬𝐩𝐨𝐫𝐭
19 RT @Bratz: Thursday! 👄👟 @PUMA #bratz https://t.co/vdGDnOExSH
20 RT @Babyyhairz: The Hussle Way \n“Miami Story” August 13\n@PUMA x @themarathonclothing https://t.co/zuWagsy0Yk
22 RT @brkicks: First look at LaMelo Ball’s first signature shoe with Puma called the MB1 😮 @NickDePaula https://t.co/AKzCYxdh6l
23 RT @NickDePaula: The Puma Jet — the brand’s private plane for its athletes — is still one of the best endorsement perks out. \n\nHere’s how L…

PATAGONIA Sentiment Analysis¶

In [4]:
# Pull out all the tweets for Patagonia in last 7 days
patagonia = analysis("patagonia")
patagonia
Base on the  63 tweets this account post from past 7 days, we get a score of  0.7208683774584815
This account had a neautral week
Out[4]:
id lang text
0 1428479629480890379 en Join Patagonia grantees @CAUSE805 and @CFROG_vc for a community meeting on August 21st to stop the expansion of a toxic natural gas compressor station in Ventura.
1 1428427233568251905 en @Nirwin_Images Sorry to hear you're disappointed by the current hat selection and color preferences. We'll let our designers know, and hopefully you'll find one you like in the future!
2 1428348017568927750 en @gianluto Hello, we are incredibly sorry to hear about the issues you are having. Would you please DM us with your order number and email so we can look into this for you? https://t.co/BQQTdfLPtb
3 1428128460237463553 en Run to: A film series about runners finding activism through sport.\n\nWatch the first episode: Corriendo Para Salvar Una Cuenca | Run To Save a Watershed: https://t.co/MBwrfmKySF https://t.co/j0uU8VHza0
4 1428118862973739009 en @attamusk You'll find our Back For Good wolf hat here: https://t.co/6eTieEDiTy
... ... ... ...
58 1425961595214069762 en Cozy sweatshirts made with soft, Regenerative Organic Certified™ Pilot Cotton. Built to last for seasons to come.
59 1425961542969790464 en Cozy sweatshirts made with soft, Regenerative Organic Certified™ Pilot Cotton. Built to last for seasons to come.
60 1425961483087749122 en Cozy sweatshirts made with soft, Regenerative Organic Certified™ Pilot Cotton. Built to last for seasons to come.
61 1425961399704985606 en Cozy sweatshirts made with soft, Regenerative Organic Certified™ Pilot Cotton. Built to last for seasons to come.
62 1425961325335781376 en Cozy sweatshirts made with soft, Regenerative Organic Certified™ Pilot Cotton. Built to last for seasons to come.

63 rows × 3 columns

In [5]:
text_patagonia = patagonia.drop(['id', 'lang'], axis=1).drop_duplicates('text')
text_patagonia.count()
Out[5]:
text    52
dtype: int64
In [6]:
Social_Good = text_patagonia[text_patagonia['text'].str.contains('protect|help|environment')]
print(Social_Good.count())
Social_Good
text    9
dtype: int64
Out[6]:
text
11 Patagonia grantee @waterfirstngo collaborates with Indigenous communities in Canada to address critical water challenges. Click to learn how they are creating solutions to sustain access to clean water and how you can help support their work.
12 Patagonia grantee @waterfirstngo collaborates with Indigenous communities in Canada to address critical water challenges. Click to learn how they are creating solutions to sustain access to clean water and ways you can help support their work.
18 Join Patagonia grantee @Savannainst and their partners on August 21st for a field day at the Memorial 4H Camp Demonstration Farm. Learn about agroforestry techniques for building soil health, protecting water quality, enhancing wildlife habitat and diversifying profits.
19 Take action with Patagonia @TheNationsRiver to help ensure a resilient and just future for communities across the nation. Call on federal leaders to invest in clean water, green jobs and nature-based infrastructure.
24 Take action with Patagonia grantee @CalWild as they work to ensure that 30% of California's lands and waters are protected by 2030.
39 Join Patagonia grantee @UM_Waterkeeper in calling on Montana leaders to protect the state's cold water fisheries for future generations. Click to add your voice.
44 @MariannaFila HI Marianna, we use OnTrac because it helps meet our customers' needs and it is more sustainable to use local shipping options per region. If you currently having issues with one of your orders delivering with OnTrac, DM us so we can help fix the situation! https://t.co/BQQTdfLPtb
45 Is donating clothes actually helpful? Many shelters in your town will take clothing donations. But they don't want to be burdened with donations that aren't clean or useful. Comics journalist Sarah Mirk learns how to donate with dignity: https://t.co/kj4VoNEqwR https://t.co/WaOMSj0kX1
49 @MackFordFan98 Perfect, we are incredibly happy to hear that Mack! If you have any questions or concerns during the exchange process, please let us know and we will be more than happy to help. 😊
In [11]:
retweets_patagonia = text_patagonia[text_patagonia['text'].str.contains('RT')]
retweets_patagonia
Out[11]:
text
3 RT @conservationall: Did you miss last week's Conservation Alliance Breakfast? You can still watch or share the recorded event. Tune in now…
35 RT @FightFossils: Biden could cancel Formosa’s permit with the stroke of a pen. \n\n@POTUS, save our lives from the industry that's poisoning…
In [8]:
reply = text_patagonia[text_patagonia['text'].str.contains('Hi|Thank you|Hey|Sorry|sorry')]
print(reply.count())
reply
text    15
dtype: int64
Out[8]:
text
1 @Nirwin_Images Sorry to hear you're disappointed by the current hat selection and color preferences. We'll let our designers know, and hopefully you'll find one you like in the future!
2 @gianluto Hello, we are incredibly sorry to hear about the issues you are having. Would you please DM us with your order number and email so we can look into this for you? https://t.co/BQQTdfLPtb
10 @mrBriskly Hey Phil, thanks for reaching out. We have a filter on our website that allows you to search for specific materials, you can select cotton or hemp for example. We have the Men's Long-Sleeved Work Henley Pocket Tee which is a hemp/cotton blend. DM us for more suggestions! https://t.co/BQQTdfLPtb
28 @sarahjeanefink We're sorry we don't currently have what you're looking for. Each season we increase the number of styles with additional size range. Please reach out to us in a DM with more specifics that we can pass along to our product designers. We'd love to hear from you! https://t.co/BQQTdfLPtb
30 Sam doesn’t consider himself a great baker or a cyclist. So why did he join his friends to start Bread Bike, a bicycle-delivery breadmaking business in San Luis Obispo? His reasons are deliciously unexpected. https://t.co/XnIhbXlM2E https://t.co/CAjgwJSPkI
33 @Ryan32198411 Thank you so much for your feedback and suggestions Ryan, we truly appreciate it! We will ensure this gets passed along to our Product Design Team so they are aware there is a need/want for these hats.
34 @insanitynow5 Hey Billy! The Interstate Trucker Hats are pretty rad. Items are sometimes reintroduced back into our line and customer feedback is one of the contributing factors towards such decisions. Your comments have been passed along your comments to our Design Team.
37 @ThomasKHuddles2 We're so sorry to see this error! Please reach out to us in a DM so that we can get you fixed up right away. https://t.co/BQQTdfLPtb
41 @dezeerae Hi Des, we're sorry to hear about the disappointment with sizing. We know that sizing has not been inclusive and we're working each season to expand our product sizing to outfit a wider range of body types. You can see what we have available here, https://t.co/Vbs9sIQApT.
42 @ckmcdkc Hey Courtney! It's a super rad hoody, right?! That is our new Regenerative Organic Cotton Essential Hoody. It is expected to launch online in early September so check out https://t.co/qXNsy9NEuR around then.
43 @ThatVatoJules Hi Julio, we're so sorry to hear you haven't had a great experience with our website. Please DM us so we can further assist with these issues. https://t.co/BQQTdfLPtb
47 @djbuffnstuff Hi Craig, we're so sorry to hear about trouble with your order arriving. Please get back to us privately so we can further assist you. https://t.co/BQQTdfLPtb
48 @JKBAD Hey, thanks for bringing this to our attention. Unfortunately, it is a scam. We'll DM you with next steps.
50 @MackFordFan98 Hello Mark, we are incredibly sorry to hear your zipper is no longer working. Would you please DM us with more details so we can get this resolved for you? https://t.co/BQQTdfLPtb
51 @tdersmom Hello! We are incredibly sorry to hear about your zipper. Would you please send us a DM with more information so we can go over our options to get your zipper repaired? https://t.co/BQQTdfLPtb

JanSport Sentiment Analysis¶

In [11]:
# Pull out all the tweets for JanSport in last 7 days
JanSport= analysis("JanSport")
JanSport
The Twitter handle entered hasn't Tweeted in 7 days.
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-11-e864d2b88562> in <module>
      1 # Pull out all the tweets for JanSport in last 7 days
----> 2 JanSport= analysis("JanSport")
      3 JanSport

<ipython-input-1-5fbff253cd5d> in analysis(handle)
     83     sentiment_url, subscription_key = connect_to_azure(data)
     84     headers = azure_header(subscription_key)
---> 85     document_format = create_document_format(res_json)
     86     sentiments = sentiment_scores(headers, sentiment_url, document_format)
     87     week_score = mean_score(sentiments)

<ipython-input-1-5fbff253cd5d> in create_document_format(res_json)
     49 
     50 def create_document_format(res_json):
---> 51     data_only = res_json["data"]
     52     doc_start = '"documents": {}'.format(data_only)
     53     str_json = "{" + doc_start + "}"

KeyError: 'data'

Columbia Sentiment Analysis¶

In [12]:
columbia = analysis("Columbia1938")
columbia
Base on the  2 tweets this account post from past 7 days, we get a score of  0.9218319654464722
This account had a positve week
Out[12]:
id lang text
0 1426283619644026891 en This 106-mile course doles out 32,940 feet of elevation gain in a series of brutal climbs, although each one is set against a stunning panoramic backdrop. ​\n\nFind out what makes the @UTMBMontBlanc so badass:​\nhttps://t.co/Y3eorH2wFU
1 1425215856708132870 en To help you make the right choice, we’ve listed seven of the most important qualities to keep in mind when you’re shopping for a backpack. \nhttps://t.co/P1ByHRq3Fu
In [ ]: