Authors: Marcel Schliebs and Dorian Quelle
knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.path = "man/figures/README-", out.width = "100%" )
Disclaimer 1: This package was just before release when Amazon announced the upcoming shut-down of Parler. While chances are high that this tool is broken by the time you read this lines, we wanted to get our current beta version out as quickly as possible to create at least a few hours of usefulness for the research community. We apologize for any bug you will be very likely to encounter, but the pending shut-down prevented us from implementing proper checks and doing extensive beta testing.
Disclaimer 2: This R package is a backend to the node.js based command line tool parlance
published here: https://github.com/castlelemongrab/parlance/. We attribute full credits to the authors of parlance and ask you to equally credit them when using this package. Similar to the legal notes described here (https://github.com/castlelemongrab/parlance#legal), we do not take any responsibility for how you use the piece of software. We do not encouragement the breach of Terms of Service of any company, except in legally and ethically permitted cases, such as for academic research. See further the bottom of this document for additional legal notes. Copyright for Backend: 2020 The Parlance Team Copyright 2020 Baby Britain, Ltd.
To use this software, node.js must be installed. Go to https://nodejs.org/en/download/ and select the version designed for your system. Following the automatic installation of node.js, you can use parleR.
This package is an R implementation of the software Parlance from https://github.com/castlelemongrab. To use it, please install parlance. Open a terminal window and enter:
npm install -g @castlelemongrab/parlance
To check whether the installation was successful, enter:
parlance
The output should look like this:
Commands: parlance init Create an authorization file parlance feed Fetch your own feed of posts parlance profile Fetch a user profile parlance post Fetch a single post by identifier parlance posts Fetch all posts for a user parlance following Fetch all users followed by a user parlance followers Fetch all followers of a user parlance comments Fetch all comments for a user, post, or comment parlance tags Fetch all posts mentioning a hashtag parlance votes Fetch all votes made by a user parlance write Post a new message to your account parlance delete Delete an existing message from your account parlance follow Follow a user parlance unfollow Unfollow an already-followed user parlance mute Mute a user parlance news Fetch your own affiliate news feed parlance moderation Fetch your list of comments for moderation Options: --help Show help [boolean] --version Show version number [boolean] --show-hidden Show hidden options [boolean] --format-options Provide format/type-specific options [string] -c, --credentials MST/JST tokens [string] [default: "config/auth.json"] -o, --credentials-out Output file for client credentials [string] -S, --start-key Specify a time-series start/resume key [string] -E, --end-key Specify a time-series end/halt key [string] -l, --ignore-last Rely solely upon time comparisons [boolean] -n, --no-delay Disable the failsafe rate-limiter [boolean] -p, --page-size Request a specific page size [number] -d, --debug Print all debug information to stderr [boolean] -v, --verbose Print verbose information to stderr [boolean] -q, --quiet Print less information to stderr [boolean] -s, --silent Print absolutely no information to stderr [boolean] -e, --expand Expand specific UUID types [array] [default: "all"] -f, --format Select output format/type [string] [default: "json"]
Disclaimer: The end user uses this piece of software at their own legal responsibility. The authors do not take any responsibility for how you use the piece of software. We do not encouragement the breach of Terms of Service of any company, except in legally and ethically permitted cases.
To use the software you must have a Parler account. After registering, you need to retrieve the cookies used by Parler. Instructions on how to extract cookies are given here for Firefox, Safari and Chrome:
Right click and select "inspect Element" from the drop down menu. In the window that pops up, select Storage tab and then click on Cookies. Two cookies are displayed.
Right-click and select "Inspect". This will open up the Chrome developer console. From the developer console, go to the Applications tab, and then expand the Cookies dropdown under the Storage section. Two cookies are displayed.
To use this package, you first must authenticate within
your project/working directory. Run the following function, which will write a file called auth.json into a folder called config. The file will have the format {"mst" : "s:........", "jst" : "....."}.
parler_auth(decode = TRUE, path = "config/auth.json",#DO NOT CHANGE option = "enter")
Now you're ready to go.
devtools::install_github("schliebs/parleR")
library(parleR)
library(tidyverse) library(quanteda) library(lubridate)
post_df1 <- parler_posts(user = "Grenell", output_format = "data.frame", flatten_sep = " || ", parse_numbers = TRUE, verbose = TRUE)
colnames(post_df1)
post_df1 %>% dplyr::select(creator_username,body,impressions,upvotes,createdAt)
Plot weekly likes over time
weekly_engagement <- post_df1 %>% mutate(week = lubridate::round_date(as_datetime(createdAt),"weeks")) %>% group_by(week) %>% summarise(across(.cols = all_of(c("impressions","upvotes", "reposts","comments")), .fns = sum, .names = "sum_{.col}")) %>% filter(week < as.Date("2021-01-10"))
ggplot(weekly_engagement %>% gather(var,val,-week)) + geom_line(aes(x = week,y = val)) + facet_wrap(~var,ncol = 2,scales = "free") + theme_minimal() + scale_x_datetime(date_breaks = "4 weeks", date_labels = "%m-%d") + theme(panel.grid.minor = element_blank()) + labs(title = "Weekly Engagement with Posts by 'Grenell'", x = "Date", y = "Weekly Amount of Engagement")
Same for 'EricTrump' (no idea if account is legit):
post_df2 <- parler_posts(user = "EricTrump", output_format = "data.frame", flatten_sep = " || ", parse_numbers = TRUE, verbose = TRUE)
post_df2 %>% dplyr::select(creator_username,body,impressions,upvotes,createdAt)
Plot weekly likes over time
weekly_engagement <- post_df2 %>% mutate(week = lubridate::round_date(as_datetime(createdAt),"weeks")) %>% group_by(week) %>% summarise(across(.cols = all_of(c("impressions","upvotes", "reposts","comments")), .fns = sum, .names = "sum_{.col}")) %>% filter(week < as.Date("2021-01-10"))
ggplot(weekly_engagement %>% gather(var,val,-week)) + geom_line(aes(x = week,y = val)) + facet_wrap(~var,ncol = 2,scales = "free") + theme_minimal() + scale_x_datetime(date_breaks = "4 weeks", date_labels = "%m-%d") + theme(panel.grid.minor = element_blank()) + labs(title = "Weekly Engagement with Posts by 'EricTrump'", x = "Date", y = "Weekly Amount of Engagement")
Because there are thousands of posts, we time out the request after a certain amount of seconds.
hashtag_posts_df1 <- parler_hashtag(hashtag = "maga", output_format = "data.frame", flatten_sep = " || ", parse_numbers = TRUE, verbose = TRUE, timeout = 60)
colnames(hashtag_posts_df1)
hashtag_posts_df1 %>% head(50) %>% dplyr::select(creator_username,body,impressions,upvotes,createdAt)
To be honest, this application does not really carry a lot of meaning, we just ran out of time before parler gets shut down and therefore opted for a quick and dirty comparison cloud.
Scrape hashtags '#nocovidvaccine' and '#electionfraud'
vaxx_hashtags <- parler_hashtag(hashtag = "nocovidvaccine", output_format = "data.frame", flatten_sep = " || ", parse_numbers = TRUE, verbose = F, timeout = 30) %>% mutate(ht = "#nocovidvaccine") electionfraud_hashtags <- parler_hashtag(hashtag = "electionfraud", output_format = "data.frame", flatten_sep = " || ", parse_numbers = TRUE, verbose = F, timeout = 30) %>% mutate(ht = "#electionfraud")
Wordcloud:
both <- bind_rows(vaxx_hashtags,electionfraud_hashtags) corpus <- quanteda::corpus(both %>% rename(text = body)) dfmat <- dfm(corpus_subset(corpus, ht %in% c("#electionfraud", "#nocovidvaccine")), remove = stopwords("english"), remove_punct = TRUE, groups = "ht") %>% dfm_trim(min_termfreq = 3)
textplot_wordcloud(dfmat, min_size = 0.5, max_size = 3, comparison = TRUE, max_words = 1000, color = c("blue", "red"))
out <- parler_profile(user = "caseybmulligan", output_format = "data.frame", flatten_sep = " || ", token_variables = F, parse_numbers = TRUE, verbose = TRUE)
colnames(out)
out %>% select(name,username,followers,likes,posts,joined,bio)
out2 <- parler_profile(user = "caseybmulligan", output_format = "data.frame", flatten_sep = " || ", token_variables = TRUE, parse_numbers = TRUE, verbose = TRUE)
colnames(out2)
New colnames which are only outputtet if token_variables == TRUE
:
colnames(out2) %>% .[!. %in% colnames(out)]
jlist <- parler_profile(user = "caseybmulligan", output_format = "list", flatten_sep = " || ", verbose = FALSE)
str(jlist)
user_vec <- c("Marklevinshow","SeanHannity","Devinnunes","GovernorNoem", "KTHopkins","Westmonster","TommyRobinson") out_df <- purrr::map(.x = user_vec, .f = ~ parler_profile(user = .x, output_format = "data.frame", flatten_sep = " || ", token_variables = FALSE, parse_numbers = TRUE, verbose = FALSE) ) %>% bind_rows()
out_df %>% select(name,username,followers,likes,posts,joined,bio)
This package is a mere R-frontend wrapper to the backend provided by parlance (https://github.com/castlelemongrab/parlance). As your machine will be calling 'parlance' to scrape data, we emphatically repeat the legal nodes by the authors of parlance in this place. You can find them here: https://github.com/castlelemongrab/parlance#legal
QUOTE: "This repository seeks to document the design of Parler as accurately and concisely as possible. Parler is of interest to researchers, political campaigns, civic engagement groups, law enforcement, anti-discrimination groups, and the public at large. The free speech conveyed in this repository is of timely and widespread public interest.
If you choose to use this speech as part of an activity, please ensure your activity is ethical and legal within your jurisdiction. The author of this work of speech cannot, will not, and has no responsibility to control the behavior of others – in any jurisdiction, on any of Jupiter's mighty moons, or anywhere within the known universe – past, present, or future.
Due to the specific nature and quality of Parler's engineering design, the speech contained within this repository is the sole product of unrelated industry experience and third-party documentation. No act of disassembly, decompilation, reverse engineering, trade secret violation – nor any other prohibited act – was necessary to create the work contained herein.
"Communication does not lose constitutional protection as 'speech' simply because it is expressed in the language of computer code. Mathematical formulae and musical scores are written in 'code,' i.e. symbolic notations not comprehensible to the uninitiated, and yet both are covered by the First Amendment. If someone chose to write a novel entirely in computer object code by using strings of 1’s and 0’s for each letter of each word, the resulting work would be no different for constitutional purposes than if it had been written in English." – DMCA, Universal City Studios v. Corley, FN191: 273 F.3d 429, 60 USPQ2d 1953 (2nd Cir. 2001)
Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the Government for a redress of grievances. "
Copyright for Backend: 2020 The Parlance Team Copyright 2020 Baby Britain, Ltd.
License Statement for Parlance Backend: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.