2016-12-05 157 views
0

我是一個初學者,爲python/flask中的計劃推文和自動轉推寫一個小的推特工具。Twitter,多個進程和數據庫

我被困在後臺運行的進程問題。

我希望計劃推文和轉推在給定用戶的後臺同時工作。

我希望能夠終止這些後臺進程相互分開運行轉推/計劃推文。

你會如何改變下面的代碼來實現這一目標?

如果您現在查看下面的代碼,它可以工作,但用戶無法同時運行計劃的推文和轉發。同樣,如果用戶決定終止其中一個進程,讓我們假設轉推其他進程也會終止(計劃推文),反之亦然。

我曾考慮過將給定進程的標識數據放入數據庫中,並且在需要終止時從數據庫中調用這個標識數據,而不是使用cookies會話,但我不知道如何實現這個在代碼中的想法。

import ........ 

mysql = MySQL() 
app = Flask(__name__) 
app.secret_key = 'xxx' 

app.config['MYSQL_DATABASE_USER'] = 'xxx' 
app.config['MYSQL_DATABASE_PASSWORD'] = 'xxx' 
app.config['MYSQL_DATABASE_DB'] = 'xxx' 
app.config['MYSQL_DATABASE_HOST'] = '0.0.0.0' 
mysql.init_app(app) 

@app.route('/showSignin') 
def showSignin(): 
    if session.get('user'): 
     return redirect('/userHome') 
    else: 
     return render_template('signin.html') 

@app.route('/showscheduletweets') 

def showscheduletweets(): 

    if session.get('user'): 
     return render_template('scheduletweets.html') 
    else: 
     return render_template('signin.html') 

    @app.route('/validateLogin',methods=['POST']) 
def validateLogin(): 
    try: 
    _username = request.form['inputEmail'] 
    _password = request.form['inputPassword'] 

    # connect to mysql 

    con = mysql.connect() 
    cursor = con.cursor() 
    cursor.callproc('sp_validateLogin',(_username,)) 
    data = cursor.fetchall() 

    if len(data) > 0: 
     if check_password_hash(str(data[0][3]),_password): 
      session['user'] = data[0][0] 
      consumerkey = data [0][4] 
      consumersecret = data [0][5] 
      accesstoken = data [0][6] 
      tokensecret = data [0][7] 
      twitter = Twython(consumerkey, consumersecret, accesstoken, tokensecret) 
      twitter.update_status(status="xxx says hello.") 
      return render_template('userHome.html') 
     else: 
      return render_template('error.html',error = 'Wrong Email address or Password.') 
    else: 
     return render_template('error.html',error = 'Wrong Email address or Password.') 

except Exception as e: 
    return render_template('error.html',error = str(e)) 
finally: 
    cursor.close() 
    con.close() 

#schedule tweets 

@app.route('/scheduletweets',methods=['POST']) 

def scheduletweets(): 
    if session.get('user'): 
    _username = request.form['inputEmail'] 
    con = mysql.connect() 
    cursor = con.cursor() 
    cursor.callproc('sp_GetTwitter', (_username,)) 
    data = cursor.fetchall() 

    session['user'] = data[0][0] 
    consumerkey = data [0][4] 
    consumersecret = data [0][5] 
    accesstoken = data [0][6] 
    tokensecret = data [0][7] 
    twitter = Twython(consumerkey, consumersecret, accesstoken, tokensecret) 

    tweet1 = request.form['inputTweet1'] 
    tweet2 = request.form['inputTweet2'] 
    tweet3 = request.form['inputTweet3'] 
    tweet4 = request.form['inputTweet4'] 
    tweet5 = request.form['inputTweet5'] 
    tweet6 = request.form['inputTweet6'] 

    Hash1 = request.form['inputHash1'] 
    Hash2 = request.form['inputHash2'] 
    Hash3 = request.form['inputHash3'] 
    Hash4 = request.form['inputHash4'] 

    fruits = [Hash1, Hash2, Hash3, Hash4] 



    list = [tweet1, tweet2, tweet3, tweet4, tweet5, tweet6] 
    def workit(): 

    while True: 
     try: 
      if len(list) > 0: 
       z = random.randint(1, len(fruits)) 
       a = random.sample(fruits, z) 


       b=" ".join(str(x) for x in a) 
       toTweet = list[random.randint(0,len(list))-1] + " " + b 

       twitter.update_status(status=toTweet) 
       time.sleep(10) 


      else: 
       twitter.update_status(status="Oh dear... I'm afraid I'm rather empty =(") 
       break 
     except TwythonError as e: 
      print (e) 


    if 'work_process' not in session: 
    process = Process(target=workit) 
    process.start() 
    pid = process.pid 
    parent_pid = psutil.Process(process.pid).parent().pid 
    session['work_process'] = (parent_pid, pid) 
    return redirect('/showscheduletweets') 
    #retweets 
    @app.route('/retweet',methods=['POST']) 
