Ваша реализация работает; однако ваше приложение Twitter API, скорее всего, будет ограничено. Прочитайте о ограничении скорости , установленном в API Twitter.
В общем, когда вы сканируете данные из стороннего API, как это, вы хотите сохранить свои результаты где-нибудь надежным (в вашем случае в файле CSV в файловой системе, что может быть вполне приемлемо для вашей проблемы), поэтому вы можете снова запросить API, чтобы получить любые данные, которые вы, возможно, не получили ни в каких предыдущих запросах.
Я предоставлю Приведенный ниже наивный пример того, как вы можете изменить дизайн своего приложения, чтобы вести себя таким образом. В двух словах, при каждом выполнении приведенный ниже пример будет изменять любой ранее существующий CSV, так что он добавляет результаты, более новые, чем самая новая известная запись в CSV, и добавляет результаты, которые старше, чем самая старая известная запись в CSV.
Мой пример ниже также демонстрирует, как использовать курсоры Tweepy для итерации по страницам в твиттере.
import csv
from dataclasses import dataclass
from pathlib import Path
import logging
import os
import sys
import tweepy
@dataclass
class TweetIdRange:
count: int
newest_id: int
oldest_id: int
def get_tweets_file_id_range(tweets_file_name: Path) -> TweetIdRange:
id_range = TweetIdRange(count=0, newest_id=None, oldest_id=None)
with open(tweets_file_name) as tweets_file:
reader = csv.reader(tweets_file)
try:
next(reader)
except StopIteration:
raise RuntimeError(f'Tweets file ({tweets_file_name}) does not contain any rows; '
f'expected at least one header row')
try:
row = next(reader)
row_id = int(row[0])
id_range.newest_id = row_id
id_range.oldest_id = row_id
id_range.count += 1
except StopIteration:
pass
else:
for row in reader:
id_range.count += 1
row_id = int(row[0])
if row_id < id_range.oldest_id:
id_range.oldest_id = row_id
if row_id > id_range.newest_id:
id_range.newest_id = row_id
return id_range
def write_tweets(tweets_file_name: Path, screen_name: str, since_id: int = None, max_id: int = None):
user_timeline_options = {
'count': 100,
'tweet_mode': 'extended',
'screen_name': screen_name,
'since_id': since_id, # >
'max_id': max_id # <=
}
tweet_count = 0
with open(tweets_file_name, 'w') as tweets_file:
writer = csv.writer(tweets_file)
for page in tweepy.Cursor(api.user_timeline, **user_timeline_options).pages():
tweets = [[tweet.id_str, tweet.created_at, tweet.full_text.replace('\n', '')] for tweet in page]
tweet_count += len(tweets)
writer.writerows(tweets)
return tweet_count
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_key, access_secret)
api = tweepy.API(auth)
screen_name = sys.argv[1] if len(sys.argv) > 1 else None
if not screen_name:
print('error: missing required screen name positional argument', file=sys.stderr)
sys.exit(1)
tweets_file_name = Path(f'{screen_name}_tweets.csv')
if not tweets_file_name.exists():
logging.info('%s: initializing new file', tweets_file_name)
with open(tweets_file_name, 'w') as existing_tweets_file:
writer = csv.writer(existing_tweets_file)
writer.writerow(['id', 'created_at', 'full_text'])
tweets_id_range = get_tweets_file_id_range(tweets_file_name)
logging.info('%s: tweet ID range (before): count: %s; newest: %s; oldest: %s',
tweets_file_name, tweets_id_range.count, tweets_id_range.newest_id, tweets_id_range.oldest_id)
newest_tweets_file_name = tweets_file_name.with_suffix('.newest' + ''.join(tweets_file_name.suffixes))
new_tweet_count = write_tweets(newest_tweets_file_name, screen_name, since_id=tweets_id_range.newest_id)
logging.info('%s: prepending %s new tweets', tweets_file_name, new_tweet_count)
oldest_tweets_file_name = tweets_file_name.with_suffix('.oldest' + ''.join(tweets_file_name.suffixes))
if tweets_id_range.oldest_id:
old_tweet_count = write_tweets(oldest_tweets_file_name, screen_name, max_id=tweets_id_range.oldest_id - 1)
logging.info('%s: appending %s old tweets', tweets_file_name, old_tweet_count)
swap_tweets_file_name = tweets_file_name.with_suffix('.swap' + ''.join(tweets_file_name.suffixes))
with open(swap_tweets_file_name, 'w') as swap_file, \
open(tweets_file_name, 'r') as existing_file:
swap_file.write(existing_file.readline())
with open(newest_tweets_file_name, 'r') as newest_tweets_file:
for line in newest_tweets_file:
swap_file.write(line)
for line in existing_file:
swap_file.write(line)
if oldest_tweets_file_name.exists():
with open(oldest_tweets_file_name, 'r') as oldest_tweets_file:
for line in oldest_tweets_file:
swap_file.write(line)
swap_tweets_file_name.rename(tweets_file_name)
os.remove(newest_tweets_file_name)
if oldest_tweets_file_name.exists():
os.remove(oldest_tweets_file_name)
tweets_id_range = get_tweets_file_id_range(tweets_file_name)
logging.info('%s: tweet ID range (after): count: %s; newest: %s; oldest: %s',
tweets_file_name, tweets_id_range.count, tweets_id_range.newest_id, tweets_id_range.oldest_id)
Вы заметите, что последовательные прогоны этого будут возвращать больше данных, пока вы не нажмете конец того, что может предоставить API Twitter, например,
▶ python test.py realDonaldTrump
INFO:root:realDonaldTrump_tweets.csv: tweet ID range (before): count: 350; newest: 1239685852093169664; oldest: 1235005879226961924
INFO:root:realDonaldTrump_tweets.csv: prepending 0 new tweets
INFO:root:realDonaldTrump_tweets.csv: appending 1799 old tweets
INFO:root:realDonaldTrump_tweets.csv: tweet ID range (after): count: 2149; newest: 1239685852093169664; oldest: 1214517113437720576
▶ python test.py realDonaldTrump
INFO:root:realDonaldTrump_tweets.csv: tweet ID range (before): count: 2149; newest: 1239685852093169664; oldest: 1214517113437720576
INFO:root:realDonaldTrump_tweets.csv: prepending 0 new tweets
INFO:root:realDonaldTrump_tweets.csv: appending 1045 old tweets
INFO:root:realDonaldTrump_tweets.csv: tweet ID range (after): count: 3194; newest: 1239685852093169664; oldest: 1203103574781317121
▶ python test.py realDonaldTrump
INFO:root:realDonaldTrump_tweets.csv: tweet ID range (before): count: 3194; newest: 1239685852093169664; oldest: 1203103574781317121
INFO:root:realDonaldTrump_tweets.csv: prepending 0 new tweets
INFO:root:realDonaldTrump_tweets.csv: appending 0 old tweets
INFO:root:realDonaldTrump_tweets.csv: tweet ID range (after): count: 3194; newest: 1239685852093169664; oldest: 1203103574781317121
Этот пример не предназначен для предоставления готовой к реализации реализации; однако, это должно дать вам несколько новых моментов для размышления, и это должно помочь вам преодолеть проблему, изложенную в вашем вопросе.