olof-bengtsson commited on
Commit
e92325c
2 Parent(s): deaf095 42184ee

Merge branch 'develop' into 37-test-twitter-scraper

Browse files
.idea/politweet.iml CHANGED
@@ -3,9 +3,8 @@
3
  <component name="NewModuleRootManager">
4
  <content url="file://$MODULE_DIR$">
5
  <excludeFolder url="file://$MODULE_DIR$/politweet-environment" />
6
- <excludeFolder url="file://$MODULE_DIR$/venv" />
7
  </content>
8
- <orderEntry type="jdk" jdkName="Python 3.9 (politweet)" jdkType="Python SDK" />
9
  <orderEntry type="sourceFolder" forTests="false" />
10
  </component>
11
  <component name="PyNamespacePackagesService">
 
3
  <component name="NewModuleRootManager">
4
  <content url="file://$MODULE_DIR$">
5
  <excludeFolder url="file://$MODULE_DIR$/politweet-environment" />
 
6
  </content>
7
+ <orderEntry type="inheritedJdk" />
8
  <orderEntry type="sourceFolder" forTests="false" />
9
  </component>
10
  <component name="PyNamespacePackagesService">
README.md CHANGED
@@ -20,8 +20,14 @@ För att få alla dependencies:
20
 
21
  1. skapa en virtual environment: https://docs.python.org/3/library/venv.html
22
  2. Aktivera din virtual environment
23
- 2. gå till projektets root path och skriv i terminalen:
24
- $ env2/bin/python -m pip install -r requirements.txt
 
 
 
 
 
 
25
 
26
 
27
 
 
20
 
21
  1. skapa en virtual environment: https://docs.python.org/3/library/venv.html
22
  2. Aktivera din virtual environment
23
+ 3. gå till projektets root path och skriv i terminalen:
24
+ $ pip install -r requirements.txt
25
+ 4. I vissa fall funkar det inte att installera twint för Ubuntu. Efter att ha ställt in allt funkade det efter att ha kört "sudo apt-get install build- essential" i terminalen.
26
+ 5. För att använda openai behövs en auktoriserings-token. Detta skapas genom att skapa en '.env' fil i projektets root path.
27
+ 6. Skriv in följande i den filen:
28
+ OPENAI_AUTHTOKEN=din open-ai token
29
+ 7. Nu borde TextClassifier kunna använda openai, givet att du har timmar att lägga till din token.
30
+
31
 
32
 
33
 
