Commit 9674aba6 authored by Romain Loth's avatar Romain Loth

tweet relay server: make cors optional and add a README

parent a28f43a8
A simple relay server to the official Twitter search API
========================================================
## Credentials setup
Like any other Twitter REST API consumer, this app needs twitter authentication credentials.
To get them, go to https://apps.twitter.com/ and register a new app... The url param can be fake.
Once you have your keys and access tokens, create a `keys.json` file on the model of the attached `keys.json.template`, and save it in the same folder as the script.
Remember not to upload your `keys.json` on git !!
## Usage
Run it with the following command:
```
cd twitterAPI2
python3 topPapers_flask_server.py
```
Then you can query the app via `127.0.0.1:5000` like this:
- `http://127.0.0.1:5000/twitter_search?query=hamon`
- it returns the exact json from the twitter search
- tinawebJS will use it in topPapers if you fill "http://127.0.0.1:5000/twitter_search" in the variable TW.APINAME
- `http://127.0.0.1:5000/twitter_limits`
- this route informs you how many queries are left until the next 15 minutes renewal time
- more info on https://dev.twitter.com/rest/public/rate-limiting
#### In local tests
Use the `--cors` option to allow requests from all apps within the local LAN
```
python3 topPapers_flask_server.py --cors
```
#### On a real server
Use nohup or gunicorn to detach the process or make it into a full-fledged server.
## More info
```python3 topPapers_flask_server.py --help```
{
"consumer_key": "something_something",
"consumer_secret": "something_something_something",
"access_token_key": "something_else",
"access_token_secret": "something_else_something_else"
}
......@@ -9,16 +9,17 @@ __version__ = "0.5"
__email__ = "romain.loth@iscpif.fr"
__status__ = "dev"
from json import load
from json import load, dumps
from flask import Flask, request
from time import ctime
from sys import argv
from urllib.parse import quote
from argparse import ArgumentParser
import twitter
from flask.ext.cors import CORS, cross_origin
app = Flask(__name__)
#cors = CORS(app)
#app.config['CORS_HEADERS'] = 'Content-Type'
app.config['DEBUG'] = False
# ---- initialize twitter api with credentials ----
keys_file = open("keys.json")
......@@ -30,14 +31,12 @@ TAPI = twitter.Api(consumer_key=credentials['consumer_key'],
access_token_key=credentials['access_token_key'],
access_token_secret=credentials['access_token_secret'])
print("logged in to twitter as", TAPI.VerifyCredentials().screen_name)
print("logged in to twitter as ***%s***" % TAPI.VerifyCredentials().screen_name)
# query context: constant for one app
QCONTEXT = "(Fillon OR Macron OR JLM2017 OR Mélenchon OR #Marine2017 OR @MLP_officiel OR Hamon OR Presidentielle2017)"
@app.route('/twitter_search')
# @cross_origin(origin="twjs.org")
#@cross_origin()
def searcher():
if 'query' in request.args:
# prepare query
......@@ -50,14 +49,42 @@ def searcher():
q = "q=%s" % q + "&result_type=recent&count=5"
search_res = TAPI.GetSearch(raw_query=q)
try:
search_res = TAPI.GetSearch(raw_query=q)
sending_json = "[%s]" % ",".join([status.AsJsonString() for status in search_res])
sending_status = 200
except twitter.TwitterError as te:
sending_json = '{"error": "Rate limit exceeded"}'
sending_status = 429
sending_json = "[%s]" % ",".join([status.AsJsonString() for status in search_res])
else:
sending_json = '{"error":"no query??"}'
sending_status = 400
response = app.response_class(
response=sending_json,
status=sending_status,
mimetype='application/json'
)
return response
@app.route('/twitter_limits')
def latest_api_limits():
if 'search' not in TAPI.rate_limit.resources:
# the API has never been used
send = {'left':180, 'until':-1, 'until_human':""}
else:
n_left = TAPI.rate_limit.resources['search']['/search/tweets']['remaining']
until_unix_time = TAPI.rate_limit.resources['search']['/search/tweets']['reset']
send = {'left':n_left, 'until':until_unix_time, 'until_human': ctime(until_unix_time)}
response = app.response_class(
response= dumps(send),
status=200,
mimetype='application/json'
)
......@@ -65,4 +92,36 @@ def searcher():
########### MAIN ###########
if __name__ == "__main__":
app.run(debug=True)
# cli args
# --------
parser = ArgumentParser(
description="Connect to twitter search/tweets API",
epilog="-----(© 2017 ISCPIF-CNRS romain.loth at iscpif dot fr )-----")
# conditional CORS: use True only if working on localhost
parser.add_argument('--cors',
help='allow queries from any domain (safe only for local tests)',
required=False,
action='store_true')
parser.add_argument('--qcontext',
type = str,
help='a boolean query that will be added to all queries with an AND()',
required=False,
metavar="'%s'" % QCONTEXT,
default=QCONTEXT,
action='store')
args = parser.parse_args(argv[1:])
if (args.cors):
print("WARNING: CORS activated (it is safe only if you're on a localhost)")
from flask_cors import CORS, cross_origin
cors = CORS(app, resources={r"/*": {"origins": "*"}})
app.config['CORS_HEADERS'] = 'Content-Type'
if (args.qcontext):
QCONTEXT = args.qcontext
app.run()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment