Форма метода POST в lxml вызывает TypeError с submit_form
Я пытаюсь отправить форму метода POST с помощью lxml, и я получаю TypeError. Это минимальный пример, который вызывает эту ошибку:
>>> import lxml.html
>>> page = lxml.html.parse("http://www.webcom.com/html/tutor/forms/start.shtml")
>>> form = page.getroot().forms[0]
>>> form.fields['your_name'] = 'Morphit'
>>> result = lxml.html.parse(lxml.html.submit_form(form))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.3/site-packages/lxml/html/__init__.py", line 887, in submit_form
return open_http(form.method, url, values)
File "/usr/lib/python3.3/site-packages/lxml/html/__init__.py", line 907, in open_http_urllib
return urlopen(url, data)
File "/usr/lib/python3.3/urllib/request.py", line 160, in urlopen
return opener.open(url, data, timeout)
File "/usr/lib/python3.3/urllib/request.py", line 471, in open
req = meth(req)
File "/usr/lib/python3.3/urllib/request.py", line 1183, in do_request_
raise TypeError(msg)
TypeError: POST data should be bytes or an iterable of bytes. It cannot be of type str.
Я нашел точную ошибку в другом месте в Интернете, но я не видел ее генерируемой изнутри lxml, как это. Кто-нибудь знает, является ли это ошибкой, ожидаемым поведением и как обойти его?
Ответы
Ответ 1
Из https://github.com/lxml/lxml/pull/122/files:
"В python3 urlopen ожидает байтовый поток для данных POST. Этот патч кодирует данные в utf-8 перед передачей." В src/lxml/html/__ init__.py измените строку 918,
data = urlencode(values)
к
data = urlencode(values).encode('utf-8')
Ответ 2
Это Python 3, поэтому вы должны написать
form.fields['your_name'] = b'Morphit'
или
form.fields['your_name'] = 'Morphit'.encode('utf-8')
Ответ 3
def myopen_http(method, url, values):
if not url:
raise ValueError("cannot submit, no URL provided")
## FIXME: should test that it not a relative URL or something
try:
from urllib import urlencode, urlopen
except ImportError: # Python 3
from urllib.request import urlopen
from urllib.parse import urlencode
if method == 'GET':
if '?' in url:
url += '&'
else:
url += '?'
url += urlencode(values)
data = None
else:
data = urlencode(values).encode('utf-8')
return urlopen(url, data)
result = lxml.html.parse(lxml.html.submit_form(form, open_http=myopen_http))