data/twitterdata.csv ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ id,tweet,date,user_id,username,urls,nlikes,nreplies,nretweets
2
+ 1208816689720283138,God jul https://t.co/AC6HzzxJI1,2019-12-22 19:28:52,95972673,jimmieakesson,[],3090,247,270
3
+ 1206517009451814915, https://t.co/SPIXCl1y7O,2019-12-16 11:10:45,95972673,jimmieakesson,[],1554,69,97
4
+ 1204392974718767105,Hej @Jonas_Gardell Läste din artikel i @Expressen vad sägs om att ses och snacka istället för att prata förbi varandra i media? Jag tror på samtalet och jag är övertygad om att jag kan lära mig något av dig. Kanske är det ömsesidigt?,2019-12-10 14:30:36,95972673,jimmieakesson,[],5207,299,634
5
+ 1202639801205317633,"""Sverigedemokraterna räds inte ett extraval om misstroendeförklaringen mot arbetsmarknadsminister Eva Nordmark (S) landar i att hela regeringen avgår. – Vi är redo för nyval så klart, säger SD-ledaren Jimmie Åkesson."" https://t.co/RxRfwKVruK",2019-12-05 18:24:07,95972673,jimmieakesson,['https://www.sydsvenskan.se/2019-12-05/sd-redo-for-extraval?redirected=1'],1209,51,144
6
+ 1202231839424950272,Intervju med Jimmie Åkesson med anledning av dagens möte med Ulf Kristersson. https://t.co/AOGYLUEwxC,2019-12-04 15:23:01,95972673,jimmieakesson,['https://www.svt.se/nyheter/inrikes/det-har-diskuterade-akesson-och-kristersson'],380,13,43
7
+ 1202200851189846022,"Mötet var givande, konstruktivt och bådar gott inför framtida samarbeten i ett nytt politiskt landskap. / Jimmie",2019-12-04 13:19:53,95972673,jimmieakesson,[],626,13,22
8
+ 1202200819354996738,"Men också hur den framtida invandringspolitiken och energipolitiken bör utformas. Även om Sverigedemokraterna och Moderaterna är två olika partier, finns det också många beröringspunkter i en rad olika sakfrågor.",2019-12-04 13:19:45,95972673,jimmieakesson,[],455,5,23
9
+ 1202199793688293376,Idag besökte jag och min gruppledare Ulf Kristerssons arbetsrum för ett första direkt möte med Ulf Kristersson och Moderaternas gruppledare. På mötet diskuterades bland annat hur vi ska komma tillrätta med den kriminaliteten i vårt land som regeringen helt har misslyckats med. https://t.co/APmt4WSrUK,2019-12-04 13:15:41,95972673,jimmieakesson,[],1801,91,148
10
+ 1202185719965458432,"Konstruktiv dag. Här i möte med vår nya gruppledare i riksdagen, @VingeHenrik . Stay tuned... #svpol https://t.co/LMYmKIS3ya",2019-12-04 12:19:45,95972673,jimmieakesson,[],370,14,28
11
+ 1199417558291533824,Ännu ett institut bekräftar det nya läget 💪 https://t.co/9WuWsdRWGt,2019-11-26 21:00:04,95972673,jimmieakesson,[],1586,74,128
12
+ 1198144200283475968,Kommuner som går på knäna. Skjutningar och sprängningar var och varannan dag. En eskalerande otrygghet som steg för steg bryter ned vårt land. Har Sverige problem? Ja. Är S-regeringen med sina stödpartier kapabla att lösa dessa problem? Nej. https://t.co/7WWRwbs1Ds,2019-11-23 08:40:12,95972673,jimmieakesson,['https://www.aftonbladet.se/debatt/a/kJPRKj/massinvandringen-har-slagit-sonder-nationen'],1937,122,292
13
+ 1197790554609852416,Utvecklingen S vs SD under 2000-talet. Det närmar sig... 💪 https://t.co/MNV5oGJktQ,2019-11-22 09:14:56,95972673,jimmieakesson,[],1243,43,120
14
+ 1197481419561472000,"Vi vill avsätta alla ministrar som går att avsätta i den här regeringen, så det är mycket sannolikt att vi hakar på en sådan eventuellt misstroendeomröstning. https://t.co/PHj6XipNGH",2019-11-21 12:46:33,95972673,jimmieakesson,['https://www.di.se/nyheter/sd-hakar-pa-v-om-af-hotar-avsatta-s-ministern/'],1419,86,128
15
+ 1197467328105062400,Många intervjuer inför partiets Landsdagar. Några återstår innan jag rullar mot Örebro. https://t.co/hXYMhcVDAG,2019-11-21 11:50:33,95972673,jimmieakesson,[],360,16,16
16
+ 1195769542456356864,Expressen inför nästa veckas Landsdagar med SD. https://t.co/vsQj18Xwaw,2019-11-16 19:24:09,95972673,jimmieakesson,[],349,21,24
17
+ 1194553636946350080,Morgan Johansson måste avgå. #pldebatt #svpol https://t.co/QsVAhqvaou,2019-11-13 10:52:35,95972673,jimmieakesson,[],1713,47,203
18
+ 1194528503284346881,Idag begär jag att riksdagen avsätter justitieminister Morgan Johansson. #svpol https://t.co/tL703x5eYQ,2019-11-13 09:12:43,95972673,jimmieakesson,[],1844,80,140
19
+ 1194495733858222080,Åtta år senare och Morgan kämpar vidare... 🦸‍♂️ https://t.co/iCWrEwhgHP,2019-11-13 07:02:30,95972673,jimmieakesson,[],1769,87,271
requirements.txt CHANGED
@@ -37,6 +37,7 @@ pycparser==2.21
37
  pyparsing==3.0.9
38
  PySocks==1.7.1
39
  python-dateutil==2.8.2
 
40
  python-socks==2.0.3
41
  pytz==2022.1
42
  regex==2022.6.2
 
37
  pyparsing==3.0.9
38
  PySocks==1.7.1
39
  python-dateutil==2.8.2
40
+ python-dotenv==0.20.0
41
  python-socks==2.0.3
42
  pytz==2022.1
43
  regex==2022.6.2
textclassifier/TextClassifier.py CHANGED
@@ -1,11 +1,24 @@
1
  import openai
 
2
  import regex as re
3
  from twitterscraper import TwitterScraper
4
  from datetime import date
 
 
 
 
 
 
 
 
 
5
 
6
 
7
  class TextClassifier:
8
- def __init__(self, model_name="text-davinci-002", from_date='2022-01-01', to_date=str(date.today()), num_tweets=100):
 
 
 
9
  """
