We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Get image button from the Google Images engine doesn't give the raw URL to the image
When searching for images using the "Google Images" engine, the "Get image" button doesn't give the raw URL (that usually ends with `.jpg` or `.png`) to the image of every result.
In fact the button gives the same exact URL as the button "View source".

On other engines (like Bing images) it gives the raw URL to the image.

Here is a screenshot explaining the issue:
![getimagegoogleimages](https://user-images.githubusercontent.com/4016501/88662178-e19f1000-d0d9-11ea-8893-a7fc9798b82c.png)

Here is a URL for testing the bug: https://darmarit.org/searx/?q=%21goi+ok&time_range=&language=en-US&category_images=on

@return42 Any thoughts about that?


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `searx/engines/google_images.py`
Content:
```
1 # SPDX-License-Identifier: AGPL-3.0-or-later
2 """Google (Images)
3 
4 :website:     https://images.google.com (redirected to subdomain www.)
5 :provide-api: yes (https://developers.google.com/custom-search/)
6 :using-api:   not the offical, since it needs registration to another service
7 :results:     HTML
8 :stable:      no
9 :template:    images.html
10 :parse:       url, title, content, source, thumbnail_src, img_src
11 
12 For detailed description of the *REST-full* API see: `Query Parameter
13 Definitions`_.
14 
15 .. _admonition:: Content-Security-Policy (CSP)
16 
17    This engine needs to allow images from the `data URLs`_ (prefixed with the
18    ``data:` scheme).::
19 
20      Header set Content-Security-Policy "img-src 'self' data: ;"
21 
22 .. _Query Parameter Definitions:
23    https://developers.google.com/custom-search/docs/xml_results#WebSearch_Query_Parameter_Definitions
24 
25 """
26 
27 from lxml import html
28 from flask_babel import gettext
29 from searx import logger
30 from searx.url_utils import urlencode, urlparse
31 from searx.utils import eval_xpath
32 from searx.engines.xpath import extract_text
33 
34 # pylint: disable=unused-import
35 from searx.engines.google import (
36     supported_languages_url,
37     _fetch_supported_languages,
38 )
39 # pylint: enable=unused-import
40 
41 from searx.engines.google import (
42     get_lang_country,
43     google_domains,
44     time_range_dict,
45 )
46 
47 logger = logger.getChild('google images')
48 
49 # engine dependent config
50 
51 categories = ['images']
52 paging = False
53 language_support = True
54 use_locale_domain = True
55 time_range_support = True
56 safesearch = True
57 
58 filter_mapping = {
59     0: 'images',
60     1: 'active',
61     2: 'active'
62 }
63 
64 
65 def scrap_out_thumbs(dom):
66     """Scrap out thumbnail data from <script> tags.
67     """
68     ret_val = dict()
69     for script in eval_xpath(dom, '//script[contains(., "_setImgSrc(")]'):
70         _script = script.text
71         # _setImgSrc('0','data:image\/jpeg;base64,\/9j\/4AAQSkZJR ....');
72         _thumb_no, _img_data = _script[len("_setImgSrc("):-2].split(",", 1)
73         _thumb_no = _thumb_no.replace("'", "")
74         _img_data = _img_data.replace("'", "")
75         _img_data = _img_data.replace(r"\/", r"/")
76         ret_val[_thumb_no] = _img_data.replace(r"\x3d", "=")
77     return ret_val
78 
79 
80 def request(query, params):
81     """Google-Video search request"""
82 
83     language, country, lang_country = get_lang_country(
84         # pylint: disable=undefined-variable
85         params, supported_languages, language_aliases
86     )
87     subdomain = 'www.' + google_domains.get(country.upper(), 'google.com')
88 
89     query_url = 'https://' + subdomain + '/search' + "?" + urlencode({
90         'q': query,
91         'tbm': "isch",
92         'hl': lang_country,
93         'lr': "lang_" + language,
94         'ie': "utf8",
95         'oe': "utf8",
96         'num': 30,
97     })
98 
99     if params['time_range'] in time_range_dict:
100         query_url += '&' + urlencode({'tbs': 'qdr:' + time_range_dict[params['time_range']]})
101     if params['safesearch']:
102         query_url += '&' + urlencode({'safe': filter_mapping[params['safesearch']]})
103 
104     params['url'] = query_url
105     logger.debug("query_url --> %s", query_url)
106 
107     params['headers']['Accept-Language'] = (
108         "%s,%s;q=0.8,%s;q=0.5" % (lang_country, language, language))
109     logger.debug(
110         "HTTP Accept-Language --> %s", params['headers']['Accept-Language'])
111     params['headers']['Accept'] = (
112         'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
113     )
114     # params['google_subdomain'] = subdomain
115     return params
116 
117 
118 def response(resp):
119     """Get response from google's search request"""
120     results = []
121 
122     # detect google sorry
123     resp_url = urlparse(resp.url)
124     if resp_url.netloc == 'sorry.google.com' or resp_url.path == '/sorry/IndexRedirect':
125         raise RuntimeWarning('sorry.google.com')
126 
127     if resp_url.path.startswith('/sorry'):
128         raise RuntimeWarning(gettext('CAPTCHA required'))
129 
130     # which subdomain ?
131     # subdomain = resp.search_params.get('google_subdomain')
132 
133     # convert the text to dom
134     dom = html.fromstring(resp.text)
135     img_bas64_map = scrap_out_thumbs(dom)
136 
137     # parse results
138     #
139     # root element::
140     #     <div id="islmp" ..>
141     # result div per image::
142     #     <div jsmodel="tTXmib"> / <div jsaction="..." data-id="..."
143     #     The data-id matches to a item in a json-data structure in::
144     #         <script nonce="I+vqelcy/01CKiBJi5Z1Ow">AF_initDataCallback({key: 'ds:1', ... data:function(){return [ ...
145     #     In this structure the ling to the origin PNG, JPG or whatever is given
146     #     (we do not blow out the link there, you could still implement that)
147     # first link per image-div contains a <img> with the data-iid for bas64 encoded image data::
148     #      <img class="rg_i Q4LuWd" data-iid="0"
149     # second link per image-div is the target link::
150     #      <a class="VFACy kGQAp" href="https://en.wikipedia.org/wiki/The_Sacrament_of_the_Last_Supper">
151     # the second link also contains two div tags with the *description* and *publisher*::
152     #      <div class="WGvvNb">The Sacrament of the Last Supper ...</div>
153     #      <div class="fxgdke">en.wikipedia.org</div>
154 
155     root = eval_xpath(dom, '//div[@id="islmp"]')
156     if not root:
157         logger.error("did not find root element id='islmp'")
158         return results
159 
160     root = root[0]
161     for img_node in eval_xpath(root, './/img[contains(@class, "rg_i")]'):
162 
163         try:
164             img_alt = eval_xpath(img_node, '@alt')[0]
165 
166             img_base64_id = eval_xpath(img_node, '@data-iid')
167             if img_base64_id:
168                 img_base64_id = img_base64_id[0]
169                 thumbnail_src = img_bas64_map[img_base64_id]
170             else:
171                 thumbnail_src = eval_xpath(img_node, '@src')
172                 if not thumbnail_src:
173                     thumbnail_src = eval_xpath(img_node, '@data-src')
174                 if thumbnail_src:
175                     thumbnail_src = thumbnail_src[0]
176                 else:
177                     thumbnail_src = ''
178 
179             link_node = eval_xpath(img_node, '../../../a[2]')[0]
180             url = eval_xpath(link_node, '@href')[0]
181 
182             pub_nodes = eval_xpath(link_node, './div/div')
183             pub_descr = img_alt
184             pub_source = ''
185             if pub_nodes:
186                 pub_descr = extract_text(pub_nodes[0])
187                 pub_source = extract_text(pub_nodes[1])
188 
189             results.append({
190                 'url': url,
191                 'title': img_alt,
192                 'content': pub_descr,
193                 'source': pub_source,
194                 'img_src': url,
195                 # 'img_format': img_format,
196                 'thumbnail_src': thumbnail_src,
197                 'template': 'images.html'
198             })
199         except Exception as e:  # pylint: disable=broad-except
200             logger.error(e, exc_info=True)
201             # from lxml import etree
202             # logger.debug(etree.tostring(img_node, pretty_print=True))
203             # import pdb
204             # pdb.set_trace()
205             continue
206 
207     return results
208
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/searx/engines/google_images.py b/searx/engines/google_images.py
--- a/searx/engines/google_images.py
+++ b/searx/engines/google_images.py
@@ -24,6 +24,7 @@
 
 """
 
+import urllib
 from lxml import html
 from flask_babel import gettext
 from searx import logger
@@ -77,6 +78,19 @@
     return ret_val
 
 
+def scrap_img_by_id(script, data_id):
+    """Get full image URL by data-id in parent element
+    """
+    img_url = ''
+    _script = script.split('\n')
+    for i, line in enumerate(_script):
+        if 'gstatic.com/images' in line and data_id in line:
+            url_line = _script[i + 1]
+            img_url = url_line.split('"')[1]
+            img_url = urllib.parse.unquote(img_url.replace(r'\u00', r'%'))
+    return img_url
+
+
 def request(query, params):
     """Google-Video search request"""
 
@@ -133,6 +147,7 @@
     # convert the text to dom
     dom = html.fromstring(resp.text)
     img_bas64_map = scrap_out_thumbs(dom)
+    img_src_script = eval_xpath(dom, '//script[contains(., "AF_initDataCallback({key: ")]')[1].text
 
     # parse results
     #
@@ -142,8 +157,7 @@
     #     <div jsmodel="tTXmib"> / <div jsaction="..." data-id="..."
     #     The data-id matches to a item in a json-data structure in::
     #         <script nonce="I+vqelcy/01CKiBJi5Z1Ow">AF_initDataCallback({key: 'ds:1', ... data:function(){return [ ...
-    #     In this structure the ling to the origin PNG, JPG or whatever is given
-    #     (we do not blow out the link there, you could still implement that)
+    #     In this structure the link to the origin PNG, JPG or whatever is given
     # first link per image-div contains a <img> with the data-iid for bas64 encoded image data::
     #      <img class="rg_i Q4LuWd" data-iid="0"
     # second link per image-div is the target link::
@@ -186,12 +200,17 @@
                 pub_descr = extract_text(pub_nodes[0])
                 pub_source = extract_text(pub_nodes[1])
 
+            img_src_id = eval_xpath(img_node, '../../../@data-id')[0]
+            src_url = scrap_img_by_id(img_src_script, img_src_id)
+            if not src_url:
+                src_url = thumbnail_src
+
             results.append({
                 'url': url,
                 'title': img_alt,
                 'content': pub_descr,
                 'source': pub_source,
-                'img_src': url,
+                'img_src': src_url,
                 # 'img_format': img_format,
                 'thumbnail_src': thumbnail_src,
                 'template': 'images.html'

{"golden_diff": "diff --git a/searx/engines/google_images.py b/searx/engines/google_images.py\n--- a/searx/engines/google_images.py\n+++ b/searx/engines/google_images.py\n@@ -24,6 +24,7 @@\n \n \"\"\"\n \n+import urllib\n from lxml import html\n from flask_babel import gettext\n from searx import logger\n@@ -77,6 +78,19 @@\n     return ret_val\n \n \n+def scrap_img_by_id(script, data_id):\n+    \"\"\"Get full image URL by data-id in parent element\n+    \"\"\"\n+    img_url = ''\n+    _script = script.split('\\n')\n+    for i, line in enumerate(_script):\n+        if 'gstatic.com/images' in line and data_id in line:\n+            url_line = _script[i + 1]\n+            img_url = url_line.split('\"')[1]\n+            img_url = urllib.parse.unquote(img_url.replace(r'\\u00', r'%'))\n+    return img_url\n+\n+\n def request(query, params):\n     \"\"\"Google-Video search request\"\"\"\n \n@@ -133,6 +147,7 @@\n     # convert the text to dom\n     dom = html.fromstring(resp.text)\n     img_bas64_map = scrap_out_thumbs(dom)\n+    img_src_script = eval_xpath(dom, '//script[contains(., \"AF_initDataCallback({key: \")]')[1].text\n \n     # parse results\n     #\n@@ -142,8 +157,7 @@\n     #     <div jsmodel=\"tTXmib\"> / <div jsaction=\"...\" data-id=\"...\"\n     #     The data-id matches to a item in a json-data structure in::\n     #         <script nonce=\"I+vqelcy/01CKiBJi5Z1Ow\">AF_initDataCallback({key: 'ds:1', ... data:function(){return [ ...\n-    #     In this structure the ling to the origin PNG, JPG or whatever is given\n-    #     (we do not blow out the link there, you could still implement that)\n+    #     In this structure the link to the origin PNG, JPG or whatever is given\n     # first link per image-div contains a <img> with the data-iid for bas64 encoded image data::\n     #      <img class=\"rg_i Q4LuWd\" data-iid=\"0\"\n     # second link per image-div is the target link::\n@@ -186,12 +200,17 @@\n                 pub_descr = extract_text(pub_nodes[0])\n                 pub_source = extract_text(pub_nodes[1])\n \n+            img_src_id = eval_xpath(img_node, '../../../@data-id')[0]\n+            src_url = scrap_img_by_id(img_src_script, img_src_id)\n+            if not src_url:\n+                src_url = thumbnail_src\n+\n             results.append({\n                 'url': url,\n                 'title': img_alt,\n                 'content': pub_descr,\n                 'source': pub_source,\n-                'img_src': url,\n+                'img_src': src_url,\n                 # 'img_format': img_format,\n                 'thumbnail_src': thumbnail_src,\n                 'template': 'images.html'\n", "issue": "Get image button from the Google Images engine doesn't give the raw URL to the image\nWhen searching for images using the \"Google Images\" engine, the \"Get image\" button doesn't give the raw URL (that usually ends with `.jpg` or `.png`) to the image of every result.\r\nIn fact the button gives the same exact URL as the button \"View source\".\r\n\r\nOn other engines (like Bing images) it gives the raw URL to the image.\r\n\r\nHere is a screenshot explaining the issue:\r\n![getimagegoogleimages](https://user-images.githubusercontent.com/4016501/88662178-e19f1000-d0d9-11ea-8893-a7fc9798b82c.png)\r\n\r\nHere is a URL for testing the bug: https://darmarit.org/searx/?q=%21goi+ok&time_range=&language=en-US&category_images=on\r\n\r\n@return42 Any thoughts about that?\r\n\n", "before_files": [{"content": "# SPDX-License-Identifier: AGPL-3.0-or-later\n\"\"\"Google (Images)\n\n:website:     https://images.google.com (redirected to subdomain www.)\n:provide-api: yes (https://developers.google.com/custom-search/)\n:using-api:   not the offical, since it needs registration to another service\n:results:     HTML\n:stable:      no\n:template:    images.html\n:parse:       url, title, content, source, thumbnail_src, img_src\n\nFor detailed description of the *REST-full* API see: `Query Parameter\nDefinitions`_.\n\n.. _admonition:: Content-Security-Policy (CSP)\n\n   This engine needs to allow images from the `data URLs`_ (prefixed with the\n   ``data:` scheme).::\n\n     Header set Content-Security-Policy \"img-src 'self' data: ;\"\n\n.. _Query Parameter Definitions:\n   https://developers.google.com/custom-search/docs/xml_results#WebSearch_Query_Parameter_Definitions\n\n\"\"\"\n\nfrom lxml import html\nfrom flask_babel import gettext\nfrom searx import logger\nfrom searx.url_utils import urlencode, urlparse\nfrom searx.utils import eval_xpath\nfrom searx.engines.xpath import extract_text\n\n# pylint: disable=unused-import\nfrom searx.engines.google import (\n    supported_languages_url,\n    _fetch_supported_languages,\n)\n# pylint: enable=unused-import\n\nfrom searx.engines.google import (\n    get_lang_country,\n    google_domains,\n    time_range_dict,\n)\n\nlogger = logger.getChild('google images')\n\n# engine dependent config\n\ncategories = ['images']\npaging = False\nlanguage_support = True\nuse_locale_domain = True\ntime_range_support = True\nsafesearch = True\n\nfilter_mapping = {\n    0: 'images',\n    1: 'active',\n    2: 'active'\n}\n\n\ndef scrap_out_thumbs(dom):\n    \"\"\"Scrap out thumbnail data from <script> tags.\n    \"\"\"\n    ret_val = dict()\n    for script in eval_xpath(dom, '//script[contains(., \"_setImgSrc(\")]'):\n        _script = script.text\n        # _setImgSrc('0','data:image\\/jpeg;base64,\\/9j\\/4AAQSkZJR ....');\n        _thumb_no, _img_data = _script[len(\"_setImgSrc(\"):-2].split(\",\", 1)\n        _thumb_no = _thumb_no.replace(\"'\", \"\")\n        _img_data = _img_data.replace(\"'\", \"\")\n        _img_data = _img_data.replace(r\"\\/\", r\"/\")\n        ret_val[_thumb_no] = _img_data.replace(r\"\\x3d\", \"=\")\n    return ret_val\n\n\ndef request(query, params):\n    \"\"\"Google-Video search request\"\"\"\n\n    language, country, lang_country = get_lang_country(\n        # pylint: disable=undefined-variable\n        params, supported_languages, language_aliases\n    )\n    subdomain = 'www.' + google_domains.get(country.upper(), 'google.com')\n\n    query_url = 'https://' + subdomain + '/search' + \"?\" + urlencode({\n        'q': query,\n        'tbm': \"isch\",\n        'hl': lang_country,\n        'lr': \"lang_\" + language,\n        'ie': \"utf8\",\n        'oe': \"utf8\",\n        'num': 30,\n    })\n\n    if params['time_range'] in time_range_dict:\n        query_url += '&' + urlencode({'tbs': 'qdr:' + time_range_dict[params['time_range']]})\n    if params['safesearch']:\n        query_url += '&' + urlencode({'safe': filter_mapping[params['safesearch']]})\n\n    params['url'] = query_url\n    logger.debug(\"query_url --> %s\", query_url)\n\n    params['headers']['Accept-Language'] = (\n        \"%s,%s;q=0.8,%s;q=0.5\" % (lang_country, language, language))\n    logger.debug(\n        \"HTTP Accept-Language --> %s\", params['headers']['Accept-Language'])\n    params['headers']['Accept'] = (\n        'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'\n    )\n    # params['google_subdomain'] = subdomain\n    return params\n\n\ndef response(resp):\n    \"\"\"Get response from google's search request\"\"\"\n    results = []\n\n    # detect google sorry\n    resp_url = urlparse(resp.url)\n    if resp_url.netloc == 'sorry.google.com' or resp_url.path == '/sorry/IndexRedirect':\n        raise RuntimeWarning('sorry.google.com')\n\n    if resp_url.path.startswith('/sorry'):\n        raise RuntimeWarning(gettext('CAPTCHA required'))\n\n    # which subdomain ?\n    # subdomain = resp.search_params.get('google_subdomain')\n\n    # convert the text to dom\n    dom = html.fromstring(resp.text)\n    img_bas64_map = scrap_out_thumbs(dom)\n\n    # parse results\n    #\n    # root element::\n    #     <div id=\"islmp\" ..>\n    # result div per image::\n    #     <div jsmodel=\"tTXmib\"> / <div jsaction=\"...\" data-id=\"...\"\n    #     The data-id matches to a item in a json-data structure in::\n    #         <script nonce=\"I+vqelcy/01CKiBJi5Z1Ow\">AF_initDataCallback({key: 'ds:1', ... data:function(){return [ ...\n    #     In this structure the ling to the origin PNG, JPG or whatever is given\n    #     (we do not blow out the link there, you could still implement that)\n    # first link per image-div contains a <img> with the data-iid for bas64 encoded image data::\n    #      <img class=\"rg_i Q4LuWd\" data-iid=\"0\"\n    # second link per image-div is the target link::\n    #      <a class=\"VFACy kGQAp\" href=\"https://en.wikipedia.org/wiki/The_Sacrament_of_the_Last_Supper\">\n    # the second link also contains two div tags with the *description* and *publisher*::\n    #      <div class=\"WGvvNb\">The Sacrament of the Last Supper ...</div>\n    #      <div class=\"fxgdke\">en.wikipedia.org</div>\n\n    root = eval_xpath(dom, '//div[@id=\"islmp\"]')\n    if not root:\n        logger.error(\"did not find root element id='islmp'\")\n        return results\n\n    root = root[0]\n    for img_node in eval_xpath(root, './/img[contains(@class, \"rg_i\")]'):\n\n        try:\n            img_alt = eval_xpath(img_node, '@alt')[0]\n\n            img_base64_id = eval_xpath(img_node, '@data-iid')\n            if img_base64_id:\n                img_base64_id = img_base64_id[0]\n                thumbnail_src = img_bas64_map[img_base64_id]\n            else:\n                thumbnail_src = eval_xpath(img_node, '@src')\n                if not thumbnail_src:\n                    thumbnail_src = eval_xpath(img_node, '@data-src')\n                if thumbnail_src:\n                    thumbnail_src = thumbnail_src[0]\n                else:\n                    thumbnail_src = ''\n\n            link_node = eval_xpath(img_node, '../../../a[2]')[0]\n            url = eval_xpath(link_node, '@href')[0]\n\n            pub_nodes = eval_xpath(link_node, './div/div')\n            pub_descr = img_alt\n            pub_source = ''\n            if pub_nodes:\n                pub_descr = extract_text(pub_nodes[0])\n                pub_source = extract_text(pub_nodes[1])\n\n            results.append({\n                'url': url,\n                'title': img_alt,\n                'content': pub_descr,\n                'source': pub_source,\n                'img_src': url,\n                # 'img_format': img_format,\n                'thumbnail_src': thumbnail_src,\n                'template': 'images.html'\n            })\n        except Exception as e:  # pylint: disable=broad-except\n            logger.error(e, exc_info=True)\n            # from lxml import etree\n            # logger.debug(etree.tostring(img_node, pretty_print=True))\n            # import pdb\n            # pdb.set_trace()\n            continue\n\n    return results\n", "path": "searx/engines/google_images.py"}], "after_files": [{"content": "# SPDX-License-Identifier: AGPL-3.0-or-later\n\"\"\"Google (Images)\n\n:website:     https://images.google.com (redirected to subdomain www.)\n:provide-api: yes (https://developers.google.com/custom-search/)\n:using-api:   not the offical, since it needs registration to another service\n:results:     HTML\n:stable:      no\n:template:    images.html\n:parse:       url, title, content, source, thumbnail_src, img_src\n\nFor detailed description of the *REST-full* API see: `Query Parameter\nDefinitions`_.\n\n.. _admonition:: Content-Security-Policy (CSP)\n\n   This engine needs to allow images from the `data URLs`_ (prefixed with the\n   ``data:` scheme).::\n\n     Header set Content-Security-Policy \"img-src 'self' data: ;\"\n\n.. _Query Parameter Definitions:\n   https://developers.google.com/custom-search/docs/xml_results#WebSearch_Query_Parameter_Definitions\n\n\"\"\"\n\nimport urllib\nfrom lxml import html\nfrom flask_babel import gettext\nfrom searx import logger\nfrom searx.url_utils import urlencode, urlparse\nfrom searx.utils import eval_xpath\nfrom searx.engines.xpath import extract_text\n\n# pylint: disable=unused-import\nfrom searx.engines.google import (\n    supported_languages_url,\n    _fetch_supported_languages,\n)\n# pylint: enable=unused-import\n\nfrom searx.engines.google import (\n    get_lang_country,\n    google_domains,\n    time_range_dict,\n)\n\nlogger = logger.getChild('google images')\n\n# engine dependent config\n\ncategories = ['images']\npaging = False\nlanguage_support = True\nuse_locale_domain = True\ntime_range_support = True\nsafesearch = True\n\nfilter_mapping = {\n    0: 'images',\n    1: 'active',\n    2: 'active'\n}\n\n\ndef scrap_out_thumbs(dom):\n    \"\"\"Scrap out thumbnail data from <script> tags.\n    \"\"\"\n    ret_val = dict()\n    for script in eval_xpath(dom, '//script[contains(., \"_setImgSrc(\")]'):\n        _script = script.text\n        # _setImgSrc('0','data:image\\/jpeg;base64,\\/9j\\/4AAQSkZJR ....');\n        _thumb_no, _img_data = _script[len(\"_setImgSrc(\"):-2].split(\",\", 1)\n        _thumb_no = _thumb_no.replace(\"'\", \"\")\n        _img_data = _img_data.replace(\"'\", \"\")\n        _img_data = _img_data.replace(r\"\\/\", r\"/\")\n        ret_val[_thumb_no] = _img_data.replace(r\"\\x3d\", \"=\")\n    return ret_val\n\n\ndef scrap_img_by_id(script, data_id):\n    \"\"\"Get full image URL by data-id in parent element\n    \"\"\"\n    img_url = ''\n    _script = script.split('\\n')\n    for i, line in enumerate(_script):\n        if 'gstatic.com/images' in line and data_id in line:\n            url_line = _script[i + 1]\n            img_url = url_line.split('\"')[1]\n            img_url = urllib.parse.unquote(img_url.replace(r'\\u00', r'%'))\n    return img_url\n\n\ndef request(query, params):\n    \"\"\"Google-Video search request\"\"\"\n\n    language, country, lang_country = get_lang_country(\n        # pylint: disable=undefined-variable\n        params, supported_languages, language_aliases\n    )\n    subdomain = 'www.' + google_domains.get(country.upper(), 'google.com')\n\n    query_url = 'https://' + subdomain + '/search' + \"?\" + urlencode({\n        'q': query,\n        'tbm': \"isch\",\n        'hl': lang_country,\n        'lr': \"lang_\" + language,\n        'ie': \"utf8\",\n        'oe': \"utf8\",\n        'num': 30,\n    })\n\n    if params['time_range'] in time_range_dict:\n        query_url += '&' + urlencode({'tbs': 'qdr:' + time_range_dict[params['time_range']]})\n    if params['safesearch']:\n        query_url += '&' + urlencode({'safe': filter_mapping[params['safesearch']]})\n\n    params['url'] = query_url\n    logger.debug(\"query_url --> %s\", query_url)\n\n    params['headers']['Accept-Language'] = (\n        \"%s,%s;q=0.8,%s;q=0.5\" % (lang_country, language, language))\n    logger.debug(\n        \"HTTP Accept-Language --> %s\", params['headers']['Accept-Language'])\n    params['headers']['Accept'] = (\n        'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'\n    )\n    # params['google_subdomain'] = subdomain\n    return params\n\n\ndef response(resp):\n    \"\"\"Get response from google's search request\"\"\"\n    results = []\n\n    # detect google sorry\n    resp_url = urlparse(resp.url)\n    if resp_url.netloc == 'sorry.google.com' or resp_url.path == '/sorry/IndexRedirect':\n        raise RuntimeWarning('sorry.google.com')\n\n    if resp_url.path.startswith('/sorry'):\n        raise RuntimeWarning(gettext('CAPTCHA required'))\n\n    # which subdomain ?\n    # subdomain = resp.search_params.get('google_subdomain')\n\n    # convert the text to dom\n    dom = html.fromstring(resp.text)\n    img_bas64_map = scrap_out_thumbs(dom)\n    img_src_script = eval_xpath(dom, '//script[contains(., \"AF_initDataCallback({key: \")]')[1].text\n\n    # parse results\n    #\n    # root element::\n    #     <div id=\"islmp\" ..>\n    # result div per image::\n    #     <div jsmodel=\"tTXmib\"> / <div jsaction=\"...\" data-id=\"...\"\n    #     The data-id matches to a item in a json-data structure in::\n    #         <script nonce=\"I+vqelcy/01CKiBJi5Z1Ow\">AF_initDataCallback({key: 'ds:1', ... data:function(){return [ ...\n    #     In this structure the link to the origin PNG, JPG or whatever is given\n    # first link per image-div contains a <img> with the data-iid for bas64 encoded image data::\n    #      <img class=\"rg_i Q4LuWd\" data-iid=\"0\"\n    # second link per image-div is the target link::\n    #      <a class=\"VFACy kGQAp\" href=\"https://en.wikipedia.org/wiki/The_Sacrament_of_the_Last_Supper\">\n    # the second link also contains two div tags with the *description* and *publisher*::\n    #      <div class=\"WGvvNb\">The Sacrament of the Last Supper ...</div>\n    #      <div class=\"fxgdke\">en.wikipedia.org</div>\n\n    root = eval_xpath(dom, '//div[@id=\"islmp\"]')\n    if not root:\n        logger.error(\"did not find root element id='islmp'\")\n        return results\n\n    root = root[0]\n    for img_node in eval_xpath(root, './/img[contains(@class, \"rg_i\")]'):\n\n        try:\n            img_alt = eval_xpath(img_node, '@alt')[0]\n\n            img_base64_id = eval_xpath(img_node, '@data-iid')\n            if img_base64_id:\n                img_base64_id = img_base64_id[0]\n                thumbnail_src = img_bas64_map[img_base64_id]\n            else:\n                thumbnail_src = eval_xpath(img_node, '@src')\n                if not thumbnail_src:\n                    thumbnail_src = eval_xpath(img_node, '@data-src')\n                if thumbnail_src:\n                    thumbnail_src = thumbnail_src[0]\n                else:\n                    thumbnail_src = ''\n\n            link_node = eval_xpath(img_node, '../../../a[2]')[0]\n            url = eval_xpath(link_node, '@href')[0]\n\n            pub_nodes = eval_xpath(link_node, './div/div')\n            pub_descr = img_alt\n            pub_source = ''\n            if pub_nodes:\n                pub_descr = extract_text(pub_nodes[0])\n                pub_source = extract_text(pub_nodes[1])\n\n            img_src_id = eval_xpath(img_node, '../../../@data-id')[0]\n            src_url = scrap_img_by_id(img_src_script, img_src_id)\n            if not src_url:\n                src_url = thumbnail_src\n\n            results.append({\n                'url': url,\n                'title': img_alt,\n                'content': pub_descr,\n                'source': pub_source,\n                'img_src': src_url,\n                # 'img_format': img_format,\n                'thumbnail_src': thumbnail_src,\n                'template': 'images.html'\n            })\n        except Exception as e:  # pylint: disable=broad-except\n            logger.error(e, exc_info=True)\n            # from lxml import etree\n            # logger.debug(etree.tostring(img_node, pretty_print=True))\n            # import pdb\n            # pdb.set_trace()\n            continue\n\n    return results\n", "path": "searx/engines/google_images.py"}]}