使用request模拟发送HTTP请求

694 阅读10分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第20篇文章,点击查看活动详情


requests 模块

Python有很多模块都可以发送HTTP请求,包括原生的模块 http.client,urllib2等,第三方模 块 requests等,都封装了发送HTTP请求的方法。由于原生的模块过于复杂,不推荐使用,之后 所有的请求都是基于第三方模块 requests 进行的,该模块的好处在于简单,把请求的框架都搭建 好了,只需要填入相应的参数数据,就能发送网络请求了。

requests模块非原生模块,所以要使用还需要先进行安装,按照之前介绍的安装模块的方法, 打开命令行(在运行中输入cmd),然后在命令行输入:

pip install requests

接着就会自动安装 requests 模块以及其相关模块,然后就可以引入该模块使用其提供的方 法了。

import requests

后面会通过一些实例来介绍requests的具体使用方法。

请求与响应

HTTP 就是发送请求和获取响应的一个过程,而requests 模块只需要一步就能完成这样的一 个过程,并且requests支持所有的HTTP请求的方法和响应数据,先进行语法介绍。

r=requests.方法(url,headers,data,·.·)

其中URL参数是必填的,毕竟HTTP请求就是对指定的URL进行发送,其他各种参数可根 据实际请求的需要选择性使用。

发送请求后会获取响应结果,然后把结果赋值给变量,最后通过变量的属性值取出需要的结 果,下面是常用返回结果。

r.headers 获取返回的头信息 

r.text 获取返回的主体

r.cookies 获取返回的cookie 

r.status_code 获取返回的状态码

学会了 requests的请求方法和获取响应的结果,就可以开始网络请求的测试了,下面就通过 代码实例来熟悉requests的模块吧。

请求参数

URL 参数

