prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Duden search engine not working anymore
  They changed the site layout.
  
  --- 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/duden.py`
  Content:
  ```
  1 """
  2  Duden
  3  @website     https://www.duden.de
  4  @provide-api no
  5  @using-api   no
  6  @results     HTML (using search portal)
  7  @stable      no (HTML can change)
  8  @parse       url, title, content
  9 """
  10 
  11 from lxml import html, etree
  12 import re
  13 from searx.engines.xpath import extract_text
  14 from searx.url_utils import quote
  15 from searx import logger
  16 
  17 categories = ['general']
  18 paging = True
  19 language_support = False
  20 
  21 # search-url
  22 base_url = 'https://www.duden.de/'
  23 search_url = base_url + 'suchen/dudenonline/{query}?page={offset}'
  24 
  25 
  26 def request(query, params):
  27     '''pre-request callback
  28     params<dict>:
  29       method  : POST/GET
  30       headers : {}
  31       data    : {} # if method == POST
  32       url     : ''
  33       category: 'search category'
  34       pageno  : 1 # number of the requested page
  35     '''
  36 
  37     offset = (params['pageno'] - 1)
  38     params['url'] = search_url.format(offset=offset, query=quote(query))
  39     return params
  40 
  41 
  42 def response(resp):
  43     '''post-response callback
  44     resp: requests response object
  45     '''
  46     results = []
  47 
  48     dom = html.fromstring(resp.text)
  49 
  50     try:
  51         number_of_results_string = re.sub('[^0-9]', '', dom.xpath(
  52             '//a[@class="active" and contains(@href,"/suchen/dudenonline")]/span/text()')[0]
  53         )
  54 
  55         results.append({'number_of_results': int(number_of_results_string)})
  56 
  57     except:
  58         logger.debug("Couldn't read number of results.")
  59         pass
  60 
  61     for result in dom.xpath('//section[@class="wide" and not(contains(@style,"overflow:hidden"))]'):
  62         try:
  63             logger.debug("running for %s" % str(result))
  64             link = result.xpath('.//h2/a')[0]
  65             url = link.attrib.get('href')
  66             title = result.xpath('string(.//h2/a)')
  67             content = extract_text(result.xpath('.//p'))
  68             # append result
  69             results.append({'url': url,
  70                             'title': title,
  71                             'content': content})
  72         except:
  73             logger.debug('result parse error in:\n%s', etree.tostring(result, pretty_print=True))
  74             continue
  75 
  76     return results
  77
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/searx/engines/duden.py b/searx/engines/duden.py
  --- a/searx/engines/duden.py
  +++ b/searx/engines/duden.py
  @@ -11,7 +11,7 @@
   from lxml import html, etree
   import re
   from searx.engines.xpath import extract_text
  -from searx.url_utils import quote
  +from searx.url_utils import quote, urljoin
   from searx import logger
   
   categories = ['general']
  @@ -20,7 +20,7 @@
   
   # search-url
   base_url = 'https://www.duden.de/'
  -search_url = base_url + 'suchen/dudenonline/{query}?page={offset}'
  +search_url = base_url + 'suchen/dudenonline/{query}?search_api_fulltext=&page={offset}'
   
   
   def request(query, params):
  @@ -35,7 +35,11 @@
       '''
   
       offset = (params['pageno'] - 1)
  -    params['url'] = search_url.format(offset=offset, query=quote(query))
  +    if offset == 0:
  +        search_url_fmt = base_url + 'suchen/dudenonline/{query}'
  +        params['url'] = search_url_fmt.format(query=quote(query))
  +    else:
  +        params['url'] = search_url.format(offset=offset, query=quote(query))
       return params
   
   
  @@ -58,12 +62,11 @@
           logger.debug("Couldn't read number of results.")
           pass
   
  -    for result in dom.xpath('//section[@class="wide" and not(contains(@style,"overflow:hidden"))]'):
  +    for result in dom.xpath('//section[not(contains(@class, "essay"))]'):
           try:
  -            logger.debug("running for %s" % str(result))
  -            link = result.xpath('.//h2/a')[0]
  -            url = link.attrib.get('href')
  -            title = result.xpath('string(.//h2/a)')
  +            url = result.xpath('.//h2/a')[0].get('href')
  +            url = urljoin(base_url, url)
  +            title = result.xpath('string(.//h2/a)').strip()
               content = extract_text(result.xpath('.//p'))
               # append result
               results.append({'url': url,
  
verification_info: {"golden_diff": "diff --git a/searx/engines/duden.py b/searx/engines/duden.py\n--- a/searx/engines/duden.py\n+++ b/searx/engines/duden.py\n@@ -11,7 +11,7 @@\n from lxml import html, etree\n import re\n from searx.engines.xpath import extract_text\n-from searx.url_utils import quote\n+from searx.url_utils import quote, urljoin\n from searx import logger\n \n categories = ['general']\n@@ -20,7 +20,7 @@\n \n # search-url\n base_url = 'https://www.duden.de/'\n-search_url = base_url + 'suchen/dudenonline/{query}?page={offset}'\n+search_url = base_url + 'suchen/dudenonline/{query}?search_api_fulltext=&page={offset}'\n \n \n def request(query, params):\n@@ -35,7 +35,11 @@\n     '''\n \n     offset = (params['pageno'] - 1)\n-    params['url'] = search_url.format(offset=offset, query=quote(query))\n+    if offset == 0:\n+        search_url_fmt = base_url + 'suchen/dudenonline/{query}'\n+        params['url'] = search_url_fmt.format(query=quote(query))\n+    else:\n+        params['url'] = search_url.format(offset=offset, query=quote(query))\n     return params\n \n \n@@ -58,12 +62,11 @@\n         logger.debug(\"Couldn't read number of results.\")\n         pass\n \n-    for result in dom.xpath('//section[@class=\"wide\" and not(contains(@style,\"overflow:hidden\"))]'):\n+    for result in dom.xpath('//section[not(contains(@class, \"essay\"))]'):\n         try:\n-            logger.debug(\"running for %s\" % str(result))\n-            link = result.xpath('.//h2/a')[0]\n-            url = link.attrib.get('href')\n-            title = result.xpath('string(.//h2/a)')\n+            url = result.xpath('.//h2/a')[0].get('href')\n+            url = urljoin(base_url, url)\n+            title = result.xpath('string(.//h2/a)').strip()\n             content = extract_text(result.xpath('.//p'))\n             # append result\n             results.append({'url': url,\n", "issue": "Duden search engine not working anymore\nThey changed the site layout.\n", "before_files": [{"content": "\"\"\"\n Duden\n @website     https://www.duden.de\n @provide-api no\n @using-api   no\n @results     HTML (using search portal)\n @stable      no (HTML can change)\n @parse       url, title, content\n\"\"\"\n\nfrom lxml import html, etree\nimport re\nfrom searx.engines.xpath import extract_text\nfrom searx.url_utils import quote\nfrom searx import logger\n\ncategories = ['general']\npaging = True\nlanguage_support = False\n\n# search-url\nbase_url = 'https://www.duden.de/'\nsearch_url = base_url + 'suchen/dudenonline/{query}?page={offset}'\n\n\ndef request(query, params):\n    '''pre-request callback\n    params<dict>:\n      method  : POST/GET\n      headers : {}\n      data    : {} # if method == POST\n      url     : ''\n      category: 'search category'\n      pageno  : 1 # number of the requested page\n    '''\n\n    offset = (params['pageno'] - 1)\n    params['url'] = search_url.format(offset=offset, query=quote(query))\n    return params\n\n\ndef response(resp):\n    '''post-response callback\n    resp: requests response object\n    '''\n    results = []\n\n    dom = html.fromstring(resp.text)\n\n    try:\n        number_of_results_string = re.sub('[^0-9]', '', dom.xpath(\n            '//a[@class=\"active\" and contains(@href,\"/suchen/dudenonline\")]/span/text()')[0]\n        )\n\n        results.append({'number_of_results': int(number_of_results_string)})\n\n    except:\n        logger.debug(\"Couldn't read number of results.\")\n        pass\n\n    for result in dom.xpath('//section[@class=\"wide\" and not(contains(@style,\"overflow:hidden\"))]'):\n        try:\n            logger.debug(\"running for %s\" % str(result))\n            link = result.xpath('.//h2/a')[0]\n            url = link.attrib.get('href')\n            title = result.xpath('string(.//h2/a)')\n            content = extract_text(result.xpath('.//p'))\n            # append result\n            results.append({'url': url,\n                            'title': title,\n                            'content': content})\n        except:\n            logger.debug('result parse error in:\\n%s', etree.tostring(result, pretty_print=True))\n            continue\n\n    return results\n", "path": "searx/engines/duden.py"}], "after_files": [{"content": "\"\"\"\n Duden\n @website     https://www.duden.de\n @provide-api no\n @using-api   no\n @results     HTML (using search portal)\n @stable      no (HTML can change)\n @parse       url, title, content\n\"\"\"\n\nfrom lxml import html, etree\nimport re\nfrom searx.engines.xpath import extract_text\nfrom searx.url_utils import quote, urljoin\nfrom searx import logger\n\ncategories = ['general']\npaging = True\nlanguage_support = False\n\n# search-url\nbase_url = 'https://www.duden.de/'\nsearch_url = base_url + 'suchen/dudenonline/{query}?search_api_fulltext=&page={offset}'\n\n\ndef request(query, params):\n    '''pre-request callback\n    params<dict>:\n      method  : POST/GET\n      headers : {}\n      data    : {} # if method == POST\n      url     : ''\n      category: 'search category'\n      pageno  : 1 # number of the requested page\n    '''\n\n    offset = (params['pageno'] - 1)\n    if offset == 0:\n        search_url_fmt = base_url + 'suchen/dudenonline/{query}'\n        params['url'] = search_url_fmt.format(query=quote(query))\n    else:\n        params['url'] = search_url.format(offset=offset, query=quote(query))\n    return params\n\n\ndef response(resp):\n    '''post-response callback\n    resp: requests response object\n    '''\n    results = []\n\n    dom = html.fromstring(resp.text)\n\n    try:\n        number_of_results_string = re.sub('[^0-9]', '', dom.xpath(\n            '//a[@class=\"active\" and contains(@href,\"/suchen/dudenonline\")]/span/text()')[0]\n        )\n\n        results.append({'number_of_results': int(number_of_results_string)})\n\n    except:\n        logger.debug(\"Couldn't read number of results.\")\n        pass\n\n    for result in dom.xpath('//section[not(contains(@class, \"essay\"))]'):\n        try:\n            url = result.xpath('.//h2/a')[0].get('href')\n            url = urljoin(base_url, url)\n            title = result.xpath('string(.//h2/a)').strip()\n            content = extract_text(result.xpath('.//p'))\n            # append result\n            results.append({'url': url,\n                            'title': title,\n                            'content': content})\n        except:\n            logger.debug('result parse error in:\\n%s', etree.tostring(result, pretty_print=True))\n            continue\n\n    return results\n", "path": "searx/engines/duden.py"}]}