mirror of
				https://github.com/searxng/searxng.git
				synced 2025-11-04 03:27:06 -05:00 
			
		
		
		
	[enh][mod] code refactor ++ search engine filtering
This commit is contained in:
		
							parent
							
								
									e56d7a58c7
								
							
						
					
					
						commit
						0540ea9ee2
					
				
							
								
								
									
										94
									
								
								searx/search.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								searx/search.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					from searx.engines import (
 | 
				
			||||||
 | 
					    categories, engines, engine_shortcuts
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from searx.languages import language_codes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Search(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """Search information container"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, request):
 | 
				
			||||||
 | 
					        super(Search, self).__init__()
 | 
				
			||||||
 | 
					        self.query = None
 | 
				
			||||||
 | 
					        self.engines = []
 | 
				
			||||||
 | 
					        self.categories = []
 | 
				
			||||||
 | 
					        query_engines = []
 | 
				
			||||||
 | 
					        self.paging = False
 | 
				
			||||||
 | 
					        self.pageno = 1
 | 
				
			||||||
 | 
					        self.lang = 'all'
 | 
				
			||||||
 | 
					        if request.cookies.get('blocked_engines'):
 | 
				
			||||||
 | 
					            self.blocked_engines = request.cookies['blocked_engines'].split(',')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.blocked_engines = []
 | 
				
			||||||
 | 
					        self.results = []
 | 
				
			||||||
 | 
					        self.suggestions = []
 | 
				
			||||||
 | 
					        self.request_data = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if request.cookies.get('language')\
 | 
				
			||||||
 | 
					           and request.cookies['language'] in (x[0] for x in language_codes):
 | 
				
			||||||
 | 
					            self.lang = request.cookies['language']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if request.method == 'POST':
 | 
				
			||||||
 | 
					            self.request_data = request.form
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.request_data = request.args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # TODO better exceptions
 | 
				
			||||||
 | 
					        if not self.request_data.get('q'):
 | 
				
			||||||
 | 
					            raise Exception('noquery')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.query = self.request_data['q']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pageno_param = self.request_data.get('pageno', '1')
 | 
				
			||||||
 | 
					        if not pageno_param.isdigit() or int(pageno_param) < 1:
 | 
				
			||||||
 | 
					            raise Exception('wrong pagenumber')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.pageno = int(pageno_param)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        query_parts = self.query.split()
 | 
				
			||||||
 | 
					        if query_parts[0].startswith('!'):
 | 
				
			||||||
 | 
					            prefix = query_parts[0][1:].replace('_', ' ')
 | 
				
			||||||
 | 
					            if prefix in engine_shortcuts\
 | 
				
			||||||
 | 
					               and not engine_shortcuts[prefix] in self.blocked_engines:
 | 
				
			||||||
 | 
					                self.engines.append({'category': 'none',
 | 
				
			||||||
 | 
					                                     'name': engine_shortcuts[prefix]})
 | 
				
			||||||
 | 
					            elif prefix in engines\
 | 
				
			||||||
 | 
					                    and not prefix in self.blocked_engines:
 | 
				
			||||||
 | 
					                self.engines.append({'category': 'none',
 | 
				
			||||||
 | 
					                                    'name': prefix})
 | 
				
			||||||
 | 
					            elif prefix in categories:
 | 
				
			||||||
 | 
					                self.engines.extend({'category': prefix,
 | 
				
			||||||
 | 
					                                    'name': engine.name}
 | 
				
			||||||
 | 
					                                    for engine in categories[prefix]
 | 
				
			||||||
 | 
					                                    if not engine in self.blocked_engines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(query_engines):
 | 
				
			||||||
 | 
					            self.query = self.query.replace(query_parts[0], '', 1).strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.categories = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(self.engines):
 | 
				
			||||||
 | 
					            self.categories = list(set(engine['category']
 | 
				
			||||||
 | 
					                                           for engine in self.engines))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            for pd_name, pd in self.request_data.items():
 | 
				
			||||||
 | 
					                if pd_name.startswith('category_'):
 | 
				
			||||||
 | 
					                    category = pd_name[9:]
 | 
				
			||||||
 | 
					                    if not category in categories:
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					                    self.categories.append(category)
 | 
				
			||||||
 | 
					            if not len(self.categories):
 | 
				
			||||||
 | 
					                cookie_categories = request.cookies.get('categories', '')
 | 
				
			||||||
 | 
					                cookie_categories = cookie_categories.split(',')
 | 
				
			||||||
 | 
					                for ccateg in cookie_categories:
 | 
				
			||||||
 | 
					                    if ccateg in categories:
 | 
				
			||||||
 | 
					                        self.categories.append(ccateg)
 | 
				
			||||||
 | 
					            if not len(self.categories):
 | 
				
			||||||
 | 
					                self.categories = ['general']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for categ in self.categories:
 | 
				
			||||||
 | 
					                self.engines.extend({'category': categ,
 | 
				
			||||||
 | 
					                                     'name': x.name}
 | 
				
			||||||
 | 
					                                    for x in categories[categ]
 | 
				
			||||||
 | 
					                                    if not x.name in self.blocked_engines)
 | 
				
			||||||
@ -39,7 +39,7 @@ class ViewsTestCase(SearxTestCase):
 | 
				
			|||||||
        self.assertEqual(result.status_code, 200)
 | 
					        self.assertEqual(result.status_code, 200)
 | 
				
			||||||
        self.assertIn('<div class="title"><h1>searx</h1></div>', result.data)
 | 
					        self.assertIn('<div class="title"><h1>searx</h1></div>', result.data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @patch('searx.webapp.search')
 | 
					    @patch('searx.webapp.do_search')
 | 
				
			||||||
    def test_index_html(self, search):
 | 
					    def test_index_html(self, search):
 | 
				
			||||||
        search.return_value = (
 | 
					        search.return_value = (
 | 
				
			||||||
            self.test_results,
 | 
					            self.test_results,
 | 
				
			||||||
@ -55,7 +55,7 @@ class ViewsTestCase(SearxTestCase):
 | 
				
			|||||||
            result.data
 | 
					            result.data
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @patch('searx.webapp.search')
 | 
					    @patch('searx.webapp.do_search')
 | 
				
			||||||
    def test_index_json(self, search):
 | 
					    def test_index_json(self, search):
 | 
				
			||||||
        search.return_value = (
 | 
					        search.return_value = (
 | 
				
			||||||
            self.test_results,
 | 
					            self.test_results,
 | 
				
			||||||
@ -71,7 +71,7 @@ class ViewsTestCase(SearxTestCase):
 | 
				
			|||||||
        self.assertEqual(
 | 
					        self.assertEqual(
 | 
				
			||||||
            result_dict['results'][0]['url'], 'http://first.test.xyz')
 | 
					            result_dict['results'][0]['url'], 'http://first.test.xyz')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @patch('searx.webapp.search')
 | 
					    @patch('searx.webapp.do_search')
 | 
				
			||||||
    def test_index_csv(self, search):
 | 
					    def test_index_csv(self, search):
 | 
				
			||||||
        search.return_value = (
 | 
					        search.return_value = (
 | 
				
			||||||
            self.test_results,
 | 
					            self.test_results,
 | 
				
			||||||
@ -86,7 +86,7 @@ class ViewsTestCase(SearxTestCase):
 | 
				
			|||||||
            result.data
 | 
					            result.data
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @patch('searx.webapp.search')
 | 
					    @patch('searx.webapp.do_search')
 | 
				
			||||||
    def test_index_rss(self, search):
 | 
					    def test_index_rss(self, search):
 | 
				
			||||||
        search.return_value = (
 | 
					        search.return_value = (
 | 
				
			||||||
            self.test_results,
 | 
					            self.test_results,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										129
									
								
								searx/webapp.py
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								searx/webapp.py
									
									
									
									
									
								
							@ -28,10 +28,12 @@ from flask import (
 | 
				
			|||||||
from flask.ext.babel import Babel
 | 
					from flask.ext.babel import Babel
 | 
				
			||||||
from searx import settings, searx_dir
 | 
					from searx import settings, searx_dir
 | 
				
			||||||
from searx.engines import (
 | 
					from searx.engines import (
 | 
				
			||||||
    search, categories, engines, get_engines_stats, engine_shortcuts
 | 
					    search as do_search, categories, engines, get_engines_stats,
 | 
				
			||||||
 | 
					    engine_shortcuts
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from searx.utils import UnicodeWriter, highlight_content, html_to_text
 | 
					from searx.utils import UnicodeWriter, highlight_content, html_to_text
 | 
				
			||||||
from searx.languages import language_codes
 | 
					from searx.languages import language_codes
 | 
				
			||||||
 | 
					from searx.search import Search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app = Flask(
 | 
					app = Flask(
 | 
				
			||||||
@ -94,95 +96,32 @@ def render(template_name, **kwargs):
 | 
				
			|||||||
    return render_template(template_name, **kwargs)
 | 
					    return render_template(template_name, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def parse_query(query):
 | 
					 | 
				
			||||||
    query_engines = []
 | 
					 | 
				
			||||||
    query_parts = query.split()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if query_parts[0].startswith('!'):
 | 
					 | 
				
			||||||
        prefix = query_parts[0][1:].replace('_', ' ')
 | 
					 | 
				
			||||||
        if prefix in engine_shortcuts:
 | 
					 | 
				
			||||||
            query_engines.append({'category': 'none',
 | 
					 | 
				
			||||||
                                  'name': engine_shortcuts[prefix]})
 | 
					 | 
				
			||||||
        elif prefix in engines:
 | 
					 | 
				
			||||||
            query_engines.append({'category': 'none',
 | 
					 | 
				
			||||||
                                  'name': prefix})
 | 
					 | 
				
			||||||
        elif prefix in categories:
 | 
					 | 
				
			||||||
            query_engines.extend({'category': prefix,
 | 
					 | 
				
			||||||
                                  'name': engine.name}
 | 
					 | 
				
			||||||
                                 for engine in categories[prefix])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if len(query_engines):
 | 
					 | 
				
			||||||
        query = query.replace(query_parts[0], '', 1).strip()
 | 
					 | 
				
			||||||
    return query, query_engines
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@app.route('/', methods=['GET', 'POST'])
 | 
					@app.route('/', methods=['GET', 'POST'])
 | 
				
			||||||
def index():
 | 
					def index():
 | 
				
			||||||
    """Render index page.
 | 
					    """Render index page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Supported outputs: html, json, csv, rss.
 | 
					    Supported outputs: html, json, csv, rss.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    paging = False
 | 
					 | 
				
			||||||
    lang = 'all'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if request.cookies.get('language')\
 | 
					    try:
 | 
				
			||||||
       and request.cookies['language'] in (x[0] for x in language_codes):
 | 
					        search = Search(request)
 | 
				
			||||||
        lang = request.cookies['language']
 | 
					    except:
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if request.method == 'POST':
 | 
					 | 
				
			||||||
        request_data = request.form
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        request_data = request.args
 | 
					 | 
				
			||||||
    if not request_data.get('q'):
 | 
					 | 
				
			||||||
        return render('index.html')
 | 
					        return render('index.html')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pageno_param = request_data.get('pageno', '1')
 | 
					    # TODO moar refactor - do_search integration into Search class
 | 
				
			||||||
    if not pageno_param.isdigit() or int(pageno_param) < 1:
 | 
					    search.results, search.suggestions = do_search(search.query,
 | 
				
			||||||
        return render('index.html')
 | 
					                                                   request,
 | 
				
			||||||
 | 
					                                                   search.engines,
 | 
				
			||||||
 | 
					                                                   search.pageno,
 | 
				
			||||||
 | 
					                                                   search.lang)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pageno = int(pageno_param)
 | 
					    for result in search.results:
 | 
				
			||||||
 | 
					        if not search.paging and engines[result['engine']].paging:
 | 
				
			||||||
    selected_categories = []
 | 
					            search.paging = True
 | 
				
			||||||
 | 
					        if search.request_data.get('format', 'html') == 'html':
 | 
				
			||||||
    query, selected_engines = parse_query(request_data['q'].encode('utf-8'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if len(selected_engines):
 | 
					 | 
				
			||||||
        selected_categories = list(set(engine['category']
 | 
					 | 
				
			||||||
                                       for engine in selected_engines))
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        for pd_name, pd in request_data.items():
 | 
					 | 
				
			||||||
            if pd_name.startswith('category_'):
 | 
					 | 
				
			||||||
                category = pd_name[9:]
 | 
					 | 
				
			||||||
                if not category in categories:
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
                selected_categories.append(category)
 | 
					 | 
				
			||||||
        if not len(selected_categories):
 | 
					 | 
				
			||||||
            cookie_categories = request.cookies.get('categories', '')
 | 
					 | 
				
			||||||
            cookie_categories = cookie_categories.split(',')
 | 
					 | 
				
			||||||
            for ccateg in cookie_categories:
 | 
					 | 
				
			||||||
                if ccateg in categories:
 | 
					 | 
				
			||||||
                    selected_categories.append(ccateg)
 | 
					 | 
				
			||||||
        if not len(selected_categories):
 | 
					 | 
				
			||||||
            selected_categories = ['general']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for categ in selected_categories:
 | 
					 | 
				
			||||||
            selected_engines.extend({'category': categ,
 | 
					 | 
				
			||||||
                                     'name': x.name}
 | 
					 | 
				
			||||||
                                    for x in categories[categ])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    results, suggestions = search(query,
 | 
					 | 
				
			||||||
                                  request,
 | 
					 | 
				
			||||||
                                  selected_engines,
 | 
					 | 
				
			||||||
                                  pageno,
 | 
					 | 
				
			||||||
                                  lang)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for result in results:
 | 
					 | 
				
			||||||
        if not paging and engines[result['engine']].paging:
 | 
					 | 
				
			||||||
            paging = True
 | 
					 | 
				
			||||||
        if request_data.get('format', 'html') == 'html':
 | 
					 | 
				
			||||||
            if 'content' in result:
 | 
					            if 'content' in result:
 | 
				
			||||||
                result['content'] = highlight_content(result['content'], query)
 | 
					                result['content'] = highlight_content(result['content'], search.query)
 | 
				
			||||||
            result['title'] = highlight_content(result['title'], query)
 | 
					            result['title'] = highlight_content(result['title'], search.query)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            if 'content' in result:
 | 
					            if 'content' in result:
 | 
				
			||||||
                result['content'] = html_to_text(result['content']).strip()
 | 
					                result['content'] = html_to_text(result['content']).strip()
 | 
				
			||||||
@ -199,40 +138,40 @@ def index():
 | 
				
			|||||||
            if engine in favicons:
 | 
					            if engine in favicons:
 | 
				
			||||||
                result['favicon'] = engine
 | 
					                result['favicon'] = engine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if request_data.get('format') == 'json':
 | 
					    if search.request_data.get('format') == 'json':
 | 
				
			||||||
        return Response(json.dumps({'query': query, 'results': results}),
 | 
					        return Response(json.dumps({'query': search.query, 'results': search.results}),
 | 
				
			||||||
                        mimetype='application/json')
 | 
					                        mimetype='application/json')
 | 
				
			||||||
    elif request_data.get('format') == 'csv':
 | 
					    elif search.request_data.get('format') == 'csv':
 | 
				
			||||||
        csv = UnicodeWriter(cStringIO.StringIO())
 | 
					        csv = UnicodeWriter(cStringIO.StringIO())
 | 
				
			||||||
        keys = ('title', 'url', 'content', 'host', 'engine', 'score')
 | 
					        keys = ('title', 'url', 'content', 'host', 'engine', 'score')
 | 
				
			||||||
        if len(results):
 | 
					        if len(search.results):
 | 
				
			||||||
            csv.writerow(keys)
 | 
					            csv.writerow(keys)
 | 
				
			||||||
            for row in results:
 | 
					            for row in search.results:
 | 
				
			||||||
                row['host'] = row['parsed_url'].netloc
 | 
					                row['host'] = row['parsed_url'].netloc
 | 
				
			||||||
                csv.writerow([row.get(key, '') for key in keys])
 | 
					                csv.writerow([row.get(key, '') for key in keys])
 | 
				
			||||||
        csv.stream.seek(0)
 | 
					        csv.stream.seek(0)
 | 
				
			||||||
        response = Response(csv.stream.read(), mimetype='application/csv')
 | 
					        response = Response(csv.stream.read(), mimetype='application/csv')
 | 
				
			||||||
        content_disp = 'attachment;Filename=searx_-_{0}.csv'.format(query)
 | 
					        content_disp = 'attachment;Filename=searx_-_{0}.csv'.format(search.query)
 | 
				
			||||||
        response.headers.add('Content-Disposition', content_disp)
 | 
					        response.headers.add('Content-Disposition', content_disp)
 | 
				
			||||||
        return response
 | 
					        return response
 | 
				
			||||||
    elif request_data.get('format') == 'rss':
 | 
					    elif search.request_data.get('format') == 'rss':
 | 
				
			||||||
        response_rss = render(
 | 
					        response_rss = render(
 | 
				
			||||||
            'opensearch_response_rss.xml',
 | 
					            'opensearch_response_rss.xml',
 | 
				
			||||||
            results=results,
 | 
					            results=search.results,
 | 
				
			||||||
            q=request_data['q'],
 | 
					            q=search.request_data['q'],
 | 
				
			||||||
            number_of_results=len(results),
 | 
					            number_of_results=len(search.results),
 | 
				
			||||||
            base_url=get_base_url()
 | 
					            base_url=get_base_url()
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return Response(response_rss, mimetype='text/xml')
 | 
					        return Response(response_rss, mimetype='text/xml')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return render(
 | 
					    return render(
 | 
				
			||||||
        'results.html',
 | 
					        'results.html',
 | 
				
			||||||
        results=results,
 | 
					        results=search.results,
 | 
				
			||||||
        q=request_data['q'],
 | 
					        q=search.request_data['q'],
 | 
				
			||||||
        selected_categories=selected_categories,
 | 
					        selected_categories=search.categories,
 | 
				
			||||||
        paging=paging,
 | 
					        paging=search.paging,
 | 
				
			||||||
        pageno=pageno,
 | 
					        pageno=search.pageno,
 | 
				
			||||||
        suggestions=suggestions
 | 
					        suggestions=search.suggestions
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user