Created
March 23, 2021 00:33
-
-
Save usr-ein/575f89260a94d89700db019376bccbac to your computer and use it in GitHub Desktop.
Twitter live map of geolocated tweets in an area, streamed to .kml file, which can be viewed in Google Earth
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
import re | |
from tempfile import mkstemp | |
from shutil import move | |
from os import remove, close | |
class LiveMap(object): | |
def __init__(self, livePoints, pathToLive = "live.kml"): | |
super(LiveMap, self).__init__() | |
self.livePoints = livePoints | |
self.pathToLive = pathToLive | |
def initKMLFile(self): | |
kmlFile = open(self.pathToLive, "w") | |
kml = '<?xml version="1.0" encoding="UTF-8"?>\n<kml xmlns="http://www.opengis.net/kml/2.2">\n<Document>' | |
for livePoint in self.livePoints: | |
kml += livePoint.kml | |
kml += '</Document>\n</kml>' | |
kmlFile.seek(0) | |
kmlFile.truncate() | |
kmlFile.write(kml) | |
kmlFile.close() | |
def updateMap(self): | |
print("Point count in map: {}".format(len(self.livePoints))) | |
#Create temp file | |
fh, abs_path = mkstemp() | |
kml = '<?xml version="1.0" encoding="UTF-8"?>\n<kml xmlns="http://www.opengis.net/kml/2.2">\n<Document>' | |
for livePoint in self.livePoints: | |
kml += livePoint.kml | |
kml += '</Document>\n</kml>' | |
new_file = open(abs_path,'w') | |
new_file.write(kml) | |
close(fh) | |
#Remove original file | |
try: | |
remove(self.pathToLive) | |
except FileNotFoundError: | |
pass # Happens when pathToLive file doesn't exist, no big deal | |
#Move new file | |
move(abs_path, self.pathToLive) | |
class LivePoint(object): | |
"""Create live pinpoint on Google Earth from lat/lon | |
Use: lp = LivePoint(lat, lon, path_to_generate_live_kml, point_s_name) """ | |
def __init__(self, lat, lon, pointName = "LivePoint", pointDesc = "A dynamic point", pointIconURI = ""): | |
super(LivePoint, self).__init__() | |
self.kml = "" | |
self.lat = lat | |
self.lon = lon | |
self.pointName = pointName | |
self.pointDesc = pointDesc | |
self.pointIconURI = pointIconURI | |
self.reg = re.compile(r"^.*<coordinates>[0-9\.\,]+<\/coordinates>.*$") | |
self.initKML() | |
def initKML(self): | |
self.kml = ( | |
'<Style id="icon"><IconStyle><Icon><href>{}</href></Icon></IconStyle></Style>\n' | |
'<Placemark>\n' | |
'<name>{}</name>\n' | |
'<description>{}</description>\n' | |
'<styleUrl>#icon</styleUrl>\n' | |
'<Point>\n' | |
'<coordinates>{},{}</coordinates>\n' | |
'</Point>\n' | |
'</Placemark>\n' | |
).format(self.pointIconURI, self.pointName, self.pointDesc, self.lon, self.lat) | |
def updatePoint(self, nLat, nLon): | |
self.kml = re.sub(self.reg, "<coordinates>{},{}</coordinates>".format(nLon, nLat), self.kml) |
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
<?xml version="1.0" encoding="UTF-8"?> | |
<kml xmlns="http://www.opengis.net/kml/2.2"> | |
<Document><Style id="icon"><IconStyle><Icon><href>http://pbs.twimg.com/profile_images/930226803008069632/2V5iRPf5_normal.jpg</href></Icon></IconStyle></Style> | |
<Placemark> | |
<name>geometre18</name> | |
<description>D E S G E N S . . . et la notion d'oisiveté. | |
. à Paris, France | |
Post ==> https://www.instagram.com/p/BhZRq7xloOu/</description> | |
<styleUrl>#icon</styleUrl> | |
<Point> | |
<coordinates>2.3508,48.8567</coordinates> | |
</Point> | |
</Placemark> | |
<Style id="icon"><IconStyle><Icon><href>http://pbs.twimg.com/profile_images/693101853987475457/02UJ5moF_normal.png</href></Icon></IconStyle></Style> | |
<Placemark> | |
<name>JulienBinet</name> | |
<description>#NouvellePP ? à Paris, France | |
Post ==> https://www.instagram.com/p/BhZR256A62z/</description> | |
<styleUrl>#icon</styleUrl> | |
<Point> | |
<coordinates>2.3508,48.8567</coordinates> | |
</Point> | |
</Placemark> | |
<Style id="icon"><IconStyle><Icon><href>http://pbs.twimg.com/profile_images/785211727088590849/LGGL32XB_normal.jpg</href></Icon></IconStyle></Style> | |
<Placemark> | |
<name>Michele_SABBAN</name> | |
<description>Conférence de presse ce matin pour le lancement de Transitions les 26 et 27 juin à Monaco 🇲🇨 à… | |
Post ==> https://www.instagram.com/p/BhZR3b4jE0O/</description> | |
<styleUrl>#icon</styleUrl> | |
<Point> | |
<coordinates>2.3508,48.8567</coordinates> | |
</Point> | |
</Placemark> | |
<Style id="icon"><IconStyle><Icon><href>http://pbs.twimg.com/profile_images/969889088395530241/s0HdAeer_normal.jpg</href></Icon></IconStyle></Style> | |
<Placemark> | |
<name>eyepreferparis</name> | |
<description>Conciergerie Please click on my profile link to watch my new video series A Bite of Paris on my… | |
Post ==> https://www.instagram.com/p/BhZR4rygQN4/</description> | |
<styleUrl>#icon</styleUrl> | |
<Point> | |
<coordinates>2.3461499,48.8560791</coordinates> | |
</Point> | |
</Placemark> | |
<Style id="icon"><IconStyle><Icon><href>http://pbs.twimg.com/profile_images/571097657143377921/W02IGFBl_normal.jpeg</href></Icon></IconStyle></Style> | |
<Placemark> | |
<name>delicesdevaness</name> | |
<description>Elles sont arrivées !! 😍 | |
Dégustées au restaurant_virtus | |
Sublimées par 2 virtuoses ✨ | |
Je vous… | |
Post ==> https://www.instagram.com/p/BhZR9-oF2oG/</description> | |
<styleUrl>#icon</styleUrl> | |
<Point> | |
<coordinates>2.37814,48.85023</coordinates> | |
</Point> | |
</Placemark> | |
<Style id="icon"><IconStyle><Icon><href>http://pbs.twimg.com/profile_images/378800000608005637/6bfde6eb41a7edaba00900ac97120824_normal.jpeg</href></Icon></IconStyle></Style> | |
<Placemark> | |
<name>Frainke</name> | |
<description>#OnceUponATime | |
La Dame de Fer | |
#Paris, #France (03/2018) | |
#LaViedArtiste #LatinosByDay #WeekEnd… | |
Post ==> https://www.instagram.com/p/BhZR8y0nOKR/</description> | |
<styleUrl>#icon</styleUrl> | |
<Point> | |
<coordinates>2.29455382,48.85838631</coordinates> | |
</Point> | |
</Placemark> | |
<Style id="icon"><IconStyle><Icon><href>http://pbs.twimg.com/profile_images/969889088395530241/s0HdAeer_normal.jpg</href></Icon></IconStyle></Style> | |
<Placemark> | |
<name>eyepreferparis</name> | |
<description>Waterfall at La Concergerie Please click on my profile link to watch my new video series A Bite… | |
Post ==> https://www.instagram.com/p/BhZSDb8gDwl/</description> | |
<styleUrl>#icon</styleUrl> | |
<Point> | |
<coordinates>2.3461499,48.8560791</coordinates> | |
</Point> | |
</Placemark> | |
</Document> | |
</kml> |
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
import tweepy | |
import requests | |
from LiveMap import LivePoint, LiveMap | |
# Paris: 2.246862,48.812219,2.422987,48.905958 | |
## Auth to Tweeter API ## | |
consumerKey = "put it here" | |
consumerSecret = "put it there" | |
accessToken = "pop it in here" | |
accessSecret = "pop it in there" | |
auth = tweepy.OAuthHandler(consumerKey, consumerSecret) | |
auth.set_access_token(accessToken, accessSecret) | |
api = tweepy.API(auth) | |
INSTAGRAM_ONLY = True | |
livePoints = [] | |
liveMap = LiveMap(livePoints, pathToLive="liveTweet.kml") | |
## Collect Football related tweets | |
class CustomStreamListener(tweepy.StreamListener): | |
def on_status(self, status): | |
text = status.text | |
if(status.geo): | |
print(text) | |
print("Geo: ", status.geo) | |
name = status._json['user']['screen_name'] | |
profilePict = status._json['user']['profile_image_url'] | |
link = status.text[-23:] | |
# Test if the twitter post is an instagram post | |
if "https" in link: | |
finalURL = requests.get(link).url | |
if INSTAGRAM_ONLY and not "instagram" in finalURL: | |
return | |
else: | |
link = finalURL | |
desc = status.text[:-23] + "\nPost ==> " + link | |
name = name.replace("&", "") | |
desc = desc.replace("&", "") | |
livePoint = LivePoint(status.geo['coordinates'][0], status.geo['coordinates'][1], pointName=name, pointDesc=desc, pointIconURI=profilePict) | |
livePoints.append(livePoint) | |
liveMap.updateMap() | |
print("-"*10) | |
streamListener = CustomStreamListener() | |
streamTweet = tweepy.Stream(auth = api.auth, listener=streamListener) | |
streamTweet.filter(locations=[2.246862,48.812219,2.422987,48.905958]) # Square around Paris |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment