Skip to content

Instantly share code, notes, and snippets.

@Sopwith
Last active June 9, 2021 13:09
Show Gist options
  • Save Sopwith/8f4b6d4a86530a552f951fcbb48fe9de to your computer and use it in GitHub Desktop.
Save Sopwith/8f4b6d4a86530a552f951fcbb48fe9de to your computer and use it in GitHub Desktop.
Google Search via SMS
# ---- A Bing Lookup Python SMS Server - via Pushbullet
# - This is basically my attempt at making my own "Google mobile" service from days of yore - basically this runs as a server to monitor your SMS's for a specific request code and returns python-webscraped data via SMS (to external contacts). It's a way to look something up via Google without having internet. It works, more or less. Results may vary though.
# - Originally this was intended to help my mom, who doesn't have data, look something up if she needed to. She could text my phone with a '#g' and a query and it would look it up and return info to her. She'd mostly be interested in addresses and phone numbers of locations while out on the road.
# > Of course, as soon as I actually completed this, we decided to upgrade her phone package to include data...
# - To accomplish this, I use Pushbullet to handle monitoring texts from the computer and responding; but you could probably retrofit the idea / approach to some other service if you could figure it out and it had something like a websockets to watch.
# - Why Bing? Because I didn't want to chance being banned by Google. :P Feel free to change this up if you want to use Google or a different search provider. You'll need to completely change the beautifulsoup webscraping parts.
# --- The Basic idea - how this works:
# > Text recieved to your phone containing in it the proper signal for a query. Currently set to '#g'.
# > Your phone has Pushbullet installed (and you have internet/data), which means that your notifications get mirror'd onto Pushbullet's servers.
# > To get the sender number, there is an additional Pushbullet API request that gets called.
# > This script, listening on your Pushbullet API via websocket, detects the new text (when sync'd to Pushbullet), reads the content, and if '#g' is detected, takes action.
# > It runs the 'Google' (Bing) function as appropriate.
# > It returns output via SMS to the requester.
# --- YOU WILL NEED
# - An android phone with a working SIM that will receive texts
# - A computer to run this python script
# - A Pushbullet account and access to the API (a key for your account), which you'll need to input below (or define to the script some other way)
# --- Current notes
# - It's basic, it basically works. More of a proof of concept than something especially useful.
# - You need to adjust which device is the active one Pushbullet is using to send / receive SMS's. Each device on your account has a unique ID code / key. You need this in order to access your SMS history (threads in the onMessage()) and recognize which device should send out the reply SMS's (the pb.push_sms within onMessage()). See the 'Devices' section at the bottom for a section of script that should spit out a dictionary of devices on your account for you to play with.
# - The Pushbullet free API supposedly has a limit of 100 SMS's per month. If you hit that, you might have to figure out a better way to send return texts. My other ideas are:
# > Use the sender's SMS gateway to translate an email into text. (https://en.wikipedia.org/wiki/SMS_gateway) The problem is you'd have to know the person's network carrier in advance...
# > Use some other third-party app idea. Like: https://medium.com/@erayerdin/send-sms-with-python-eab7a5854d3a
# > Use Pushbullet and Automate (android app - published by Llamalab) to detect each other and send return texts. (However Pushbullet's free API also possibly has a 500-push limit per month...)
# - I'm using just a basic approach to getting the search HTML, which attempts to impersonate a user with a browser. This means if you don't act like a user - eg. if you proceed to make too many requests in too little of a timeframe - you'll get IP banned. Beware. --- You could optionally replace this with something from scraperapi.com (free) but I found it slow and tempermental.
# - You may need this package...
# !pip install pushbullet.py==0.9.1
import websocket, json, requests
from bs4 import BeautifulSoup
from pushbullet import Pushbullet
api_key = '<your-pushbullet-api-key>'
socket = 'wss://stream.pushbullet.com/websocket/' + api_key
pb = Pushbullet(api_key)
def Google(query):
global url, r, out, soup, cards, highlight, sidebar, items, definition # This was just for my troubleshooting. I think you can take this out.
query = query.replace(" ", "+")
url = 'https://www.bing.com/search?q=' + query
# Note: This way of getting the HTML attempts to impersonate a user with a browser. This means if you don't act like a user - eg. if you proceed to make too many requests in too little of a timeframe - you'll get IP banned. Beware. --- You could optionally replace this with something from scraperapi.com (free) but I found it slow and tempermental.
r = requests.get(url, headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0'})
soup = BeautifulSoup(r.text, 'html.parser')
body = soup.body.text
if len(body) > 900:
out = ''
# Cleaning up junk for various options that may follow.
for div in soup.find_all("div", {'class':'expansionAccessibilityText'}):
div.decompose()
for div in soup.find_all("div", {'class':'b_hide'}):
div.decompose()
for div in soup.find_all("div", {'id':'trns_dict'}):
div.decompose()
# Extracting elements for inspection, in a particular order
cards = soup.find_all('div', {'class' : 'b_scard b_scardf b_scardh'}) # Cards - when you get numerous responses, eg "gas <location>"
highlight = soup.find_all('span', {'id' : 'lgb_info'}) # Highlight - when there's just one option, eg "walmart trenton ontario" (there is only one)
sidebar = soup.find_all('div', {'class' : 'b_subModule'}) # Sidebar - when the result shows up as a singular entity in the sidebar, eg. "belleville ontario"
items = soup.find_all('div', {'class' : 'card'}) # Items - when it wants to list items on a map, typically for restaurants, eg. "indian food belleville"
definition = soup.find_all('div', {'class' : 'dcont dcsbx'}) # Definition - when you look up a word definition, eg. "search definition"
# Checking in a particular order whether any of these element searches returned something. If so, that's our result.
if len(cards) > 0:
for c in cards:
out = out + str(c.get_text(separator="\n").replace("DIRECTIONS", "").replace("WEBSITE", ""))
out = out + "\n"
return(out)
elif len(highlight) > 0:
for h in highlight:
out = out + str(h.get_text(separator="\n"))
return(out)
elif len(items) > 0:
for i in items:
out = out + str(i.get_text(separator="\n"))
out = out + "\n\n"
return(out)
elif len(definition) > 0:
for d in definition:
out = out + str(d.get_text(separator="\n"))
return(out)
elif len(sidebar) > 0:
out = sidebar[0]
return(out.get_text(separator="\n"))
else:
print("Request failed. Please try again.")
def on_open(ws):
print('Connection opened... Awaiting new SMS pushes from Pushbullet...')
def on_close(ws):
print('Connection closed.')
def on_message(ws, message):
global q, m, num, response, api_key
# print(message)
m = json.loads(message)['push']['notifications'][0]['body']
if "#g" in m:
print("\nQuery request (#g) detected... Activating search subroutine...")
# Step 1: Identify sender.
# *** PUT IN YOUR DEVICE ID CODE INTO THIS WEB ADDRESS! (Or define it elsewhere, like a better programmer, you know the drill.)
threads = requests.get('https://api.pushbullet.com/v2/permanents/<your-device-id>_threads', headers={'Authorization': 'Bearer ' + api_key, 'Content-Type': 'application/json'})
t = json.loads(threads.text)
num = t['threads'][0]['recipients'][0]['address'].replace("(", "").replace(")", "") # Most recent SMS sender
# Step 2: Prepare and submit query.
q = m.replace("#g ", "")
print("Submitting query: '" + q + "'")
response = Google(q)
print("\n... Response:\n")
print(response)
# Step 3: Send response back.
push = pb.push_sms(pb.devices[1], num, response) # This is how to send a text using the pushbullet python package.
else:
print("\nSMS recieved... No query request... Ignoring...")
# The Pushbullet API websocket listener...
ws = websocket.WebSocketApp(socket, on_open=on_open, on_close=on_close, on_message=on_message)
ws.run_forever()
# --- DEVICES
# resp = requests.get('https://api.pushbullet.com/v2/devices', headers={'Authorization': 'Bearer ' + api_key, 'Content-Type': 'application/json'})
# r = json.loads(resp.text)
# print(json.dumps(r, indent=4, sort_keys=True))
# --- SMS THREADS
# resp = requests.get('https://api.pushbullet.com/v2/permanents/<your-device-id>', headers={'Authorization': 'Bearer ' + api_key, 'Content-Type': 'application/json'})
# r = json.loads(resp.text)
# print(json.dumps(r['threads'][0:4], indent=4, sort_keys=True))
# --- Printing JSON
# print(json.dumps(r, indent=4, sort_keys=True))
# REFERENCE: Send a text using the Pushbullet python package...
# push = pb.push_sms(pb.devices[1], num, 'message')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment