├── seek ├── __init__.py ├── search.py └── seek.py ├── MANIFEST.in ├── requirements.txt ├── LICENSE ├── README.md └── setup.py /seek/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md LICENSE requirements.txt 2 | recursive-include soundscrape *.py 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | BeautifulSoup==3.2.1 2 | args==0.1.0 3 | clint==0.5.1 4 | gnureadline==6.3.8 5 | pyglance>=0.3.1 6 | requests==2.18.3 7 | wsgiref==0.1.2 8 | -------------------------------------------------------------------------------- /seek/search.py: -------------------------------------------------------------------------------- 1 | # Search functionality for Seek 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | import requests 5 | import urllib 6 | 7 | def search_engine(term, result=0): 8 | # TODO: Get engine preference from config. 9 | return search_duckduckgo(term, result) 10 | 11 | # This doesn't work yet 12 | def search_google(term, result=0): 13 | result = requests.get("https://www.google.com/#q=" + urllib.quote_plus(term)) 14 | 15 | def search_duckduckgo(term, result=0): 16 | search_result = requests.get('https://duckduckgo.com/html/?q=' + urllib.quote_plus(term)) 17 | soup = BeautifulSoup(search_result.content) 18 | 19 | # Skip the ads. Sorry DDG. 20 | # There is probably a better way to do this using a better selector rather than looping. TODO. 21 | divs = soup.findAll('div', 'results_links') 22 | for div in divs: 23 | if 'web-result-sponsored' in div['class']: 24 | divs.remove(div) 25 | 26 | link = divs[result] 27 | link_url = link.findAll('a')[0]['href'] 28 | 29 | return link_url 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Rich Jones 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![seek. command line nirvana.](http://i.imgur.com/2wEYui1.png) 2 | # seek 3 | 4 | Display internet search results without ever leaving your terminal. Oh, and it can speed read the results as well. Basically, it's command line nirvana. 5 | 6 | Seek is a sister to [howdoi](https://github.com/gleitz/howdoi/) and [Glance](https://github.com/Miserlou/glance/). 7 | 8 | ## Installation 9 | 10 | pip install seek 11 | 12 | ## Examples 13 | 14 | $ seek a nice up of tea orwell 15 | 16 | If you look up 'tea' in the first cookery book that comes to hand you will probably find that it is unmentioned; or at most you will find a few lines of sketchy instructions which give no ruling on several of the most important points. [etc.] 17 | A Nice Cup of Tea 18 | http://www.booksatoz.com/witsend/tea/orwell.htm 19 | 20 | $ seek a nice cup of tea orwell --glance 21 | A Nice Cup of Tea 22 | http://www.booksatoz.com/witsend/tea/orwell.htm 23 | stimulation <--- (This is animated) 24 | 25 | ## Features: 26 | 27 | * [Glance](http://glance.wtf) mode! Powered by [pyglance](http://github.com/Miserlou/pyglance). 28 | * Diffbot article extraction 29 | * Searches DuckDuckGo, Google coming soon (maybe). 30 | 31 | BSD 3-clause, 2014-2015. 32 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup 3 | 4 | # Set external files 5 | README = open(os.path.join(os.path.dirname(__file__), 'README.md')).read() 6 | with open(os.path.join(os.path.dirname(__file__), 'requirements.txt')) as f: 7 | required = f.read().splitlines() 8 | 9 | # allow setup.py to be run from any path 10 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 11 | 12 | setup( 13 | name='seek', 14 | version='0.2.3', 15 | packages=['seek'], 16 | install_requires=required, 17 | include_package_data=True, 18 | license='MIT License', 19 | description='Terminal search and speed reader.', 20 | long_description=README, 21 | url='https://github.com/Miserlou/Seek', 22 | author='Rich Jones', 23 | author_email='rich@openwatch.net', 24 | entry_points={ 25 | 'console_scripts': [ 26 | 'seek = seek.seek:command_line_runner', 27 | ] 28 | }, 29 | classifiers=[ 30 | 'Environment :: Console', 31 | 'License :: OSI Approved :: Apache Software License', 32 | 'Operating System :: OS Independent', 33 | 'Programming Language :: Python', 34 | 'Programming Language :: Python :: 2.6', 35 | 'Programming Language :: Python :: 2.7', 36 | 'Topic :: Internet :: WWW/HTTP', 37 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 38 | ], 39 | ) 40 | -------------------------------------------------------------------------------- /seek/seek.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import requests 4 | import urllib 5 | import argparse 6 | 7 | from pyglance import glance, get_page_data 8 | from search import search_engine 9 | 10 | def print_body(data): 11 | 12 | if 'text' in data: 13 | print data['text'] 14 | print "" 15 | print data['title'] 16 | print data['url'] 17 | else: 18 | print "No usable text found." 19 | 20 | def glance_body(data, speed=600): 21 | print data['title'] 22 | print data['url'] 23 | glance(data['text'], speed) 24 | 25 | def get_parser(): 26 | parser = argparse.ArgumentParser(description='Command line searching for incredibly lazy people.') 27 | parser.add_argument('query', metavar='QUERY', type=str, nargs='*', 28 | help='the question to answer') 29 | parser.add_argument('-p','--pos', help='select answer in specified position (default: 0)', default=0, type=int) 30 | parser.add_argument('-t','--text', help='display answer as plaintext', default=True, dest='plaintext', action='store_true') 31 | parser.add_argument('-g','--glance', help='display result in glance format', default=False, dest='glancemode', action='store_true') 32 | parser.add_argument('-s','--speed', help='WPM to glance at.', default=600, dest='speed', type=int) 33 | return parser 34 | 35 | def command_line_runner(): 36 | parser = get_parser() 37 | args = vars(parser.parse_args()) 38 | if not args['query']: 39 | parser.print_help() 40 | return 41 | else: 42 | try: 43 | seek(args) 44 | except (KeyboardInterrupt, SystemExit): 45 | print "" 46 | quit() 47 | except Exception, e: 48 | quit() 49 | 50 | def seek(args): 51 | term = ' '.join(args['query']).replace('?', '') 52 | link_url = search_engine(term, args['pos']) 53 | data = get_page_data(link_url) 54 | if args['glancemode']: 55 | glance_body(data, args['speed']) 56 | else: 57 | print_body(data) 58 | 59 | if __name__ == '__main__': 60 | try: 61 | command_line_runner() 62 | except (KeyboardInterrupt, SystemExit): 63 | print "" 64 | quit() 65 | except Exception, e: 66 | quit() 67 | --------------------------------------------------------------------------------