有时候我们需要用脚本模仿浏览器向服务器发送请求,这个时候首先需要打开浏览器进入调试功能,然后找到发送请求时浏览器所发送的数据,包括请求的header和数据部分。如下图所示:
这是请求的header
这是请求的content部分
要模拟浏览器发送请求很简单,就是将上面的信息全都封装成json的数据格式,然后发送给服务器就好了。
下面是用python request实现的。需要注意的是,服务器需要进行csrftoken验证。为了让同一个对象能够跨请求保持某些参数,同一个Session实例发出的所有请求之间cookies是相同的,所以我们需要跨请求来保持cookies
下面是代码:
import requests
login_url = 'http://example.com'
client=requests.session()
client.get(login_url)
csrf_token=client.cookies['csrftoken']
hed={'X-CSRFToken':csrf_token,'Refer':'http://example.com','User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36','Content-Type':'application/x-www-form-urlencoded'}
udata={'csrfmiddlewaretoken':csrf_token,'username':'111','password':'123456','this_is_the_login_form':1,'next':'/admin/'}
r=client.post(login_url,data=udata,headers=hed)
在向别的url发送请求的过程中,我发现了有时候我们发送的数据不是form data而是multipart/form-data,和form data比起来这个数据格式就看起来比较复杂:
multipart/form-data主要由三部分组成:
1 HTTP Header。需要添加头"Content-Type: multipart/form-data; boundary=%s",这个boundary就是分隔符,见第二条。
2 分隔符boundary。分隔符是一串和正文内容不冲突的字符串,用以分割多个参数。一般都是N个减号+随机字符串,比如"----------当前时间"。
正文需要加header:Content-Disposition: form-data; name="%s",%s为需要传递的变量名。
Content-Type: 指定正文MIME类型,默认是纯文本text/plain,未知类型可以填application/octet-stream。
3 数据。要注意的是数据的编码,文档上说"7BIT encoding",ISO-8859-1即可。
我试了好几种方法,后来发现,对发送的数据按照上面的那种格式进行处理以后然后按照刚才的方法发送比较有效。
代码如下:
import requests
import time
import string
def _encode_multipart(params_dict):
boundary = '----%s' % hex(int(time.time() * 10000000))
data = []
for k, v in params_dict.items():
data.append('--%s' % boundary)
if hasattr(v, 'read'):
filename = getattr(v, 'name', '')
content = v.read()
decoded_content = content.decode('ISO-8859-1')
data.append('Content-Disposition: form-data; name="%s"; filename="hidden"' % k)
data.append('Content-Type: application/octet-stream\r\n')
data.append(decoded_content)
else:
data.append('Content-Disposition: form-data; name="%s"\r\n' % k)
data.append(v if isinstance(v, str) else v.decode('utf-8'))
data.append('--%s--\r\n' % boundary)
return '\r\n'.join(data), boundary
usradd_url='http://example.com'
client.get(usradd_url)
csrf_token1=client.cookies['csrftoken']
username='test'+str(i)
print username
fdata={'csrfmiddlewaretoken':csrf_token,'username':username,'password1':'123456','password2':'123456','_save':'Save'}
rfdata,boundary=_encode_multipart(fdata)
nbdry='multipart/form-data;boundary='+boundary
hed1={'X-CSRFToken':csrf_token,'Refer':'http://example.com','User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36','Content-Type':nbdry}
re=client.post(usradd_url,data=rfdata.encode('ISO-8859-1'),headers=hed1)
print re.status_code