URL是唯一的必填参数,既然是网络请求,必须要有URL地址才能发送,就像快递一定 要写目的地才能发件一样。先从最简单的HTTP请求讲起,请求一个静态页面,比如访问网 易首页,通过抓包可以看到该请求是用get方式发送的,所以要调用requests的get(方法来发 送请求。

以网易首页作为请求例子,实例代码:

1 import requests

2 test_url ="http://www.163.com" 

3 response=requests.get(test_ur1) 

4 print(response.status_code) 

5 print (response.headers) 

6 print(response.text)

代码说明:

1 导入requests 模块。

2 将网易首页的URL赋值到变量test_url中(这样的好处在于看起来清晰,也方便代码今后 的维护,只需要修改test_url对应的URL就行了)。

3 在get(方法中将变量test_url直接传入,即完成了带着URL的get请求(结果会赋值到变 量response中,response中包含了返回结果的所有数据,可以根据需要获取想要的数据)。

4 获取并打印返回结果的状态码。

5 获取并打印返回结果的头信息。

6 获取并打印返回结果的内容。 运行结果如图所示。

image.png

可以看出通过requests 发送 HTTP 请求只有第3行代码,就那么简简单单的一行代码完成整 个请求。

整个请求过程全被封装在方法之中,对于没有编码基础的测试人员来说再适合不过了。

2.headers 参数

headers是最常用的参数之一,前面那个例子只是最简单的请求,没有带其他参数信息,而很 多时候需要带入headers 发送请求,才可以获取相应的请求结果。

还是以网易首页作为例子,如果是pc端的请求,会返回pc端的页面,如果是手机端的请求,则返回手机端的页面,这时候就要用带上 headers 参数的请求,通过浏览器的抓包工具可以看到headers 有个字段“User—Agent”,而服务器就是根据这个字段来判断访问的来源,如果需要模拟手机端请求,需要将“User—Agent”改为请求的手机型号。

实例代码:

1 import requests

2 test_url = "http://www.163.com"

3 h = {"User-Agent":"Android/H60-L01/4.4.2/"}

4 response = requests.get(test_ur1,headersers=h) 

5 print (response.status_code)

6 print (response.headers)

7 print (response.text) 

代码说明:

3 将需要发送的headers赋值到变量h之中。

4 在get(方法中加一个headers的参数,然后将变量h 赋值给headers 参数,即完成了带着header 信息的get请求。

运行结果如图所示。

image.png

3.cookies 参数

cookies也是最常用的参数之一,因为只要涉及登录后数据获取,都需要用到cookies参数, 那么如何获取 cookie呢?一种是通过post发送登录请求,获取返回值的cookies属性(这个会在 后面的实例中讲解),还有一种就是通过浏览器的网络抓包的方式获取,在还不会熟练使用 requests 模块的前提下,就先介绍如何通过抓包获取 cookies吧。

首先打开 chrome 浏览器,然后登录网易邮箱,接着按住F12键打开开发者工具,抓取 cookie 的界面如图所示。

image.png

选择 application中的cookies,点击对应的测试的URL域名,再找到Session 属性并且 Domain 是对应测试请求的域名,然后这条信息name和value对应的就是 cookie了。

cookies参数以字典的形式发送,只需要对应地将name和value 传入即可。 以网易邮箱登录后的请求为例,实例代码:

1 import requests

2c=("JSESSIONID":"6272E7C3762FA26619780AF615A75A0B")

3 test_url ="http://mail.163.com/js6/main.jsp?sid=xCsXkCUUCJYwVBCjouUUtnRzyRTfyHOs&df =163nav_icon#module=welcome.WelcomeModule&7C&7B&7D"

4 response=requests.get(test_url,cookies=c)

5 print (response.status_code)

6 print (response.headers) 

7 print (response.text)

代码说明:

2 将浏览器的抓取的cookies 信息以字典的形式赋值到变量c之中。

4 在get方法中加一个cookies的参数,然后将变量c赋值给cookies参数,即完成了带着cookie 信息的get请求。

运行结果如图所示。

image.png

实例代码:

1 import requests

2c="JSESSIONID=6272E7C3762FA26619780AF615A75A0B"

3 test_ur1="https://mail.163.com/js6/main.jsp?sid=xCsXkCUUCJYwVBCjouUUtn RzyRTfyHOs&df=163nav_icon#module=welcome.WelcomeModule&7C&7Bt7D"

4 response=requests.get(test_url,headers={"cookie":c}) 

5 print(response.status_code)

6 print(response.headers) 

7 print(response.text)

代码说明:

其实 cookie 也是可以通过headers参数传递的,只是不同之处在于cookie是以字典的形式发 送的,而在headers之中 cookie只是其中一个键,所以需要把 cookie放到该键对应的值里面,而 对应的值是以key=value的形式传入的,改一下代码。

2 将浏览器的抓取的cookies 信息以字符串的形式赋值到变量c之中。

4 在get方法中将变量c赋值给 headers 参数中的 cookie字段,即完成了带着 cookie 信息的get 请求。

运行结果如图所示。

image.png 可以看到运行结果与上面代码一致,只是使用的参数不一样,然后对应数据类型不一样而已。这2种方法其实都可以用,但还是推荐使用cookies参数。一方面把cookies单独分离出来,不用与其他 headers的字段放在一起,让代码更清晰;另外一方面通过post请求返回的cookies是可以直接赋值到cookies参数之中的,不需要再做转换。

4.params 参数

对于params 参数可以存放请求的表单,并会以keyl=valuel&key2=values的形式跟在URL之 后发送,为了区分URL和参数,最好不要把表单放在URL之中,可以通过params参数进行发送,上面网易邮箱的URL也是带着参数的,直接放到URL之中,如果使用params参数就可以把后面的参数和URL分离。

还以网易邮箱为例,只是URL部分把参数进行分离,实例代码:

1 import requests

2c="JSESSIONID=6272E7C3762FA26619780AF615A75A0B" 

3 test_url="http://mail.163.com/js6/main.jsp"

4 p = {"sid":"xCsXkCUUCJYwVBCjouUUtnRzyRTfyHOs","df":"163nav_icon#module= welcome.WelcomeModule&7C&7B&7D"}

5 response=requests.get(test_url,headers = {"cookie":c},params=p)

6 print(response.status_code)

7 print (response.headers) 

8 print (response.text)

代码说明:

4 将需要发送表单以字典的形式赋值到变量p之中。

5 在get方法中加一个params的参数,然后将变量p赋值给params参数,即完成了带着params信息的get请求。

运行结果如图所示。

image.png

运行结果还是和上面一致的,params的使用还是比较简单的,如果不使用这个参数的话,也可以直接把表单加到url之中,只是代码不清晰,也不容易维护,所以不推荐这种方法。

5.data 参数

data 参数也是用于存放请求的表单,是request模块中最重要的参数之一。

在使用data之前,先来了解一下post提交数据类型,区别于params,后者只有一种类型,就是字符串,而post可以提交4种类型的数据,至于需要提交什么类型取决于服务器接收的数据类型,post的数据类型需要和服务器接收的一致,不然服务器就无法正确识别post的数据,导致测试结果报错。就像协议一样,接收方约定接收哪种类型的表单,然后发送方按照接收方指定的协议发送表单,这样就完成了一个表单的提交。

如何识别服务器接收的数据类型呢?最简单的方式还是抓包。抓取数据类型的界面如图所示。

image.png

通过抓包可以看到,在request headers 中有一个 content-tpye的字段,这个字段表示了post 发送数据的类型,一般分为以下4种类型。

(1)Content-Type:application/json

实际上,现在越来越多的人把application/json作为请求头,用来告诉服务器端消息主体是序列化后 的JSON字符串。由于JSON规范的流行,除了低版本IE之外的各大浏览器都原生支持JSON.stringify, 服务端器语言也都有处理JSON的函数,并且JSON格式支持比键值对更加复杂的结构化数据。

(2)Content-Type:application/x-www-form-urlencoded

这是最常见的POST提交数据的方式,浏览器的原生form表单,如果不设置enctype属性, 那么最终就会以 application/x-www-form-urlencoded 方式提交数据。提交的数据按照 keyl= valuel&key2=value2的方式进行编码,key和value都进行了URL转码,然后打包发送到服务器。

(3)Content-Type:multipart/form-data Content-Type为multipart/form-data方式,主要用于上传文件。需要注意的是同时form的enctype 属性也要设置为multipart/form—data,才能正确提交并解析所传输的数据。

(4)Content-Type:text/xml

它是一种使用HTTP作为传输协议,XML作为编码方式的远程调用规范。考虑到XML结构 还是过于臃肿,一般场景用JSON会更灵活方便,所以这种提交方式在我们的工作中实际使用的 不多,仅了解一下就可以了。

最常见的是 application/x-www-form-urlencoded这种类型,直接将数据以{key:value}的字典形 式赋值给表单,然后通过 request.post()中的data参数传递就可以了。

以网易音乐为例,搜索一首歌曲,通过抓包可以看到 content-Type是 application/x-www-form- urlencoded,网易音乐的数据类型抓取如图所示。

image.png

搜索一首 nothing to lose,通过抓包会发现有进行加密,那就直接把加密后的内容放到form之中发送出去,网易音乐的表单抓取如图所示。

image.png

实例代码:

image.png

代码说明:

3 将需要发送的表单(抓包获取的参数)以字典的形式赋值到变量 form之中。

4 在post方法中加一个data参数,然后将变量 form赋值给data参数,即完成了带着表单信息的post请求。

运行结果如图所示。

image.png