def retweet(): 
    if session.get('user'): 

    _username = request.form['inputEmail'] 
    con = mysql.connect() 
    cursor = con.cursor() 
    cursor.callproc('sp_GetTwitter', (_username,)) 
    data = cursor.fetchall() 

    session['user'] = data[0][0] 
    consumerkey = data [0][4] 
    consumersecret = data [0][5] 
    accesstoken = data [0][6] 
    tokensecret = data [0][7] 


    Retweet1 = request.form['inputRetweet1'] 
    Retweet2 = request.form['inputRetweet2'] 
    Retweet3 = request.form['inputRetweet3'] 
    Retweet4 = request.form['inputRetweet4'] 
    Exclude1 = request.form['inputExclude1'] 
    Exclude2 = request.form['inputExclude2'] 




    def work(): 
    twitter = Twython(consumerkey, consumersecret, accesstoken, tokensecret) 
    naughty_words = [Exclude1, Exclude2] 
    good_words = [Retweet1, Retweet2, Retweet3, Retweet4] 
    filter = " OR ".join(good_words) 
    blacklist = " -".join(naughty_words) 
    keywords = filter +" -"+ blacklist 
    print(keywords) 
    while True: 
     search_results = twitter.search(q=keywords, count=10) 
     try: 
      for tweet in search_results["statuses"]: 
       try: 
        twitter.retweet(id = tweet["id_str"]) 
        time.sleep(60) 
       except TwythonError as e: 
              print (e) 
     except TwythonError as e: 
            print (e) 

    if 'work_process' not in session: 
    process = Process(target=work) 
    process.start() 
    pid = process.pid 
    parent_pid = psutil.Process(process.pid).parent().pid 
    session['work_process'] = (parent_pid, pid) 
    return redirect('/showretweet') 

     #terminating scheduled tweets and retweets 
     @app.route('/stoptweet', methods=['POST']) 
    def stoptweet(): 
    if 'work_process' in session: 
    parent_pid, pid = session['work_process'] 
    try: 
     process = psutil.Process(pid) 
     if process.parent().pid == parent_pid: 
      process.terminate() 
    except psutil.NoSuchProcess: 
     pass 
    session.pop('work_process') 
    return render_template('index.html') 
else: 
    return render_template('index.html') 

if __name__ == '__main__': 
    app.run(host=os.getenv('IP', '0.0.0.0'),port=int(os.getenv('PORT', xxx))) 

回答

0

您可能需要使用celery python module和移動的時間表鳴叫和銳推爲背景的作品。

如需進一步信息,請參閱文檔:http://flask.pocoo.org/docs/0.11/patterns/celery/

您將裝點那些與芹菜的功能,而不是瓶。

作爲例子:

在你的腳本:

import my_schedule_module 

,然後在my_schedule_module.py

from celery import Celery, Task 
from celery.result import AsyncResult 

from celery.task.base import periodic_task 

import sqlite3 # Here I use sqlite, can be sql 
import redis # Here I am using redis, you can use another db as well > check documentation 

from datetime import timedelta # used to schedule your background jobs, see in configuration below 


app_schedule = Celery('my_schedule_module') 


''' 
Celery Configuration 
''' 

# a mockup configuration of your background jobs, as example use retweet each 60s 
app_schedule.conf.update(
    CELERY_ACCEPT_CONTENT = ['application/json'], 
    CELERY_TASK_SERIALIZER='json', 
    # CELERY_ACCEPT_CONTENT=['json'], # Ignore other content 
    CELERY_RESULT_SERIALIZER='json', 
    # CELERY_TIMEZONE='Europe/Oslo', 
    # CELERY_ENABLE_UTC=True, 
    CELERYD_TASK_TIME_LIMIT = 600, 
    CELERYD_TASK_SOFT_TIME_LIMIT = 600, 
    CELERYD_MAX_TASKS_PER_CHILD = 1000, 
    CELERYD_OPTS="--time-limit=600 --concurrency=4", 
    BROKER_URL = 'redis://localhost:6379/0', 
    CELERY_RESULT_BACKEND = 'redis://localhost', 
    CELERYBEAT_SCHEDULE = { 
     'add-every-60-seconds': { 
     'task': 'my_schedule_module.retweet', 
     'schedule': timedelta(seconds=60) 
     }, 
    } 
) 

@app_schedule.task() 
def retweet(tweet): 
    # your tweet function 

@app_schedule.task() 
def scheduletweets(): 
    # your background job 
    # pseudo code 
    tweets = get_tweets() 
    process_tweet_list = [] 
    for tweet in tweets: 
      process_tweet_list.append(retweet.s(tweet)) 
    job = group(process_tweet_list) #group is celery.group, see documentation 
    result = job.apply_async() # process job list async 
    print 'result', result.ready(), result.successful() 

您還可以使用回叫功能 - 如例如,您可能想更新日期時間在你的推特被轉推的時候。

在這種情況下,你將有一個語法,如:

result = my_schedule_module.retweet.apply_async((tweet,) , link=my_schedule_module.callback_to_store_results_of_retweet.s()) 
+0

謝謝你的,但我一直在嘗試之前芹菜。我遇到了請求上下文的問題:RuntimeError:在請求上下文之外工作。 這通常意味着您試圖使用需要活動HTTP請求的功能。 – Lucas

+0

此外,這在實踐中意味着什麼? CELERYD_TASK_TIME_LIMIT = 600, CELERYD_TASK_SOFT_TIME_LIMIT = 600, CELERYD_MAX_TASKS_PER_CHILD = 1000, CELERYD_OPTS = 「 - 時限= 600 --concurrency = 4」, - 即轉推過程可以持續最多600秒,然後終止? – Lucas

+0

關於我對請求上下文的第一條評論 - 在所有的推文被安排或要轉推的文字/ hastags來自用戶在html表單中輸入它們之後。我會使用芹菜,但我不知道如何將芹菜應用於HTML格式的上下文。 – Lucas