Browse Source

[enh] initial commit

asciimoo 11 years ago
commit
ae9fb1d7dc

+ 2
- 0
.gitignore View File

@@ -0,0 +1,2 @@
1
+env
2
+searx.conf

+ 4
- 0
README.md View File

@@ -0,0 +1,4 @@
1
+searx
2
+=====
3
+
4
+Minimalistic web interface to different search engines.

+ 3
- 0
requirements.txt View File

@@ -0,0 +1,3 @@
1
+flask
2
+grequests
3
+lxml

+ 0
- 0
searx/__init__.py View File


+ 15
- 0
searx/engines/__init__.py View File

@@ -0,0 +1,15 @@
1
+
2
+from os.path import realpath, dirname, splitext, join
3
+from os import listdir
4
+from imp import load_source
5
+
6
+engine_dir = dirname(realpath(__file__))
7
+
8
+engines = []
9
+
10
+for filename in listdir(engine_dir):
11
+    modname = splitext(filename)[0]
12
+    if filename.startswith('_') or not filename.endswith('.py'):
13
+        continue
14
+    filepath = join(engine_dir, filename)
15
+    engines.append(load_source(modname, filepath))

+ 14
- 0
searx/engines/duckduckgo.py View File

@@ -0,0 +1,14 @@
1
+from lxml import html
2
+
3
+
4
+def request(query, params):
5
+    params['method']    = 'POST'
6
+    params['url']       = 'https://duckduckgo.com/html'
7
+    params['data']['q'] = query
8
+    return params
9
+
10
+
11
+def response(resp):
12
+    dom = html.fromstring(resp.text)
13
+    results = dom.xpath('//div[@class="results_links results_links_deep web-result"]')
14
+    return [html.tostring(x) for x in results]

+ 0
- 0
searx/static/css/style.css View File


+ 17
- 0
searx/templates/base.html View File

@@ -0,0 +1,17 @@
1
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
3
+<head>
4
+    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
5
+    <meta http-equiv="content-language" content="en" />
6
+    <meta name="description" content="" />
7
+    <meta name="keywords" content="" />
8
+    <title>searx {% block title %}{% endblock %}</title>
9
+    <link rel="stylesheet" href="/static/css/style.css" type="text/css" media="screen" charset="utf-8" />
10
+    {% block styles %}
11
+    {% endblock %}
12
+</head>
13
+<body>
14
+{% block content %}
15
+{% endblock %}
16
+</body>
17
+</html>

+ 8
- 0
searx/templates/index.html View File

@@ -0,0 +1,8 @@
1
+{% extends "base.html" %}
2
+{% block content %}
3
+<h1>searx</h1>
4
+<form method="post" action="">
5
+    <input type="text" name="q" />
6
+    <input type="submit" value="search" />
7
+</form>
8
+{% endblock %}

+ 7
- 0
searx/templates/results.html View File

@@ -0,0 +1,7 @@
1
+{% extends "base.html" %}
2
+{% block content %}
3
+<h1>searx</h1>
4
+{% for result in results %}
5
+    <p>{{ result|safe }}</p>
6
+{% endfor %}
7
+{% endblock %}

+ 69
- 0
searx/webapp.py View File

@@ -0,0 +1,69 @@
1
+#!/usr/bin/env python
2
+
3
+if __name__ == "__main__":
4
+    from sys import path
5
+    from os.path import realpath, dirname
6
+    path.append(realpath(dirname(realpath(__file__))+'/../'))
7
+
8
+from flask import Flask, request, flash, render_template
9
+import ConfigParser
10
+from os import getenv
11
+from searx.engines import engines
12
+import grequests
13
+
14
+cfg = ConfigParser.SafeConfigParser()
15
+cfg.read('/etc/searx.conf')
16
+cfg.read(getenv('HOME')+'/.searxrc')
17
+cfg.read(getenv('HOME')+'/.config/searx/searx.conf')
18
+cfg.read('searx.conf')
19
+
20
+
21
+app = Flask(__name__)
22
+app.secret_key = cfg.get('app', 'secret_key')
23
+
24
+def default_request_params():
25
+    return {'method': 'GET', 'headers': {}, 'data': {}, 'url': ''}
26
+
27
+def make_callback(results, callback):
28
+    def process_callback(response, **kwargs):
29
+        results.extend(callback(response))
30
+    return process_callback
31
+
32
+@app.route('/', methods=['GET', 'POST'])
33
+def index():
34
+    if request.method=='POST':
35
+        if not request.form.get('q'):
36
+            flash('Wrong post data')
37
+            return render_template('index.html')
38
+        query = request.form['q']
39
+        requests = []
40
+        results = []
41
+        for engine in engines:
42
+            request_params = engine.request(query, default_request_params())
43
+            callback = make_callback(results, engine.response)
44
+            if request_params['method'] == 'GET':
45
+                req = grequests.get(request_params['url']
46
+                                   ,headers=request_params['headers']
47
+                                   ,hooks=dict(response=callback)
48
+                                   )
49
+            else:
50
+                req = grequests.post(request_params['url']
51
+                                    ,data=request_params['data']
52
+                                    ,headers=request_params['headers']
53
+                                    ,hooks=dict(response=callback)
54
+                                    )
55
+            requests.append(req)
56
+        grequests.map(requests)
57
+        return render_template('results.html', results=results)
58
+
59
+
60
+    return render_template('index.html')
61
+
62
+if __name__ == "__main__":
63
+    from gevent import monkey
64
+    monkey.patch_all()
65
+
66
+    app.run(debug        = cfg.get('server', 'debug')
67
+           ,use_debugger = cfg.get('server', 'debug')
68
+           ,port         = int(cfg.get('server', 'port'))
69
+           )