10
  Initializes the TextClassifier.
11
  :param model_name: name of the model from openai.
@@ -13,20 +26,263 @@ class TextClassifier:
13
  :param to_date: string of the format 'YYYY-MM-DD'.
14
  :param num_tweets: integer value of the maximum number of tweets to be scraped.
15
  """
 
 
 
 
 
 
 
 
16
 
17
  self.model_name = model_name
18
- self.df = TwitterScraper.TwitterScraper(from_date, to_date, num_tweets)
19
- self.api_key = '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'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
  def classify_sentiment(self, text: str):
22
  """
23
  Classifies the sentiment of a text.
24
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- def classify_topics(self, text: str):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  """
28
  Classifies the topics of a text.
 
29
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  def __repr__(self):
32
- return f"TextClassifier(df={self.df}, col={self.col}, model_name={self.model_name})"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import openai
2
+ import csv
3
  import regex as re
4
  from twitterscraper import TwitterScraper
5
  from datetime import date
6
+ import os
7
+ from dotenv import find_dotenv, load_dotenv
8
+
9
+ # Set one directory up into ROOT_PATH
10
+ ROOT_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
11
+
12
+ dotenv_path = find_dotenv()
13
+ load_dotenv(dotenv_path)
14
+ OPENAI_AUTHTOKEN = os.environ.get("OPENAI_AUTHTOKEN")
15
 
16
 
17
  class TextClassifier:
18
+ def __init__(self, model_name="text-davinci-002", from_date='2022-01-01', to_date=str(date.today()),
19
+
20
+ user_name='jimmieakesson',
21
+ num_tweets=20, ):
22
  """
23
  Initializes the TextClassifier.
24
  :param model_name: name of the model from openai.
 
26
  :param to_date: string of the format 'YYYY-MM-DD'.
27
  :param num_tweets: integer value of the maximum number of tweets to be scraped.
28
  """
29
+ # Make sure to_date is later than from_date
30
+ assert from_date < to_date, "from_date must be earlier than to_date"
31
+ # Make sure the dates are in the correct format
32
+ assert re.match(r'^\d{4}-\d{2}-\d{2}$', from_date) is not None, "from_date must be in the format YYYY-MM-DD"
33
+ # Make sure user_name is not empty
34
+ assert user_name is not None, "user_name cannot be empty"
35
+ # Make sure num_tweets is a positive integer
36
+ assert num_tweets > 0, "num_tweets must be a positive integer"
37
 
38
  self.model_name = model_name
39
+ self.from_date = from_date
40
+ self.to_date = to_date
41
+ self.num_tweets = num_tweets
42
+ self.user_name = user_name
43
+ self.ts = TwitterScraper.TwitterScraper(from_date, to_date, num_tweets)
44
+ self.df = self.ts.scrape_by_user(user_name)
45
+ # self.api_key = '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'
46
+ openai.api_key = OPENAI_AUTHTOKEN
47
+
48
+ def classify_topic_and_sentiment(self):
49
+ self.classify_topic_of_tweets()
50
+ self.classify_sentiment_of_tweets()
51
+
52
+ # save the dataframe to a csv file
53
+
54
+
55
+ @staticmethod
56
+ def cleanup_sentiment_results(classification_unclean):
57
+ """
58
+ Cleans up the results of the sentiment classification.
59
+ :param classification_unclean: string of the classification result.
60
+ :return: cleaned up string.
61
+ """
62
+ classification_clean = classification_unclean.replace('\n\n', "")
63
+ classification_clean = classification_clean.replace('\n', "")
64
+ if classification_clean.startswith(" "):
65
+ classification_clean = classification_clean.replace(" ", "")
66
+
67
+ return classification_clean
68
 
69
  def classify_sentiment(self, text: str):
70
  """
71
  Classifies the sentiment of a text.
