@@ -20,9 +20,10 @@ Definitions`_.
21from urllib.parse import urlencode, urlparse
21from urllib.parse import urlencode, urlparse
22from lxml import html
22from lxml import html
23−from flask_babel import gettext
24from searx import logger
23from searx import logger
25−from searx.utils import match_language, extract_text, eval_xpath
24+from searx.utils import match_language, extract_text, eval_xpath, eval_xpath_list, eval_xpath_getindex
25+from searx.exceptions import SearxEngineCaptchaException
27logger = logger.getChild('google engine')
28logger = logger.getChild('google engine')
@@ -131,14 +132,6 @@ suggestion_xpath = '//div[contains(@class, "card-section")]//a'
131spelling_suggestion_xpath = '//div[@class="med"]/p/a'
132spelling_suggestion_xpath = '//div[@class="med"]/p/a'
134−def extract_text_from_dom(result, xpath):
135− """returns extract_text on the first result selected by the xpath or None"""
136− r = eval_xpath(result, xpath)
138− return extract_text(r[0])
142def get_lang_country(params, lang_list, custom_aliases):
135def get_lang_country(params, lang_list, custom_aliases):
143 """Returns a tuple with *langauage* on its first and *country* on its second
136 """Returns a tuple with *langauage* on its first and *country* on its second
144 position."""
137 position."""
@@ -210,10 +203,10 @@ def response(resp):
210 # detect google sorry
203 # detect google sorry
211 resp_url = urlparse(resp.url)
204 resp_url = urlparse(resp.url)
212 if resp_url.netloc == 'sorry.google.com' or resp_url.path == '/sorry/IndexRedirect':
205 if resp_url.netloc == 'sorry.google.com' or resp_url.path == '/sorry/IndexRedirect':
213− raise RuntimeWarning('sorry.google.com')
206+ raise SearxEngineCaptchaException()
215 if resp_url.path.startswith('/sorry'):
208 if resp_url.path.startswith('/sorry'):
216− raise RuntimeWarning(gettext('CAPTCHA required'))
209+ raise SearxEngineCaptchaException()
218 # which subdomain ?
211 # which subdomain ?
219 # subdomain = resp.search_params.get('google_subdomain')
212 # subdomain = resp.search_params.get('google_subdomain')
@@ -229,18 +222,17 @@ def response(resp):
229 logger.debug("did not found 'answer'")
222 logger.debug("did not found 'answer'")
231 # results --> number_of_results
224 # results --> number_of_results
233− _txt = eval_xpath(dom, '//div[@id="result-stats"]//text()')[0]
226+ _txt = eval_xpath_getindex(dom, '//div[@id="result-stats"]//text()', 0)
234− _digit = ''.join([n for n in _txt if n.isdigit()])
227+ _digit = ''.join([n for n in _txt if n.isdigit()])
235− number_of_results = int(_digit)
228+ number_of_results = int(_digit)
236− results.append({'number_of_results': number_of_results})
229+ results.append({'number_of_results': number_of_results})
238− except Exception as e: # pylint: disable=broad-except
230+ except Exception as e: # pylint: disable=broad-except
239− logger.debug("did not 'number_of_results'")
231+ logger.debug("did not 'number_of_results'")
240− logger.error(e, exc_info=True)
232+ logger.error(e, exc_info=True)
242 # parse results
234 # parse results
243− for result in eval_xpath(dom, results_xpath):
235+ for result in eval_xpath_list(dom, results_xpath):
245 # google *sections*
237 # google *sections*
246 if extract_text(eval_xpath(result, g_section_with_header)):
238 if extract_text(eval_xpath(result, g_section_with_header)):
@@ -248,14 +240,14 @@ def response(resp):
251− title_tag = eval_xpath(result, title_xpath)
243+ title_tag = eval_xpath_getindex(result, title_xpath, 0, default=None)
252− if not title_tag:
244+ if title_tag is None:
253 # this not one of the common google results *section*
245 # this not one of the common google results *section*
254 logger.debug('ingoring <div class="g" ../> section: missing title')
246 logger.debug('ingoring <div class="g" ../> section: missing title')
256− title = extract_text(title_tag[0])
248+ title = extract_text(title_tag)
257− url = eval_xpath(result, href_xpath)[0]
249+ url = eval_xpath_getindex(result, href_xpath, 0)
258− content = extract_text_from_dom(result, content_xpath)
250+ content = extract_text(eval_xpath_getindex(result, content_xpath, 0, default=None), allow_none=True)
259 results.append({
251 results.append({
260 'url': url,
252 'url': url,
261 'title': title,
253 'title': title,
@@ -270,11 +262,11 @@ def response(resp):
272 # parse suggestion
264 # parse suggestion
273− for suggestion in eval_xpath(dom, suggestion_xpath):
265+ for suggestion in eval_xpath_list(dom, suggestion_xpath):
274 # append suggestion
266 # append suggestion
275 results.append({'suggestion': extract_text(suggestion)})
267 results.append({'suggestion': extract_text(suggestion)})
277− for correction in eval_xpath(dom, spelling_suggestion_xpath):
269+ for correction in eval_xpath_list(dom, spelling_suggestion_xpath):
278 results.append({'correction': extract_text(correction)})
270 results.append({'correction': extract_text(correction)})
280 # return results
272 # return results
@@ -286,7 +278,7 @@ def _fetch_supported_languages(resp):
286 ret_val = {}
278 ret_val = {}
287 dom = html.fromstring(resp.text)
279 dom = html.fromstring(resp.text)
289− radio_buttons = eval_xpath(dom, '//*[@id="langSec"]//input[@name="lr"]')
281+ radio_buttons = eval_xpath_list(dom, '//*[@id="langSec"]//input[@name="lr"]')
291 for x in radio_buttons:
283 for x in radio_buttons:
292 name = x.get("data-name")
284 name = x.get("data-name")