AnesKAM commited on
Commit
8a2a935
·
verified ·
1 Parent(s): f035afd

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -0
app.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template_string, request, jsonify
2
+ import requests
3
+ from bs4 import BeautifulSoup
4
+
5
+ app = Flask(__name__)
6
+
7
+ HTML_TEMPLATE = """
8
+ <!DOCTYPE html>
9
+ <html lang="ar" dir="rtl">
10
+ <head>
11
+ <meta charset="UTF-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
13
+ <title>محرك البحث الذكي</title>
14
+ <style>
15
+ * { margin: 0; padding: 0; box-sizing: border-box; }
16
+ body {
17
+ font-family: 'Segoe UI', Tahoma, sans-serif;
18
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
19
+ min-height: 100vh; display: flex; flex-direction: column; align-items: center;
20
+ justify-content: center; padding: 20px;
21
+ }
22
+ .container { width: 100%; max-width: 700px; text-align: center; }
23
+ .logo { font-size: 3rem; color: #e94560; margin-bottom: 10px; font-weight: bold; letter-spacing: 2px; }
24
+ .subtitle { color: #a0a0b0; margin-bottom: 30px; font-size: 0.9rem; }
25
+ .search-box {
26
+ display: flex; gap: 10px; background: rgba(255,255,255,0.1);
27
+ backdrop-filter: blur(10px); border-radius: 30px; padding: 5px 10px;
28
+ box-shadow: 0 8px 32px rgba(0,0,0,0.3); margin-bottom: 20px;
29
+ }
30
+ .search-box input {
31
+ flex: 1; padding: 15px 20px; border: none; background: transparent;
32
+ color: white; font-size: 1rem; outline: none;
33
+ }
34
+ .search-box input::placeholder { color: #8a8a9a; }
35
+ .search-box button {
36
+ padding: 12px 25px; background: #e94560; color: white; border: none;
37
+ border-radius: 25px; font-size: 1rem; cursor: pointer; font-weight: bold;
38
+ transition: background 0.3s;
39
+ }
40
+ .search-box button:hover { background: #c23152; }
41
+ #results { width: 100%; margin-top: 20px; }
42
+ .result-item {
43
+ background: rgba(255,255,255,0.05); backdrop-filter: blur(5px);
44
+ border-radius: 12px; padding: 15px; margin-bottom: 10px; text-align: right;
45
+ border-right: 3px solid #e94560; transition: background 0.3s;
46
+ }
47
+ .result-item:hover { background: rgba(255,255,255,0.1); }
48
+ .result-item a {
49
+ color: #4fc3f7; text-decoration: none; font-size: 1.1rem; font-weight: bold;
50
+ }
51
+ .result-item a:hover { text-decoration: underline; }
52
+ .result-item .url { color: #66bb6a; font-size: 0.8rem; margin: 5px 0; word-break: break-all; }
53
+ .result-item p { color: #ccc; font-size: 0.9rem; margin-top: 8px; line-height: 1.5; }
54
+ .loading { color: white; margin: 20px 0; display: none; }
55
+ .spinner { display: inline-block; width: 20px; height: 20px; border: 3px solid rgba(255,255,255,0.3); border-radius: 50%; border-top-color: #e94560; animation: spin 1s linear infinite; margin-left: 8px; }
56
+ @keyframes spin { to { transform: rotate(360deg); } }
57
+ </style>
58
+ </head>
59
+ <body>
60
+ <div class="container">
61
+ <div class="logo">🔎 باحث</div>
62
+ <p class="subtitle">محرك بحث مفتوح المصدر - ابحث في الإنترنت بحرية</p>
63
+
64
+ <div class="search-box">
65
+ <input type="text" id="searchInput" placeholder="ماذا تريد أن تبحث؟" dir="auto">
66
+ <button onclick="performSearch()">🔍 بحث</button>
67
+ </div>
68
+
69
+ <div class="loading" id="loading">
70
+ <span class="spinner"></span> جاري البحث...
71
+ </div>
72
+
73
+ <div id="results"></div>
74
+ </div>
75
+
76
+ <script>
77
+ async function performSearch() {
78
+ const query = document.getElementById('searchInput').value.trim();
79
+ if (!query) return;
80
+
81
+ const loading = document.getElementById('loading');
82
+ const results = document.getElementById('results');
83
+
84
+ loading.style.display = 'block';
85
+ results.innerHTML = '';
86
+
87
+ try {
88
+ // نرسل الطلب إلى خادمنا Flask الذي بدوره يتصل بـ DuckDuckGo
89
+ const response = await fetch(`/search?q=${encodeURIComponent(query)}`);
90
+ const data = await response.json();
91
+
92
+ loading.style.display = 'none';
93
+
94
+ if (data.results && data.results.length > 0) {
95
+ let html = '';
96
+ data.results.forEach((res, index) => {
97
+ html += `
98
+ <div class="result-item">
99
+ <a href="${res.link}" target="_blank" rel="noopener">${index + 1}. ${res.title}</a>
100
+ <div class="url">${res.link.substring(0, 80)}${res.link.length > 80 ? '...' : ''}</div>
101
+ <p>${res.snippet}</p>
102
+ </div>
103
+ `;
104
+ });
105
+ results.innerHTML = html;
106
+ } else {
107
+ results.innerHTML = '<p style="color: #ccc; text-align: center;">لم يتم العثور على نتائج. جرب كلمات مختلفة.</p>';
108
+ }
109
+ } catch (error) {
110
+ loading.style.display = 'none';
111
+ results.innerHTML = `<p style='color: #ff6b6b;'>حدث خطأ: ${error.message}</p>`;
112
+ }
113
+ }
114
+
115
+ document.getElementById('searchInput').addEventListener('keypress', function(e) {
116
+ if (e.key === 'Enter') performSearch();
117
+ });
118
+ </script>
119
+ </body>
120
+ </html>
121
+ """
122
+
123
+ def search_duckduckgo(query, max_results=10):
124
+ """يبحث في DuckDuckGo ويعيد قائمة من النتائج"""
125
+ url = "https://html.duckduckgo.com/html/"
126
+ headers = {
127
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
128
+ }
129
+ params = {'q': query}
130
+
131
+ try:
132
+ response = requests.post(url, data=params, headers=headers, timeout=10)
133
+ soup = BeautifulSoup(response.text, 'html.parser')
134
+ results = []
135
+ for item in soup.select('.result')[:max_results]:
136
+ title_element = item.select_one('.result__title a')
137
+ snippet_element = item.select_one('.result__snippet')
138
+ link_element = item.select_one('.result__url')
139
+
140
+ if title_element:
141
+ title = title_element.get_text(strip=True)
142
+ link = link_element.get_text(strip=True) if link_element else title_element.get('href', '')
143
+ snippet = snippet_element.get_text(strip=True) if snippet_element else ''
144
+ results.append({'title': title, 'link': link, 'snippet': snippet})
145
+ return results
146
+ except Exception as e:
147
+ return []
148
+
149
+ @app.route('/')
150
+ def home():
151
+ return render_template_string(HTML_TEMPLATE)
152
+
153
+ @app.route('/search')
154
+ def search():
155
+ query = request.args.get('q', '')
156
+ if not query:
157
+ return jsonify({'results': []})
158
+ results = search_duckduckgo(query)
159
+ return jsonify({'results': results})
160
+
161
+ if __name__ == '__main__':
162
+ app.run(host='0.0.0.0', port=7860)