72
  """
73
+ assert isinstance(text, str)
74
+
75
+ prompt_string = "Classify one sentiment for this tweet:\n \""
76
+ prompt_string += text
77
+ prompt_string += "\" \nFor example:\nSupport,\nOpposition,\nCriticism,\nPraise,\nDisagreement," \
78
+ "\nAgreement,\nSkepticism,\nAdmiration,\nAnecdotes,\nJokes,\nMemes,\nSarcasm,\nSatire," \
79
+ "\nQuestions,\nStatements,\nOpinions,\nPredictions.\nSENTIMENT="
80
+
81
+ response = openai.Completion.create(
82
+ model=self.model_name,
83
+ prompt=prompt_string,
84
+ temperature=0.0,
85
+ max_tokens=256,
86
+ top_p=1,
87
+ frequency_penalty=0,
88
+ presence_penalty=0,
89
+ logprobs=5
90
+ )
91
+ classification_unclean = response.choices[0]['text']
92
+ classification_clean = self.cleanup_sentiment_results(classification_unclean)
93
+
94
+ return classification_clean.lower()
95
+
96
+ def classify_sentiment_of_tweets(self):
97
+ """
98
+ Classifies the sentiment of a user's tweets.
99
+ """
100
+ df_sentiment = self.df.copy()
101
+
102
+ df_sentiment['sentiment'] = df_sentiment['tweet'].apply(self.classify_sentiment)
103
+ self.df = df_sentiment
104
+ return self.df
105
 
106
+ def analyze_sentiment(self, text: str, sentiment: str):
107
+ # TODO: fix prompt before running this method
108
+ """
109
+ Analyzes the sentiment of a text using OpenAI.
110
+ :param text: string of the tweet text.
111
+ :param sentiment:
112
+ :return:
113
+ """
114
+ # assert 1 == 2, "Måste fixa prompt innan denna metod körs"
115
+ prompt_string = "Who is the TARGET of this "
116
+ prompt_string += sentiment
117
+ prompt_string += " TWEET?\\nTWEET=\""
118
+ prompt_string += text
119
+ prompt_string += "\"\\n.TARGET should consist of less than 5 words.\\nTARGET="
120
+
121
+ response = openai.Completion.create(
122
+ model=self.model_name,
123
+ prompt=prompt_string,
124
+ temperature=0,
125
+ max_tokens=256,
126
+ top_p=1,
127
+ frequency_penalty=0,
128
+ presence_penalty=0
129
+ )
130
+
131
+ analyzed_sentiment = response.choices[0]['text']
132
+ # Remove spaces at the start/end of the response
133
+ if analyzed_sentiment.startswith(' '):
134
+ analyzed_sentiment = analyzed_sentiment[1:]
135
+ if analyzed_sentiment.endswith(' '):
136
+ analyzed_sentiment = analyzed_sentiment[:-1]
137
+
138
+ # Sometimes GPT-3 gives faulty results, so a simple filter is introduced
139
+ # If the prediction is bad
140
+ # -> set target value to N/A (not applicable)
141
+ if len(analyzed_sentiment) > 50:
142
+ analyzed_sentiment = "N/A"
143
+
144
+ # An attempt to merge target responses that should be the same
145
+ analyzed_sentiment = re.sub("\(", "", analyzed_sentiment)
146
+ analyzed_sentiment = re.sub("\)", "", analyzed_sentiment)
147
+
148
+ s_list = ["s", "the swedish social democratic party"]
149
+ m_list = ["m", "the swedish moderate party", "the moderate party"]
150
+ mp_list = ["mp", "the swedish green party"]
151
+
152
+ if analyzed_sentiment.lower() == "v":
153
+ analyzed_sentiment = "Vänsterpartiet"
154
+ elif analyzed_sentiment.lower() == "mp":
155
+ analyzed_sentiment = "Miljöpartiet"
156
+ elif analyzed_sentiment.lower() in s_list:
157
+ analyzed_sentiment = "Socialdemokraterna"
158
+ elif analyzed_sentiment.lower() == "c":
159
+ analyzed_sentiment = "Centerpartiet"
160
+ elif analyzed_sentiment.lower() == "l":
161
+ analyzed_sentiment = "Liberalerna"
162
+ elif analyzed_sentiment.lower() == "kd":
163
+ analyzed_sentiment = "Kristdemokraterna"
164
+ elif analyzed_sentiment.lower() in m_list:
165
+ analyzed_sentiment = "Moderaterna"
166
+ elif analyzed_sentiment.lower() == "sd":
167
+ analyzed_sentiment = "Sverigedemokraterna"
168
+ elif analyzed_sentiment.lower() == "the swedish government":
169
+ analyzed_sentiment = "Regeringen"
170
+
171
+ return analyzed_sentiment
172
+
173
+ def analyze_sentiment_of_tweets(self):
174
+ """
175
+ Analyzes the sentiment of a user's tweets.
176
+ """
177
+ # check if 'sentiment' column exists, raise exception if not
178
+ assert 'sentiment' in self.df.columns, \
179
+ "'sentiment' column does not exist. Please run classify_sentiment_of_tweets first."
180
+
181
+ df_sentiment = self.df.copy()
182
+ df_sentiment['target'] = df_sentiment.apply(lambda row: self.analyze_sentiment(row['tweet'], row['sentiment']),
183
+ axis=1)
184
+ self.df = df_sentiment
185
+ return self.df
186
+
187
+ def classify_topic(self, text: str):
188
  """
