Changed (significantly) to use the new User Settings API to store all of the credentials and search history

This commit is contained in:
PySimpleGUI 2020-11-13 14:47:41 -05:00
parent 1ec6e6b1ff
commit 382cfc4157
1 changed files with 190 additions and 82 deletions

View File

@ -5,103 +5,211 @@ from webbrowser import open_new_tab
""" """
Demo Reddit Searcher Demo Reddit Searcher
Will search through a list of subreddits for a string of your choice. You can search only the Will search through a list of subreddits for a string(s) of your choice. You can search only the
posts or the posts and comments. When a match is found the title will be displayed in the window. posts or the posts and comments. When a match is found the title will be displayed in the window.
The post details are displayed in a popup window or launched a browser tab to the post on Reddit. Two progress meters show the current progress.
Once completed, a listbox is populared with he responses. Click on the titles and a brower tab
is opened to the topic.
NOTE - you must register with Reddit as a developer. Instructions on doing that are below NOTE - you must register with Reddit as a developer. https://www.reddit.com/prefs/apps/
You can set these credentials using the "Settings Window".
Copyright 2020 PySimpleGUI Copyright 2020 PySimpleGUI
""" """
# To use the Reddit APIs you will need to sign up by visiting this site: settings = sg.UserSettings()
# https://www.reddit.com/prefs/apps/
# You will receive a client_id and client_secret string that you can
# enter below along with your normal Reddit ID & Password
reddit_praw_parameters = {'client_id': ' YOU MUST REGISTER ', # get from Reddit PRAW signup
'client_secret': ' YOU MUST REGISTER ', # get from Reddit PRAW signup
'user_agent': 'YourRedditID', # same as user name on Reddit
'username': 'YourRedditID', # same as user name on Reddit
'password': 'YourRedditPassword'} # your Reddit password
# The list of subreddits to search def make_search_row(item_number):
sub_names = ('Python', 'learnpython', 'learnprogramming', 'PySimpleGUI', 'AskProgramming', 'Coding', 'Programming') search_layout = [sg.Combo(sorted(settings.get('-search string-', [])), settings['-last search-'], size=(45,1), k=('-SEARCH STRING-', item_number)),
# sg.In(key=('-SEARCH STRING-', item_number)),
sg.CB('Require', key=('-SEARCH REQUIRED-', item_number))]
return search_layout
sg.theme('Dark Red') def settings_window():
def input_line(text, key, default):
return [sg.T(text, size=(15,1), justification='r'), sg.In(default, size=(20,1), k=key)]
if reddit_praw_parameters['username'] == 'YourRedditID': layout = [[sg.T('Reddit PRAW Settings', font='default 15')],
sg.popup_error('You must register with Reddit to get credentials first', [sg.T('Note - You must register with Reddit to obtain PRAW credentials')],
'Modify the reddit_praw_parameters dictionary with the details', input_line('Client ID', '-CLIENT ID-', settings['client_id']),
r'Go here to register: https://www.reddit.com/prefs/apps/') input_line('Client Secret', '-CLIENT SECRET-', settings['client_secret']),
exit() input_line('User Agent', '-USER AGENT-', settings['user_agent']),
input_line('Username', '-USERNAME-', settings['username']),
input_line('Password', '-PASSWORD-', settings['password']),
[sg.CB('Clear Search History', k='-CLEAR HISTORY-')],
]
layout += [[sg.Ok(), sg.Cancel()]]
layout = [[sg.Text('Reddit Reader')], event, values = sg.Window('Reddit Reader Settings', layout).read(close=True)
[sg.Listbox(sub_names, size=(25, 7), select_mode=sg.SELECT_MODE_MULTIPLE, key='-SUBS-')],
[sg.Text('Search for:'), sg.Input(key='-SEARCH STRING-')],
[sg.Checkbox('Look in Comments', key='-COMMENTS-')],
[sg.Checkbox('Show finds in browser', key='-BROWSER-')],
[sg.Text('Limit: '), sg.Spin(list(range(100, 5000)), size=(4, 1), key='-LIMIT-')],
[sg.Text('Now Reading Sub:'), sg.Text(size=(25, 1), key='-OUT SUB-')],
[sg.Text('Now Reading Post:'), sg.Text(size=(40, 1), key='-OUT POST-')],
[sg.Text('Posts Read:'), sg.Text(size=(25, 1), key='-NUM POSTS-')],
[sg.Multiline(size=(60, 10), key='-MLINE-')],
[sg.ProgressBar(100, orientation='horizontal', size=(30, 20), key='-PROG-')],
[sg.Button('Start Scrape'), sg.Button('Exit')], ]
window = sg.Window('Reddit Reader', layout) if event == 'Ok':
settings['client_id'] = values['-CLIENT ID-']
settings['client_secret'] = values['-CLIENT SECRET-']
settings['user_agent'] = values['-USER AGENT-']
settings['username'] = values['-USERNAME-']
settings['password'] = values['-PASSWORD-']
if values['-CLEAR HISTORY-']:
settings['-search string-'] = []
return True
reddit = praw.Reddit(**reddit_praw_parameters) return False
while True: # Event Loop
event, values = window.read() def main():
if event in (sg.WIN_CLOSED, 'Exit'): while True:
break # reddit_praw_parameters = settings.get_dict()
subs_to_read = values['-SUBS-'] reddit_praw_parameters = {'client_id' : settings['client_id'], 'client_secret':settings['client_secret'],
search_string = values['-SEARCH STRING-'] 'user_agent' : settings['user_agent'], 'username' : settings['username'], 'password': settings['password']}
if event.startswith('Start'): try:
for sub in subs_to_read: reddit = praw.Reddit(**reddit_praw_parameters)
window['-OUT SUB-'].update(sub) break
subreddit = reddit.subreddit(sub) except Exception as e:
submissions = subreddit.new(limit=int(values['-LIMIT-'])) sg.popup('Problem with your settings file', e)
num_submissions = int(values['-LIMIT-']) if not settings_window():
for num, submission in enumerate(submissions): sg.popup_error('Must set settings before can continue')
opened = False exit()
text = ''.join([t for t in submission.selftext if ord(t) in range(65536)])
window['-PROG-'].update_bar(100 * (num + 1) // num_submissions) # Read your Reddit PRAW configuration from a json file
title = ''.join([t for t in submission.title if ord(t) in range(65536)]) # try:
window['-NUM POSTS-'].update(num) # with open(path.join(path.dirname(__file__), r'praw.cfg'), 'r') as f:
window.refresh() # reddit_praw_parameters = load(f)
if search_string in text: # except:
opened = True # sg.popup_error('Failed loading the Reddit API login credential file.', 'The File should be named:', path.join(path.dirname(__file__), r'praw.cfg'))
window['-MLINE-'].update(str(title) + '\n', append=True, autoscroll=True) # exit()
if values['-BROWSER-']: # To use the Reddit APIs you will need to sign up by visiting this site:
open_new_tab(submission.url) # https://www.reddit.com/prefs/apps/
else: # You will receive a client_id and client_secret string that you can
sg.popup_scrolled(f'Found {search_string} in post', submission.url, f'\nTITLE: {title}', str(text), title=title, non_blocking=True) # enter along with your normal Reddit ID & Password and save into a file named praw.cfg
window['-OUT POST-'].update(str(title))
if values['-COMMENTS-']: # if should also search comments sub_names = ('Python', 'learnpython', 'learnprogramming', 'PySimpleGUI', 'madeinpython', 'AskProgramming', 'Coding', 'Programming', 'learnmachinelearning', 'MLQuestions', 'datascience', 'MachineLearning', 'pythontips', 'pystats', 'pythoncoding', 'pythondev', 'scipy')
comments = submission.comments
for comment in comments: sg.theme('Dark Red')
if search_string in comment.body: num_searches = 1
window['-MLINE-'].update(str(title) + '\n', append=True, autoscroll=True) search_layout = [[sg.B('+'), sg.T('Add term')]]
comment = ''.join([t for t in comment.body if ord(t) in range(65536)]) search_layout += [make_search_row(i) for i in range(num_searches)]
if values['-BROWSER-']: layout = [[sg.Text('Reddit Searcher', font='Any 18')],
if not opened: [sg.Frame('Choose Subs',
[[sg.Listbox(sub_names, size=(25, 7), select_mode=sg.SELECT_MODE_MULTIPLE, key='-SUBS-')]]),
sg.Frame('Options',
[[sg.Checkbox('Look in Comments', True, key='-COMMENTS-')],
[sg.Checkbox('Show finds in browser', key='-BROWSER-')],
[sg.Checkbox('Show popup', key='-POPUP-')],
[sg.Text('Limit: '), sg.Spin(list(range(200, 5000)), size=(4, 1), key='-LIMIT-')]])],
[sg.Frame('Search Terms', search_layout, key='-SEARCH FRAME-' )],
[sg.Frame('Status',[
[sg.Text('Reading Sub:'), sg.Text(size=(25, 1), key='-OUT SUB-')],
[sg.Text('Reading Post:'), sg.Text(size=(40, 1), key='-OUT POST-')],
[sg.Text('Posts Read:'), sg.Text(size=(25, 1), key='-NUM POSTS-')],
[sg.T('Sub Progress', size=(12,1)), sg.ProgressBar(100, orientation='horizontal', size=(30, 20), key='-PROG-')],
[sg.T('Overall Progress', size=(12,1)),sg.ProgressBar(100, orientation='horizontal', size=(30, 20), key='-PROG-TOTAL-')],])],
[sg.Frame('Results (Click to Lauch in Browser)',
[[sg.Listbox([], size=(60,10), key='-LISTBOX-', enable_events=True)]])],
[sg.Button('Start Search', bind_return_key=True), sg.B('Settings'), sg.Button('Exit')], ]
window = sg.Window('Reddit Reader', layout, icon=reddit_icon, use_default_focus=False)
results = {}
while True: # Event Loop
event, values = window.read()
if event in (None, 'Exit'):
break
if event == 'Settings':
if settings_window():
reddit = praw.Reddit(**reddit_praw_parameters)
subs_to_read = values['-SUBS-']
if event.startswith('Start'):
window['-LISTBOX-'].update([''])
results = {}
search_list = [] # make a list of tuples (search term, bool required)
for v in values:
if isinstance(v, tuple): # if value is a tuple
if v[0] == '-SEARCH STRING-':
search_list.append((values[v].lower(), values[('-SEARCH REQUIRED-', v[1])]))
settings['-search string-'] = list(set(settings.get('-search string-', []) + [values['-SEARCH STRING-', v[1]], ]))
settings['-last search-'] = search_list[0][0]
print('last search = ', settings['-last search-'])
print('Search list = ', search_list)
# Loop through the subs
for sub_count, sub in enumerate(subs_to_read):
window['-OUT SUB-'].update(sub)
subreddit = reddit.subreddit(sub)
submissions = subreddit.new(limit=int(values['-LIMIT-']))
num_submissions = int(values['-LIMIT-'])
# Loop through submissions
for num, submission in enumerate(submissions):
opened = False
text = ''.join([t.lower() for t in submission.selftext if ord(t) in range(65536)])
window['-PROG-'].update_bar(100 * (num + 1) // num_submissions)
title = ''.join([t for t in submission.title if ord(t) in range(65536)])
window['-NUM POSTS-'].update(num)
window.refresh()
found = False
for search_item in search_list:
if search_item[0] and search_item[0] in text:
found = True
elif search_item[1]:
found = False
break
if found:
opened = True
results[title] = submission.url
window['-LISTBOX-'].update(list(results.keys()))
if values['-BROWSER-']:
open_new_tab(submission.url)
elif values['-POPUP-']:
sg.popup_scrolled(f'Search found', submission.url, f'\nTITLE: {title}', str(text), title=title, non_blocking=True)
window['-OUT POST-'].update(str(title))
if values['-COMMENTS-']: # if should also search comments
for comment in submission.comments:
found = False
for search_item in search_list:
try:
if search_item[0] and search_item[0] in comment.body.lower():
found = True
elif search_item[1]:
found = False
break
except Exception as e:
print(f'Exception searching the comments:\n{e}')
if found:
results[title] = submission.url
window['-LISTBOX-'].update(list(results.keys()))
comment_text = ''.join([t for t in comment.body if ord(t) in range(65536)])
if values['-BROWSER-'] and not opened:
open_new_tab(submission.url) open_new_tab(submission.url)
opened = True opened = True
else: elif values['-POPUP-']:
sg.popup_scrolled(f'Found {search_string} in comment', submission.url, f'\nTITLE: {title}', comment, title=title, sg.popup_scrolled(f'Search found in comment', submission.url, f'\nTITLE: {title}', comment_text, title=title, non_blocking=True)
non_blocking=True) window.refresh()
window.refresh() event, values = window.read(timeout=0)
event, values = window.read(timeout=0) if event == '-LISTBOX-': # experimental - see if clicked on an item in the list while it's still being built
if event in (sg.WIN_CLOSED, 'Exit'): url = results.get(values['-LISTBOX-'][0])
if url: open_new_tab(url)
if event in (None, 'Exit'):
break
# Done processing the single sub, so update the total progress bar
window['-PROG-TOTAL-'].update_bar(100 * (sub_count + 1) // len(subs_to_read))
if event in (None, 'Exit'):
window['-OUT SUB-'].update('*** Aborted ***')
break break
if event in (sg.WIN_CLOSED, 'Exit'): else:
window['-OUT SUB-'].update('*** Aborted ***') window['-OUT SUB-'].update('*** Done with this sub ***')
else: # if made it through the loop, then show a popup saying completed
window['-OUT SUB-'].update('*** DONE with all subs ***')
if event is None:
break break
else: if event == '+':
window['-OUT SUB-'].update('*** Done! ***') window.extend_layout(window['-SEARCH FRAME-'], [make_search_row(num_searches)])
if event == sg.WIN_CLOSED: num_searches += 1
break if event == '-LISTBOX-':
window.close() url = results.get(values['-LISTBOX-'][0])
if url: open_new_tab(url)
window.close()
if __name__ == '__main__':
reddit_icon = b'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'
main()