diff --git a/scrapy/utils/iterators.py b/scrapy/utils/iterators.py
index ce59c9719..b0688791e 100644
--- a/scrapy/utils/iterators.py
+++ b/scrapy/utils/iterators.py
@@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
 
 def xmliter(obj, nodename):
     """Return a iterator of Selector's over all nodes of a XML document,
-       given tha name of the node to iterate. Useful for parsing XML feeds.
+       given the name of the node to iterate. Useful for parsing XML feeds.
 
     obj can be:
     - a Response object
@@ -35,7 +35,7 @@ def xmliter(obj, nodename):
     header_end = re_rsearch(HEADER_END_RE, text)
     header_end = text[header_end[1]:].strip() if header_end else ''
 
-    r = re.compile(r"<{0}[\s>].*?</{0}>".format(nodename_patt), re.DOTALL)
+    r = re.compile(r'<%(np)s[\s>].*?</%(np)s>' % {'np': nodename_patt}, re.DOTALL)
     for match in r.finditer(text):
         nodetext = header_start + match.group() + header_end
         yield Selector(text=nodetext, type='xml').xpath('//' + nodename)[0]
@@ -48,7 +48,7 @@ def xmliter_lxml(obj, nodename, namespace=None, prefix='x'):
     iterable = etree.iterparse(reader, tag=tag, encoding=reader.encoding)
     selxpath = '//' + ('%s:%s' % (prefix, nodename) if namespace else nodename)
     for _, node in iterable:
-        nodetext = etree.tostring(node)
+        nodetext = etree.tostring(node, encoding='unicode')
         node.clear()
         xs = Selector(text=nodetext, type='xml')
         if namespace:
@@ -128,8 +128,11 @@ def csviter(obj, delimiter=None, headers=None, encoding=None, quotechar=None):
 
 
 def _body_or_str(obj, unicode=True):
-    assert isinstance(obj, (Response, six.string_types, bytes)), \
-        "obj must be Response or basestring, not %s" % type(obj).__name__
+    expected_types = (Response, six.text_type, six.binary_type)
+    assert isinstance(obj, expected_types), \
+        "obj must be %s, not %s" % (
+            " or ".join(t.__name__ for t in expected_types),
+            type(obj).__name__)
     if isinstance(obj, Response):
         if not unicode:
             return obj.body

XMLFeedSpider encoding issue
Scrapy version: 1.04

My spider (from the XMLFeedSpider example in the docs) doesn´t seem to read the defined itertag since it contains the iso-8859-1 letter "Þ"
http://www.w3schools.com/charsets/ref_html_8859.asp

I´ve tried my code on a different url with english xml tags and it works fine.

```python
# -*- coding: utf-8 -*-

import scrapy

from scrapy.spiders import XMLFeedSpider
from althingi_scraper.items import PartyItem

class PartySpider(XMLFeedSpider):
    name = 'party'
    allowed_domains = ['http://www.althingi.is']
    #session = '145'  

    start_urls = [
        #'http://www.althingi.is/altext/xml/thingflokkar/?lthing=%s' % session,        
        'http://www.althingi.is/altext/xml/thingflokkar/'
    ]   

    itertag = 'þingflokkar'

    def parse_node(self, response, node):        
        item = PartyItem()
        item['party_id'] = node.xpath('@id').extract()
        item['name'] = node.xpath('heiti').extract()
        #item['short_abbr'] = node.xpath('stuttskammstöfun').extract()
        #item['long_abbr'] = node.xpath('löngskammstöfun').extract()
        
        return item
```

Any thoughts?
diff --git a/tests/test_utils_iterators.py b/tests/test_utils_iterators.py
index d42ed2c91..b2e3889a4 100644
--- a/tests/test_utils_iterators.py
+++ b/tests/test_utils_iterators.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 import os
 import six
 from twisted.trial import unittest
@@ -46,6 +47,60 @@ class XmliterTestCase(unittest.TestCase):
                  for e in self.xmliter(response, 'matchme...')]
         self.assertEqual(nodenames, [['matchme...']])
 
+    def test_xmliter_unicode(self):
+        # example taken from https://github.com/scrapy/scrapy/issues/1665
+        body = u"""<?xml version="1.0" encoding="UTF-8"?>
+            <þingflokkar>
+               <þingflokkur id="26">
+                  <heiti />
+                  <skammstafanir>
+                     <stuttskammstöfun>-</stuttskammstöfun>
+                     <löngskammstöfun />
+                  </skammstafanir>
+                  <tímabil>
+                     <fyrstaþing>80</fyrstaþing>
+                  </tímabil>
+               </þingflokkur>
+               <þingflokkur id="21">
+                  <heiti>Alþýðubandalag</heiti>
+                  <skammstafanir>
+                     <stuttskammstöfun>Ab</stuttskammstöfun>
+                     <löngskammstöfun>Alþb.</löngskammstöfun>
+                  </skammstafanir>
+                  <tímabil>
+                     <fyrstaþing>76</fyrstaþing>
+                     <síðastaþing>123</síðastaþing>
+                  </tímabil>
+               </þingflokkur>
+               <þingflokkur id="27">
+                  <heiti>Alþýðuflokkur</heiti>
+                  <skammstafanir>
+                     <stuttskammstöfun>A</stuttskammstöfun>
+                     <löngskammstöfun>Alþfl.</löngskammstöfun>
+                  </skammstafanir>
+                  <tímabil>
+                     <fyrstaþing>27</fyrstaþing>
+                     <síðastaþing>120</síðastaþing>
+                  </tímabil>
+               </þingflokkur>
+            </þingflokkar>"""
+
+        for r in (
+            # with bytes
+            XmlResponse(url="http://example.com", body=body.encode('utf-8')),
+            # Unicode body needs encoding information
+            XmlResponse(url="http://example.com", body=body, encoding='utf-8')):
+
+            attrs = []
+            for x in self.xmliter(r, u'þingflokkur'):
+                attrs.append((x.xpath('@id').extract(),
+                              x.xpath(u'./skammstafanir/stuttskammstöfun/text()').extract(),
+                              x.xpath(u'./tímabil/fyrstaþing/text()').extract()))
+
+            self.assertEqual(attrs,
+                             [([u'26'], [u'-'], [u'80']),
+                              ([u'21'], [u'Ab'], [u'76']),
+                              ([u'27'], [u'A'], [u'27'])])
 
     def test_xmliter_text(self):
         body = u"""<?xml version="1.0" encoding="UTF-8"?><products><product>one</product><product>two</product></products>"""
@@ -96,6 +151,10 @@ class XmliterTestCase(unittest.TestCase):
 
         self.assertRaises(StopIteration, next, iter)
 
+    def test_xmliter_objtype_exception(self):
+        i = self.xmliter(42, 'product')
+        self.assertRaises(AssertionError, next, i)
+
     def test_xmliter_encoding(self):
         body = b'<?xml version="1.0" encoding="ISO-8859-9"?>\n<xml>\n    <item>Some Turkish Characters \xd6\xc7\xde\xdd\xd0\xdc \xfc\xf0\xfd\xfe\xe7\xf6</item>\n</xml>\n\n'
         response = XmlResponse('http://www.example.com', body=body)
@@ -169,6 +228,9 @@ class LxmlXmliterTestCase(XmliterTestCase):
         node = next(my_iter)
         self.assertEqual(node.xpath('f:name/text()').extract(), ['African Coffee Table'])
 
+    def test_xmliter_objtype_exception(self):
+        i = self.xmliter(42, 'product')
+        self.assertRaises(TypeError, next, i)
 
 class UtilsCsvTestCase(unittest.TestCase):
     sample_feeds_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'sample_data', 'feeds')

pip install -e .
parse_log_pytest
requirements.txt
pytest pytest-cov
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==25.3.0
Automat==24.8.1
cffi==1.17.1
constantly==23.10.4
coverage==7.8.0
cryptography==44.0.2
cssselect==1.3.0
exceptiongroup==1.2.2
hyperlink==21.0.0
idna==3.10
incremental==24.7.2
iniconfig==2.1.0
jmespath==1.0.1
lxml==5.3.1
packaging==24.2
parsel==1.10.0
pluggy==1.5.0
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
PyDispatcher==2.0.7
pyOpenSSL==25.0.0
pytest==8.3.5
pytest-cov==6.0.0
queuelib==1.7.0
-e git+https://github.com/scrapy/scrapy.git@f01fd076420f0e58a1a165be31ec505eeb561ef4#egg=Scrapy
service-identity==24.2.0
six==1.17.0
tomli==2.2.1
Twisted==24.11.0
typing_extensions==4.13.0
w3lib==2.3.1
zope.interface==7.2

name: scrapy
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==25.3.0
      - automat==24.8.1
      - cffi==1.17.1
      - constantly==23.10.4
      - coverage==7.8.0
      - cryptography==44.0.2
      - cssselect==1.3.0
      - exceptiongroup==1.2.2
      - hyperlink==21.0.0
      - idna==3.10
      - incremental==24.7.2
      - iniconfig==2.1.0
      - jmespath==1.0.1
      - lxml==5.3.1
      - packaging==24.2
      - parsel==1.10.0
      - pluggy==1.5.0
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pycparser==2.22
      - pydispatcher==2.0.7
      - pyopenssl==25.0.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - queuelib==1.7.0
      - service-identity==24.2.0
      - six==1.17.0
      - tomli==2.2.1
      - twisted==24.11.0
      - typing-extensions==4.13.0
      - w3lib==2.3.1
      - zope-interface==7.2
prefix: /opt/conda/envs/scrapy

tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_unicode
tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_defaults tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_delimiter tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_delimiter_binary_response_assume_utf8_encoding tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_encoding tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_exception tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_falserow tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_headers tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_quotechar tests/test_utils_iterators.py::UtilsCsvTestCase::test_csviter_wrong_quotechar
tests/test_utils_iterators.py::XmliterTestCase::test_xmliter tests/test_utils_iterators.py::XmliterTestCase::test_xmliter_encoding tests/test_utils_iterators.py::XmliterTestCase::test_xmliter_exception tests/test_utils_iterators.py::XmliterTestCase::test_xmliter_namespaces tests/test_utils_iterators.py::XmliterTestCase::test_xmliter_objtype_exception tests/test_utils_iterators.py::XmliterTestCase::test_xmliter_text tests/test_utils_iterators.py::XmliterTestCase::test_xmliter_unicode tests/test_utils_iterators.py::XmliterTestCase::test_xmliter_unusual_node tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_encoding tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_exception tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_iterate_namespace tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_namespaces tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_namespaces_prefix tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_objtype_exception tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_text tests/test_utils_iterators.py::LxmlXmliterTestCase::test_xmliter_unusual_node tests/test_utils_iterators.py::TestHelper::test_body_or_str
scrapy/utils/iterators.py
scrapy/utils/iterators.py