189
  Classifies the topics of a text.
190
+ :param text: string of the tweet text.
191
  """
192
+ assert isinstance(text, str)
193
+
194
+ prompt_string = "Classify one topic for this tweet:\n \""
195
+ prompt_string += text
196
+ prompt_string += "\" \nFor example:\nEconomy,\nEnvironment,\nHealth,\nPolitics,\nScience,\nSports,\nTechnology," \
197
+ "\nTransportation,\nWorld.\nTOPIC="
198
+
199
+ response = openai.Completion.create(
200
+ model=self.model_name,
201
+ prompt=prompt_string,
202
+ temperature=0,
203
+ max_tokens=892,
204
+ top_p=1,
205
+ frequency_penalty=0,
206
+ presence_penalty=0,
207
+ )
208
+ classification_unclean = response.choices[0]['text']
209
+ classification_clean = self.cleanup_topic_results(classification_unclean)
210
+
211
+ return classification_clean.lower()
212
+
213
+ def classify_topics_of_tweets(self):
214
+ """
215
+ Classifies the topics of a user's tweets.
216
+ """
217
+ df_topic = self.df
218
+ df_topic['topic'] = df_topic['tweet'].apply(self.classify_topic)
219
+ return df_topic
220
+
221
+ @staticmethod
222
+ def cleanup_topic_results(prediction_dict, text):
223
+ new_item = text.replace("\n", " ")
224
+ new_item = new_item.replace(" ", " ")
225
+ return new_item
226
+
227
+ def df_to_csv(self, filename="{}/data/twitterdata.csv".format(ROOT_PATH)):
228
+ """
229
+ Writes pandas df to csv file. If it already exists, it appends. If not, it creates. It also removes duplicates.
230
+ :param filename:
231
+ :return:
232
+ """
233
+ if not os.path.exists(filename):
234
+ self.df.to_csv(filename, index=False)
235
+ else:
236
+ self.df.to_csv(filename, mode='a', header=False, index=False)
237
+
238
+ self.remove_duplicates_from_csv(filename)
239
+
240
+ @staticmethod
241
+ def remove_duplicates_from_csv(filename="{}/data/twitterdata.csv".format(ROOT_PATH)):
242
+ """
243
+ Removes duplicates from csv file.
244
+ :param filename: filename of csv file
245
+ :return: None
246
+ """
247
+ with open(filename, 'r') as f:
248
+ lines = f.readlines()
249
+ with open(filename, 'w') as f:
250
+ for line in lines:
251
+ if line not in lines[lines.index(line) + 1:]:
252
+ f.write(line)
253
+
254
+ def remove_already_classified_tweets(self, filename="{}/data/twitterdata.csv".format(ROOT_PATH)):
255
+ """
256
+ Removes tweets that have already been classified.
257
+ :param filename: filename of csv file
258
+ :return: None
259
+ """
260
+ df = self.df
261
+ df = df[df['sentiment'].isnull()]
262
+ self.df = df
263
+ self.df_to_csv(filename)
264
 
265
  def __repr__(self):
266
+ """
267
+ Gives a string that describes which user is classified
268
+ :return:
269
+ """
270
+ return "Classifier for user: " + self.user_name + " with model: " + self.model_name + "."
271
+
272
+ if __name__ == "__main__":
273
+ tc = TextClassifier(from_date="2022-01-01", to_date="2022-05-31", user_name='jimmieakesson', num_tweets=20)
274
+ tc.remove_duplicates_from_csv()
275
+ # import pandas as pd
276
+ # from datetime import datetime
277
+ # import os
278
+ # # show all columns
279
+ # pd.set_option('display.max_columns', None)
280
+ #
281
+ # tc = TextClassifier(from_date="2019-01-01", to_date="2019-05-31", user_name='jimmieakesson', num_tweets=20)
282
+ # tc.classify_sentiment_of_tweets()
283
+ # # df = tc.analyze_sentiment_of_tweets()
284
+ # # print(df)
285
+ # df = tc.classify_topics_of_tweets()
286
+ # print(df)
287
+ # # save to csv in a folder under politweet with timestamp in name
288
+ # df.to_csv(f"{datetime.now().strftime('%Y-%m-%d %H-%M-%S')}_tweets.csv")
twitterscraper/TwitterScraper.py CHANGED
@@ -11,6 +11,7 @@ class TwitterScraper(object):
11
  input: user, from_date, to_date, num_tweets
12
  output: dict
13
  """
 
