Запускать скрипт на Python каждый час - PullRequest
1 голос
/ 11 октября 2019

Я хочу, чтобы по расписанию мой скрипт Python запускался каждый час и сохранял данные в индексе эластичного поиска. Так что я использовал написанную мной функцию set_interval, которая использует библиотеку tweepy. Но это не работает, так как мне нужно, чтобы это работало. Он запускается каждую минуту и ​​сохраняет данные в индексе. Даже после набора, равного 3600 секундам, он запускается каждую минуту. Но я хочу настроить это для запуска на почасовой основе.

Как я могу это исправить? Вот мой скрипт на python:

def call_at_interval(time, callback, args):
    while True:
        timer = Timer(time, callback, args=args)
        timer.start()
        timer.join()


def set_interval(time, callback, *args):
    Thread(target=call_at_interval, args=(time, callback, args)).start()


def get_all_tweets(screen_name):
    # authorize twitter, initialize tweepy
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_key, access_secret)
    api = tweepy.API(auth)

    screen_name = ""

    # initialize a list to hold all the tweepy Tweets
    alltweets = []

    # make initial request for most recent tweets (200 is the maximum allowed count)
    new_tweets = api.user_timeline(screen_name=screen_name, count=200)

    # save most recent tweets
    alltweets.extend(new_tweets)

    # save the id of the oldest tweet less one
    oldest = alltweets[-1].id - 1

    # keep grabbing tweets until there are no tweets left to grab
    while len(new_tweets) > 0:
        #print
        #"getting tweets before %s" % (oldest)

        # all subsiquent requests use the max_id param to prevent duplicates
        new_tweets = api.user_timeline(screen_name=screen_name, count=200, max_id=oldest)

        # save most recent tweets
        alltweets.extend(new_tweets)

        # update the id of the oldest tweet less one
        oldest = alltweets[-1].id - 1

        #print
        #"...%s tweets downloaded so far" % (len(alltweets))

    outtweets = [{'ID': tweet.id_str, 'Text': tweet.text, 'Date': tweet.created_at, 'author': tweet.user.screen_name} for tweet in alltweets]

    def save_es(outtweets, es):  # Peps8 convention
        data = [  # Please without s in data
            {
                "_index": "index name",
                "_type": "type name",
                "_id": index,
                "_source": ID
            }
            for index, ID in enumerate(outtweets)
        ]
        helpers.bulk(es, data)

    save_es(outtweets, es)

    print('Run at:')
    print(datetime.now())
    print("\n")

    set_interval(3600, get_all_tweets(screen_name))

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Зачем вам так много сложности, чтобы выполнять какое-то задание каждый час? Вы можете запускать скрипт каждый час следующим образом, помните, что он выполняется 1 час + время на выполнение работы:

import time


def do_some_work():
    print("Do some work")
    time.sleep(1)
    print("Some work is done!")


if __name__ == "__main__":
    time.sleep(60)  # imagine you would like to start work in 1 minute first time
    while True:
        do_some_work()
        time.sleep(3600)  # do work every one hour

Если вы хотите запускать скрипт точно каждый час, выполните следующий код:

import time
import threading


def do_some_work():
    print("Do some work")
    time.sleep(4)
    print("Some work is done!")


if __name__ == "__main__":
    time.sleep(60)  # imagine you would like to start work in 1 minute first time
    while True:
        thr = threading.Thread(target=do_some_work)
        thr.start()
        time.sleep(3600)  # do work every one hour 

В этом случае thr должен завершить свою работу быстрее, чем 3600 секунд, хотя это не так, вы все равно получите результаты, но результаты будут получены с другой попытки, см. Пример ниже:

import time
import threading


class AttemptCount:
    def __init__(self, attempt_number):
        self.attempt_number = attempt_number


def do_some_work(_attempt_number):
    print(f"Do some work {_attempt_number.attempt_number}")
    time.sleep(4)
    print(f"Some work is done! {_attempt_number.attempt_number}")
    _attempt_number.attempt_number += 1


if __name__ == "__main__":
    attempt_number = AttemptCount(1)
    time.sleep(1)  # imagine you would like to start work in 1 minute first time
    while True:
        thr = threading.Thread(target=do_some_work, args=(attempt_number, ),)
        thr.start()
        time.sleep(1)  # do work every one hour

Результат, который вы получите в этом случае:

Сделайте некоторую работу 1 Сделайте некоторую работу 1 Сделайте некоторую работу 1 Сделайте некоторую работу 1 Некоторая работа выполнена! 1 Проделайте определенную работу 2 Проделайте определенную работу! 2 Проделайте определенную работу 3 Проделайте определенную работу! 3 Проделайте определенную работу 4 Проделайте определенную работу! 4 Проделайте определенную работу 5 Проделайте определенную работу! 5 Проделайте некоторую работу 6 Проделайте определенную работу! 6 Проделайте определенную работу 7 Проделайте определенную работу! 7 Проделайте определенную работу 8 Проделайте определенную работу! 8 Выполните некоторую работу 9

Мне нравится использовать подпроцесс. Откройте для таких задач, если дочерний подпроцесс не завершил свою работу в течение одного часа по какой-либо причине, вы просто завершаете его и запускаете новый.

Вы также можете использовать CRON, чтобы планировать запуск некоторых процессов каждый час.

0 голосов
/ 11 октября 2019

Избавьтесь от всего кода таймера, просто напишите логику, и cron сделает всю работу за вас, добавив это в конец файла после crontab -e

0 * * * * /path/to/python /path/to/script.py

0 * * * * означает запускать каждую ноль минуту, вы можете найти более подробное объяснение здесь

А также я заметил, что вы рекурсивно звоните get_all_tweets(screen_name) Я думаю, вам, возможно, придется вызвать егоизвне

Просто держите свой сценарий так много

def get_all_tweets(screen_name):
    # authorize twitter, initialize tweepy
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_key, access_secret)
    api = tweepy.API(auth)

    screen_name = ""

    # initialize a list to hold all the tweepy Tweets
    alltweets = []

    # make initial request for most recent tweets (200 is the maximum allowed count)
    new_tweets = api.user_timeline(screen_name=screen_name, count=200)

    # save most recent tweets
    alltweets.extend(new_tweets)

    # save the id of the oldest tweet less one
    oldest = alltweets[-1].id - 1

    # keep grabbing tweets until there are no tweets left to grab
    while len(new_tweets) > 0:
        #print
        #"getting tweets before %s" % (oldest)

        # all subsiquent requests use the max_id param to prevent duplicates
        new_tweets = api.user_timeline(screen_name=screen_name, count=200, max_id=oldest)

        # save most recent tweets
        alltweets.extend(new_tweets)

        # update the id of the oldest tweet less one
        oldest = alltweets[-1].id - 1

        #print
        #"...%s tweets downloaded so far" % (len(alltweets))

    outtweets = [{'ID': tweet.id_str, 'Text': tweet.text, 'Date': tweet.created_at, 'author': tweet.user.screen_name} for tweet in alltweets]

    def save_es(outtweets, es):  # Peps8 convention
        data = [  # Please without s in data
            {
                "_index": "index name",
                "_type": "type name",
                "_id": index,
                "_source": ID
            }
            for index, ID in enumerate(outtweets)
        ]
        helpers.bulk(es, data)

    save_es(outtweets, es)

get_all_tweets("") #your screen name here
...