RedShot is an event-based Python package that provides a Selenium wrapper for automating WhatsApp Web workflows. It allows you to interact with WhatsApp Web to send and receive messages, search chats, and more.
Whatsapp Web is constantly changing so this library is very susceptible to breaking and bugs. I'll do my best to fix these as soon as possible. Also, expect much more functionality in future updates.
Note: Use this library at your own risk. Whatsapp does not allow the unauthorised use of automated or bulk messaging.
pip install redshotSee the examples folder for more.
from redshot import Client
client = Client()
@client.event("on_start")
def on_start():
print("Client has started")
client.stop()
client.run()Whatsapp Web allows users to connect their whatsapp web to their phone via by scanning a QR code in the app. To allow for this session data to persist between script executions, we can implement different authentication strategies.
Currently, there is two working authentication strategies: LocalProfileSession that uses the chrome user data directory and NoAuth which saves no information between sessions:
redshot.auth.LocalProfileSession(data_dir, profile="selenium")
Parameters:
- data_dir: The chrome user data directory to be used
- profile: The chrome profile to be used
redshot.auth.NoAuth()
redshot.Client(auth=None, poll_freq=0.25, unread_messages_sleep=0.5, headless=True)
Parameters:
- auth: An authentication strategy (if None this defaults to
NoAuth) - poll_freq: Time between polls of the whatsapp webpage
- unread_messages_sleep: Time waited for the unread messages section to load
- headless: If true, the chrome UI interface won't be displayed
Events listeners are instantiated using the redshot.Client.event decorator as follows:
@client.event("on_event")
def on_event(*event_args):
print("Event triggered!")Event types:
on_start: Called once the chrome driver object has been created and has opened https://web.whatsapp.com/on_auth: Called when the authentication screen appearson_qr: Called when the qr code has loaded in the authentication screen- Arguments:
qr- the QR code image's binary string
- Arguments:
on_qr_change: Called when a new qr code is generated in the authentication screen (if the old qr code wasn't scanned in time)- Arguments:
new_qr- The new QR code image's binary string
- Arguments:
on_loading: Called when a loading screen appears:- Arguments:
loading_chats: True if the loading screen appears as a result of the qr code being scanned
- Arguments:
on_logged_in: Called when the client successfully logs inon_unread_chat: Called on each poll of the mainloop with an unread chat- Arguments:
chat: ASearchResultobject containing information about the unread chat
- Arguments:
on_tick: Called at the end of each tick of the mainloop
redshot.Client.run(): Begins the client main loop (in an asyncio thread).
redshot.Client.stop(): Stops the client's main loop once the current tick of the main loop is complete.
Note that the stop method should be run within the main loop's thread i.e. in an event listener.
Also, calling stop too soon after send_message may cause the message not to be sent (depending on internet speeds).
redshot.Client.get_recent_messages(search_field, sleep=1): Get's the recent messages from the first chat in the search results.
Parameters:
search_field: Used in the whatsapp searchbar to find the given chat
redshot.Client.send_message(search_field, message): Sends a message to the first chat in the search results.
Parameters:
search_field: Used in the whatsapp searchbar to find the given chatmessage: The message to be sent to the given chat
redshot.Client.search(search_field): Returns a list of SearchResult containing: chats, groups in common, contacts, messages.
Parameters:
search_field: Used in the whatsapp searchbar to obtain the search results
Class redshot.object.Message:
info: AMessageInfoobjecttext: A string containing the message's textquote: AMessageQuoteobjectlink: AMessageLinkobjecthas_quote(): True if theMessagecontains a quotehas_link(): True if theMessagecontains a linkas_string(): A formatted string of the message contents
Class redshot.object.MessageInfo:
time: The time the message was sentdate: The date the message was sentuser: The user who sent the messageas_string(): A formatted string of the message info contents
Class redshot.object.MessageQuote:
user: The user who sent the quoted messagetext: The text in the quoted messageas_string(): A formatted string of the message quote contents
Class redshot.object.MessageLink:
title: The title of the linked urldescription: The description of the linked urlurl: The linked urlas_string(): A formatted string of the message link contents
Class redshot.object.MessageImage:
binary: The base64 string of the imageas_string(): A formatted string of the message image contents
Class redshot.object.SearchResult:
result_type: The search result typetitle: The search result's timedatetime: The search result's datetime (either a date or a time)info: The search result's info sectionunread_messages: The number of unread messagesgroup: The group the search result is in (if the search result is a chat)
In the likely event that Whatsapp changes the structure of their website, issues may be fixed in the short term by manually overloading certain locators. Each locator is a tuple pair (by, by_str) which allow you to find elements in HTML by a certain characteristic (e.g. name, xpath, id, etc).
redshot.constants.Locator.set_locator(locator_name, locator): Updates a single locator (see the source code for the given locator name). Returns True if successful.
redshot.constants.Locator.set_locator(locators): Updates multiple locators by passing a dict of locator names and associated tuples. Returns a list of booleans.
-
Add aMessageImageclass and parse images in messages - Parse emojis within messages and other contexts
- Add support for users to override locators in case of bugs
- Replace
time.sleepfor waiting for messages or search results to load - Implement better error handling
- Add support for more features - chat descriptions/info, polls, images, files etc
- Find a way to save data between sessions without using a user data directory. See here (suggestions are more than welcome). Also look at
redshot.auth.LocalSessionAuthfor updates.