14
  def __init__(self, from_date="2022-07-01", to_date=str(date.today()), num_tweets=20):
15
  # TODO: add a check to make sure that the dates are in the correct format.
16
  # TODO: add a check to make sure that the number of tweets is a positive number.
@@ -69,7 +70,7 @@ class TwitterScraper(object):
69
  tweets_info = tweet_and_replies_info.drop(labels=indx_replies, axis=0)
70
  # drop removes the columns which its index specified by
71
  # indx_replies. axis=0 if we want to delete rows.
72
- #print(len(tweets['tweet']), " of them are Tweets")
73
  return tweets_info
74
 
75
  def __get_tweets__from_twint__(self):
@@ -110,15 +111,12 @@ class TwitterScraper(object):
110
  def __repr__(self):
111
  return "TwitterScraper(from_date={}, to_date={}, num_tweets={})".format(self.from_date, self.to_date,
112
  self.num_tweets)
 
 
 
113
  if __name__ == "__main__":
114
  sc = TwitterScraper(from_date="2022-05-01", to_date="2022-07-31", num_tweets=40)
115
  dc = sc.scrape_by_user("jimmieakesson")
116
  print(dc.head())
117
  print(dc.shape)
118
  print(dc.columns)
119
-
120
-
121
-
122
-
123
-
124
-
 
11
  input: user, from_date, to_date, num_tweets
12
  output: dict
