尝试使用scrapy来抓取一个网站,该网站将其帖子请求编码为" multipart / form-data"出于某种原因。
有没有办法使用" application / x-www-form-urlencoded"来覆盖scrapy的默认发布行为?
看起来该网站没有响应蜘蛛,因为它希望使用" multipart / form-data"来发布请求。
尝试过对表单变量进行多部分编码,但是看过使用wireshark,scrapy仍然错误地设置了标头,无论这种编码如何。
答案 0 :(得分:0)
只需使用scrapy.http.FormRequest代替scrapy.Request,在formdata参数中传递参数。
示例代码:
import scrapy
from scrapy.http import FormRequest
class MySpider(scrapy.Spider):
# ...
def start_requests(self):
yield FormRequest(some_post_url,
formdata=dict(param1='value1', param2='value2'))
答案 1 :(得分:0)
您可以使用此MultipartRequest:
代码:
from scrapy import Request
from StringIO import StringIO
import mimetypes
import random
class MultipartRequest(Request):
def __init__(self, *args, **kwargs):
formdata = kwargs.pop('formdata', None)
files = kwargs.pop('files', None)
kwargs['method'] = 'POST'
super(MultipartRequest, self).__init__(*args, **kwargs)
self._boundary = '-----------------------------{0}'.format(random.random() * 1e10)
if formdata or files:
buffer = StringIO()
if formdata:
self._write_formdata(formdata, buffer)
if files:
self._write_files(files, buffer)
self.headers['Content-Type'] = 'multipart/form-data; boundary={0}'.format(self._boundary)
self._set_body(buffer.getvalue())
def _write_formdata(self, formdata, buffer):
for key, value in formdata.iteritems():
buffer.write('--{0}\r\n'.format(self._boundary))
buffer.write('Content-Disposition: form-data; name="{0}"\r\n'.format(key))
buffer.write('\r\n')
buffer.write('{0}\r\n'.format(str(value).encode('utf-8')))
def _write_files(self, files, buffer):
for key, filedesc, fd in files:
buffer.write('--{0}\r\n'.format(self._boundary))
buffer.write('Content-Disposition: form-data; name="{0}"; filename="{1}"\r\n'.format(key, filedesc))
buffer.write('Content-Type: {0}\r\n'.format(self.get_content_type(filedesc)))
buffer.write('\r\n')
if isinstance(fd, basestring):
buffer.write(fd)
else:
buffer.write(fd.getvalue())
buffer.write('\r\n')
buffer.write('--{0}--\r\n'.format(self._boundary))
buffer.write('\r\n')
def get_content_type(self, filepath):
return mimetypes.guess_type(filepath)[0] or 'application/octet-stream'
答案 2 :(得分:0)
我花了更多的时间在这上面比我想要的更多,所以这里是scrapy
中的情况的概述。
multipart/form-data
内容类型具有您需要遵循的特定编码类型。您可以在发送此类请求时查看此示例,检查任何主要浏览器的Network
中的Developer tools
标签。以下是multipart/form-data
请求正文/有效负载
-----------------------------9128252932315252835063017
Content-Disposition: form-data; name="username"
tibor.udvari
-----------------------------9128252932315252835063017
Content-Disposition: form-data; name="passwd"
secret
-----------------------------9128252932315252835063017
Content-Disposition: form-data; name="_mode"
edit
-----------------------------9128252932315252835063017--
您还必须在标头中设置相应的Content-Type
和Content-Length
。
在撰写本文时,Scrapy 1.4
没有便利的方式来发送multipart/form-data
个请求。您必须自己构建一个帖子请求。
首先,您需要从数据中构建请求,我使用MultipartEncoder
requests-toolbelt
类来执行此操作。
formdata = {'username': 'example', 'password': 'example'}
me = MultipartEncoder(fields=formdata)
me_boundary = me.boundary[2:] #need this in headers
me_length = me.len #need this in headers
me_body = me.to_string() #contains the request body
下一步是创建带有有效标头的请求
headers = {
'Content-Type': 'multipart/form-data; charset=utf-8; boundary=' + me_boundary,
'Content-Length': me_length
}
r = scrapy.Request(url='https://example.com', method='POST', body=me_body, headers=headers)
发送此请求应该产生有效的响应,如果它以某种方式格式错误,您应该得到服务器响应,例如"上传错误"。
假设您正在使用scrapy shell
,您现在可以发送请求
fetch(r)
我只使用文本输入进行了测试,处理文件可能需要更多步骤。