From 382cfc4157c46a442b2895818d7dd6af26409ec9 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 13 Nov 2020 14:47:41 -0500 Subject: [PATCH] Changed (significantly) to use the new User Settings API to store all of the credentials and search history --- DemoPrograms/Demo_Reddit_Search.py | 272 ++++++++++++++++++++--------- 1 file changed, 190 insertions(+), 82 deletions(-) diff --git a/DemoPrograms/Demo_Reddit_Search.py b/DemoPrograms/Demo_Reddit_Search.py index e8b73378..4f48080f 100644 --- a/DemoPrograms/Demo_Reddit_Search.py +++ b/DemoPrograms/Demo_Reddit_Search.py @@ -5,103 +5,211 @@ from webbrowser import open_new_tab """ 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. - 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 """ -# To use the Reddit APIs you will need to sign up by visiting this site: -# 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 +settings = sg.UserSettings() -# The list of subreddits to search -sub_names = ('Python', 'learnpython', 'learnprogramming', 'PySimpleGUI', 'AskProgramming', 'Coding', 'Programming') +def make_search_row(item_number): + 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': - sg.popup_error('You must register with Reddit to get credentials first', - 'Modify the reddit_praw_parameters dictionary with the details', - r'Go here to register: https://www.reddit.com/prefs/apps/') - exit() + layout = [[sg.T('Reddit PRAW Settings', font='default 15')], + [sg.T('Note - You must register with Reddit to obtain PRAW credentials')], + input_line('Client ID', '-CLIENT ID-', settings['client_id']), + input_line('Client Secret', '-CLIENT SECRET-', settings['client_secret']), + 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')], - [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')], ] + event, values = sg.Window('Reddit Reader Settings', layout).read(close=True) -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() - if event in (sg.WIN_CLOSED, 'Exit'): - break - subs_to_read = values['-SUBS-'] - search_string = values['-SEARCH STRING-'] - if event.startswith('Start'): - for sub in subs_to_read: - window['-OUT SUB-'].update(sub) - subreddit = reddit.subreddit(sub) - submissions = subreddit.new(limit=int(values['-LIMIT-'])) - num_submissions = int(values['-LIMIT-']) - for num, submission in enumerate(submissions): - opened = False - text = ''.join([t 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() - if search_string in text: - opened = True - window['-MLINE-'].update(str(title) + '\n', append=True, autoscroll=True) - if values['-BROWSER-']: - open_new_tab(submission.url) - else: - sg.popup_scrolled(f'Found {search_string} in post', 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 - comments = submission.comments - for comment in comments: - if search_string in comment.body: - window['-MLINE-'].update(str(title) + '\n', append=True, autoscroll=True) - comment = ''.join([t for t in comment.body if ord(t) in range(65536)]) - if values['-BROWSER-']: - if not opened: + +def main(): + while True: + # reddit_praw_parameters = settings.get_dict() + reddit_praw_parameters = {'client_id' : settings['client_id'], 'client_secret':settings['client_secret'], + 'user_agent' : settings['user_agent'], 'username' : settings['username'], 'password': settings['password']} + try: + reddit = praw.Reddit(**reddit_praw_parameters) + break + except Exception as e: + sg.popup('Problem with your settings file', e) + if not settings_window(): + sg.popup_error('Must set settings before can continue') + exit() + + # Read your Reddit PRAW configuration from a json file + # try: + # with open(path.join(path.dirname(__file__), r'praw.cfg'), 'r') as f: + # reddit_praw_parameters = load(f) + # except: + # sg.popup_error('Failed loading the Reddit API login credential file.', 'The File should be named:', path.join(path.dirname(__file__), r'praw.cfg')) + # exit() + # To use the Reddit APIs you will need to sign up by visiting this site: + # https://www.reddit.com/prefs/apps/ + # You will receive a client_id and client_secret string that you can + # enter along with your normal Reddit ID & Password and save into a file named praw.cfg + + sub_names = ('Python', 'learnpython', 'learnprogramming', 'PySimpleGUI', 'madeinpython', 'AskProgramming', 'Coding', 'Programming', 'learnmachinelearning', 'MLQuestions', 'datascience', 'MachineLearning', 'pythontips', 'pystats', 'pythoncoding', 'pythondev', 'scipy') + + sg.theme('Dark Red') + num_searches = 1 + search_layout = [[sg.B('+'), sg.T('Add term')]] + search_layout += [make_search_row(i) for i in range(num_searches)] + layout = [[sg.Text('Reddit Searcher', font='Any 18')], + [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) opened = True - else: - sg.popup_scrolled(f'Found {search_string} in comment', submission.url, f'\nTITLE: {title}', comment, title=title, - non_blocking=True) - window.refresh() - event, values = window.read(timeout=0) - if event in (sg.WIN_CLOSED, 'Exit'): + elif values['-POPUP-']: + sg.popup_scrolled(f'Search found in comment', submission.url, f'\nTITLE: {title}', comment_text, title=title, non_blocking=True) + window.refresh() + 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 + 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 - if event in (sg.WIN_CLOSED, 'Exit'): - window['-OUT SUB-'].update('*** Aborted ***') + else: + 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 - else: - window['-OUT SUB-'].update('*** Done! ***') - if event == sg.WIN_CLOSED: - break -window.close() + if event == '+': + window.extend_layout(window['-SEARCH FRAME-'], [make_search_row(num_searches)]) + num_searches += 1 + if event == '-LISTBOX-': + 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() \ No newline at end of file