13
  """
14
+
15
  def __init__(self, from_date="2022-07-01", to_date=str(date.today()), num_tweets=20):
16
  # TODO: add a check to make sure that the dates are in the correct format.
17
  # TODO: add a check to make sure that the number of tweets is a positive number.
 
70
  tweets_info = tweet_and_replies_info.drop(labels=indx_replies, axis=0)
71
  # drop removes the columns which its index specified by
72
  # indx_replies. axis=0 if we want to delete rows.
73
+ # print(len(tweets['tweet']), " of them are Tweets")
74
  return tweets_info
75
 
76
  def __get_tweets__from_twint__(self):
 
111
  def __repr__(self):
112
  return "TwitterScraper(from_date={}, to_date={}, num_tweets={})".format(self.from_date, self.to_date,
113
  self.num_tweets)
114
+
115
+
116
+
117
  if __name__ == "__main__":
118
  sc = TwitterScraper(from_date="2022-05-01", to_date="2022-07-31", num_tweets=40)
119
  dc = sc.scrape_by_user("jimmieakesson")
120
  print(dc.head())
121
  print(dc.shape)
122
  print(dc.columns)
 
 
 
 
 
 
twitterscraper/jimmieakesson.csv ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ,id,tweet,date,user_id,username,urls,nlikes,nreplies,nretweets
2
+ 0,1546801285021814784,"Sverigedemokraterna kommer även fortsättningsvis att vara den tyngsta rösten för kraftigt sänkta priser på både bränsle och el. Alla vi miljontals människor som bor utanför storstädernas kollektivtrafik och cykelbanor måste kunna leva. Sänk bränslepriserna, nu! https://t.co/OiPb6WdaZG",2022-07-12 12:18:59,95972673,jimmieakesson,[],1074,63,103
3
+ 1,1544748873767424001,Fruktansvärt att nås av beskedet att kvinnan som attackerades i Visby har avlidit. Mina tankar finns hos hennes familj ikväll.,2022-07-06 20:23:26,95972673,jimmieakesson,[],3482,178,143
4
+ 2,1538948369611210764,"@annieloof Nej, jag håller med. Tänk mer som Mathias Andersson (SD). https://t.co/gSqQDz5N8z",2022-06-20 20:14:18,95972673,jimmieakesson,[],1511,89,115
5
+ 3,1537770920621879297,"Man kan ha synpunkter på en sådan lösning, men den är naturligtvis att föredra framför frigående våldsverkare som fortsätter misshandla sina offer i väntan på fängelse.",2022-06-17 14:15:32,95972673,jimmieakesson,[],694,17,41
6
+ 4,1537770809225273344,Är det ont om plats på anstalterna så får man sänka standarden rejält för att få rum med fler interner per kvadratmeter.,2022-06-17 14:15:05,95972673,jimmieakesson,[],812,26,57
7
+ 5,1537770713368735744,"Döms man för brott, särskilt våldsbrott, ska man vara inlåst från det att domen faller tills straffet är avtjänat. Allt annat är vansinne.",2022-06-17 14:14:43,95972673,jimmieakesson,[],1015,26,85
8
+ 6,1537770657823576066,"Platsbrist? Jaha, vad spelar det för roll? Det gör mig förbannad och bestört att lösningen på problemet med överfulla fängelser verkar vara att dömda våldsbrottslingar får röra sig fritt i samhället istället för att sitta inlåsta. https://t.co/QDi9rM3kMC",2022-06-17 14:14:29,95972673,jimmieakesson,['https://sverigesradio.se/artikel/domda-kvinnomisshandlare-kan-fortsatta-valdet-mot-samma-kvinna-innan-fangelset'],1157,86,132
9
+ 7,1534230353094885383,"Det är ytterst beklagligt att Magdalena Andersson saboterar Sveriges Natoansökan genom att kohandla med en marxistisk vilde som inte bryr sig ett smack om Sverige, utan istället fullt ut företräder utländska intressen. Svekfullt, maktfullkomligt och ansvarslöst.",2022-06-07 19:46:35,95972673,jimmieakesson,[],6118,544,556
10
+ 8,1533881878553538560,"Glöm att Sverigedemokraterna kommer att lova regeringen frikort att missköta sig för att de gör sig av med en, förvisso exceptionellt usel, minister. https://t.co/3yVuUQU42o",2022-06-06 20:41:52,95972673,jimmieakesson,['https://live.aftonbladet.se/supernytt/news/m-och-l-foeljer-kds-erbjudande-till-magdalena-andersson.CqhNSVhf9'],1079,97,77
11
+ 9,1532625870824808448,"Det är bra att väljarna får denna tydliga varudeklaration, en röst på Centern är en röst på Socialdemokraterna.",2022-06-03 09:30:57,95972673,jimmieakesson,[],1255,57,96
12
+ 10,1532625804223516672,Centern ❤️ Sossarna Ännu en gång är det Annie Lööf som kommer till Morgan Johanssons räddning. För vilken gång i ordningen vet jag inte. Det är tydligt att Centern blivit det vänsterparti som krafter inom partiet arbetat för att det ska bli.,2022-06-03 09:30:41,95972673,jimmieakesson,[],2512,211,188
13
+ 11,1532341074127163392,"Därför valde Sverigedemokraterna idag att, under dagens frågestund i kammaren, väcka frågan om misstroende gentemot Morgan Johansson. Sverige förtjänar bättre.",2022-06-02 14:39:16,95972673,jimmieakesson,[],790,32,34
14
+ 12,1532340946456694785,"Morgan Johanssons misslyckanden kan inte få fortgå en enda dag mer än nödvändigt och det är vår inställning att oavsett valets utfall, så bör han förtidspensioneras som Sveriges justitie- och inrikesminister.",2022-06-02 14:38:45,95972673,jimmieakesson,[],659,9,40
15
+ 13,1532340845042622465,"De enda som kan vara nöjda med regeringens arbete är de kriminella, de som mördar, skadar och hotar. De hoppas just nu på att även kommande mandatperiod ska innebära ytterligare fyra år med Socialdemokratisk saft- och bullepolitik.",2022-06-02 14:38:21,95972673,jimmieakesson,[],435,15,35
16
+ 14,1532340768681209858,Tusentals föräldrar och syskon har förlorat någon närstående och Morgan Johanssons misslyckanden är förmodligen ett av de mest tragiska kapitlen i svensk historia.,2022-06-02 14:38:03,95972673,jimmieakesson,[],406,7,21
17
+ 15,1532340666751242240,Morgan Johansson måste avgå som minister. Otryggheten biter sig fast och gängkriminaliteten är allt annat än knäckt. Antalet skjutningar ökar och sätter skräck i varje del av vårt land. Sverige har förvandlats till ett gangsterland.,2022-06-02 14:37:39,95972673,jimmieakesson,[],3064,172,231
18
+ 16,1523345947165483008, https://t.co/64aJSb1G58,2022-05-08 18:55:50,95972673,jimmieakesson,['https://www.dn.se/debatt/sa-vill-m-sd-kd-och-l-ge-alla-pensionarer-mer-i-planboken/'],122,9,11
19
+ 17,1523345873769357312,"För oss Sverigedemokrater är detta en prioriterad fråga om både rättvisa och moral. Svenskar som på olika sätt har varit med och byggt det här landet, förtjänar en värdig ålderdom.",2022-05-08 18:55:33,95972673,jimmieakesson,[],294,11,14
20
+ 18,1523345831629180928,"I en tid när priserna stiger kraftigt på just de varor och tjänster som är svårast att avvara – mat, värme och bränsle - är det nödvändigt att förbättra de svenska pensionärernas situation.",2022-05-08 18:55:23,95972673,jimmieakesson,[],214,5,8
21
+ 19,1523345750255538176,"Största pensionssatsningen sedan pensionssystemet infördes. Vi kan idag presentera en överenskommelse med Moderaterna, Kristdemokraterna och Liberalerna om att göra den största förstärkningen av pensionärernas ekonomi sedan det nuvarande pensionssystemet infördes. https://t.co/tENrQDFy9o",2022-05-08 18:55:03,95972673,jimmieakesson,[],706,57,73
22
+ 20,1522508592376602625,Varför har ens SR alla dessa invandrarredaktioner? Ska du bo i Sverige - lär dig svenska.,2022-05-06 11:28:29,95972673,jimmieakesson,[],6876,380,522
23
+ 21,1521752982198620161,"Jag uppmanar andra inbjudna partiledare att ställa samma krav. Det får faktiskt finnas någon gräns för tokigheterna, svensk polis förtjänar tydligt stöd från Sveriges politiska partier.",2022-05-04 09:25:58,95972673,jimmieakesson,[],1914,48,106
24
+ 22,1521752934702362626,Järvaveckan får helt enkelt välja – polishataren Kakan Hermansson eller partiledaren Jimmie Åkesson.,2022-05-04 09:25:47,95972673,jimmieakesson,[],1588,53,77
25
+ 23,1521752853110566912,"Jag kommer idag att meddela arrangörerna att jag inte avser närvara och hålla tal på årets Järvaveckan, vilket tidigare planerats, om denna person på något sätt är en del av deras evenemang.",2022-05-04 09:25:27,95972673,jimmieakesson,[],1258,46,56
26
+ 24,1521752814082535424,"Kakan Hermansson har genom åren gjort sig känd för en rad politiskt extrema och direkt stötande uttalanden, inte minst hatiska inlägg om svensk polis.",2022-05-04 09:25:18,95972673,jimmieakesson,[],1006,27,47
27
+ 25,1521752766921781249,"Nu figurerar uppgifter om att årets upplaga av Järvaveckan, en politikervecka i norra Stockholm, återigen genomförs i samarbete med den mycket hårt kritiserade extremvänsterprofilen Kakan Hermansson.",2022-05-04 09:25:07,95972673,jimmieakesson,[],780,10,33
28
+ 26,1521752718070755331,"Den senaste tidens utveckling, med Ramadan-kravaller innefattande grovt våld i uppenbart syfte att döda poliser, har aktualiserat behovet av sammanhållning och rakryggat stöd för Polisen och för det svenska samhället i stort.",2022-05-04 09:24:55,95972673,jimmieakesson,[],853,13,35
29
+ 27,1521752661170794496,Järvaveckan får välja – Kakan Hermansson eller Jimmie Åkesson,2022-05-04 09:24:41,95972673,jimmieakesson,[],3924,465,215
30
+ 28,1521489890369843200,Varför svenska barn påtvingas politisk indoktrinering i skolan är en fråga som kräver en omedelbar förklaring. Vi kommer att kalla Skolverkets generaldirektör till utbildningsutskottet. Från dagens nationella prov i historia.,2022-05-03 16:00:32,95972673,jimmieakesson,[],3359,168,246
31
+ 29,1521489797038157827,Det här äcklar mig på riktigt. Propaganda riktad till skolbarn hör hemma i diktaturer. https://t.co/BDYiNs8NDV,2022-05-03 16:00:10,95972673,jimmieakesson,[],6804,735,711
32
+ 30,1521395241454034945, https://t.co/tpIq94r7BG,2022-05-03 09:44:26,95972673,jimmieakesson,['https://www.youtube.com/watch?v=f-eK1cgzGF8&ab_channel=Sverigedemokraterna'],178,10,20
33
+ 31,1521180859012943878,Ikväll medverkar jag i Aktuellt. Ämnet är trafiken och Sveriges åtgärder för att minska utsläppen. Debatt mot Annie Lööf. Aktuellt sänds i SVT2 med start kl 21.00.,2022-05-02 19:32:33,95972673,jimmieakesson,[],874,104,53