Last active
June 9, 2021 13:09
-
-
Save Sopwith/8f4b6d4a86530a552f951fcbb48fe9de to your computer and use it in GitHub Desktop.
Google Search via SMS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ---- 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