使用Python提高工作效率之Requests库

Python是一门强大且灵活的脚本语言,依赖众多强大的第三方库可以大大提高工作效率。在网络编程和自动化领域Python有着大量的实际应用,可以用C语言编写Python底层的实现库,然后通过Python简洁的语法,在实际工作中快速达到为所欲为的目的。由于最近工作需要配合测试人员进行一些数据接口的大量访问和数据的批量生成,为了能够高效的完成工作我选择了Python。工作中一些零散的任务我也基本上是以Python来完成,我决定分为几篇文章来对一些基本库的使用进行记录,方便日后查阅以及学习。本章节我先以比较常用的request库开始。

快速上手

发送请求

第一步:导入requests模块

1
>>> import requests

第二步:请求网络资源

1
>>> r = requests.get('https://www.lanshiqin.com')

使用方式非常简单,只需要引入requests的模块,然后发送GET请求只需要一行代码搞定。
上述步骤将会使用GET请求网站并且将响应的Response对象赋值给r。

Requests还支持各种RESTFul方式的请求

1
2
3
4
5
>>> r = requests.post('http://httpbin.org/post', data={'key': 'value'})
>>> r = requests.put('http://httpbin.org/put', data={'key': 'value'})
>>> r = requests.delete('http://httpbin.org/delete')
>>> r = requests.head('http://httpbin.org/get')
>>> r = requests.options('http://httpbin.org/get')

响应内容

1
2
3
4
import requests
r = requests.get('https://api.github.com/')
print(r.text)
# 输出文本内容 {"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","notifications_url":"https://api.github.com/notifications","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_url":"https://api.github.com/orgs/{org}","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","team_url":"https://api.github.com/teams","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}

r.text输出文本内容的编码是Request进行自动推断的,可以使用r.encoding来输出实际响应的编码,也可以自己自定Response的编码

1
r.encoding = 'utf-8'

二进制响应内容

对于非文本请求,可以用字节byte的方式来访问响应内容
Request库提供了r.content来访问二进制响应内容

1
2
3
4
5
6
7
8
9
import requests
from PIL import Image
from io import BytesIO
# 请求图片
r = requests.get('https://github.githubassets.com/images/icons/emoji/unicode/1f947.png?v8')
# 打开图片
i = Image.open(BytesIO(r.content))
# 保存图片
i.save('1f947.png', 'png')

原始响应内容

对于一些文件的下载,可以使用Request库提供的r.raw获取原始响应内容
可以使用r.raw.read(1024)指定大小的读取原始内容
大多数情况下一般会将原始内容保存为文件

1
2
3
4
5
6
7
import requests
# 请求数据
r = requests.get('https://dl.pstmn.io/download/latest/osx', stream=True)
print(r.raw.read(10))
with open('osx.zip', 'wb') as fd:
for chunk in r.iter_content(1024):
fd.write(chunk)

requests请求时要指定属性值stream=True,通过Requests库提供的iter_content方法可以指定一次读取多少数据

更加复杂的请求

请求头参数

以我个人的使用场景作为参考,使用请求头参数最多是爬虫程序,因为要伪装成正常的用户请求,所以不得不在请求头参数中指定UA和Cookie等值。除此之外,对于正常的程序访问来说我们一般也需要一些认证授权信息,可以通过自定义请求头参数来进行验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests

url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2019-01-07&leftTicketDTO.from_station=XMS&leftTicketDTO.to_station=YXS&purpose_codes=ADULT'
headers = {
'accept': '*/*',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
'cache-control': 'no-cache',
'cookie': 'JSESSIONID=165AEDA56401B93F15E336494663D93E; tk=eZwgZIZASH0T-_CHKxmQrHzn0XZAtbknB1gk02D_ONMmk1110; RAIL_EXPIRATION=1546917370307; RAIL_DEVICEID=d0WOu4qSJ_ujU4sVmDaD6LfXgFfxHTWIBX__FHRtRH7o4E_3UvHcp86Iv2qCOFoEiDAh-ihWW2e6s7RnINhR1Ff8oR3In-wiOPokEhTyh1X-zci59jSrdIxTarXFrtWu03bxxzpuO0k8dfaKhCC3njv8PjH9mPtp; BIGipServerpassport=887619850.50215.0000; route=c5c62a339e7744272a54643b3be5bf64; BIGipServerotn=284164618.38945.0000; BIGipServerpool_passport=300745226.50215.0000; _jc_save_fromStation=%u53A6%u95E8%2CXMS; _jc_save_toStation=%u5C24%u6EAA%2CYXS; _jc_save_toDate=2019-01-06; _jc_save_wfdc_flag=dc; current_captcha_type=Z; _jc_save_fromDate=2019-01-07',
'if-modified-since': '0',
'referer': 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E5%8E%A6%E9%97%A8,XMS&ts=%E5%B0%A4%E6%BA%AA,YXS&date=2019-01-06&flag=N,N,Y',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
'x-requested-with': 'XMLHttpRequest'
}
r = requests.get(url=url, headers=headers)
print(r.text)

上面的请求头参数,是我用Chrome浏览器访问12306购票网站,然后在开发者模式下查看网络请求得到的数据,通过请求头参数就可以完美的模拟浏览器的请求,服务端将无法区分出到底是来自用户正常的浏览器,还是一个自动化的脚步程序。通过这些特性我们可以做一些小工具方便自己。

POST请求参数

在发起请求的时候设置data参数值来指定请求参数,data默认是一个表单数据格式,键值对表示要传送的参数名和对应的参数值。

1
2
3
4
5
6
7
8
9
10
import requests

# 请求数据
data = {
'CMD': '102',
'CITYNAME': '厦门市',
'KEYWORD': '641'
}
r = requests.post('https://wx.shenghuoquan.cn/WxBusServer/ApiData.do', data=data)
print(r.text)

如果要传送的格式为json格式,只需要在上述的data参数中指定data=json.dumps(data)即可,使用json需要在头部引入import json,不过最新版的Request库为我们做了自动转换,如果接口接受一个json而不是表单,request库会自动将data转换为json。
上面的请求参数和请求地址,是我通过抓包工具得到的,某公交实时查询软件所请求的数据,通过post请求并且带上不同的参数值,可以达到和软件请求一样的效果。由于该软件打开有广告并且我认为一些功能是我用不到的,所以我可以通过抓包分析然后通过Python模拟请求,最终确定想要的数据接口后,自己开发一个基于该接口的App。

POST上传Multipart类型的文件

通过Post请求上传文件是很常见的场景,在Postman等工具中可以方便的选择文件并且上传到指定地址,使用Python的Request一样很方便

1
2
3
4
5
6
import requests

url = 'http://httpbin.org/post'
files = {'file': open('1f947.png', 'rb')}
r = requests.post(url, files=files)
print(r.text)

同样的,在请求的时候指定files参数值为一个打开的文件对象,files = {'file': open('1f947.png', 'rb')}这行代码可以打开1f947.png这个文件作为 file的值。Python的语法优雅到如此简单。

高级用法

代理

目前中国大陆有长城防火墙,把Google等一些国外网站给过滤了,正常的直接网络是访问不到的,所以一般都会租用大陆以外的服务器作为代理去替我们访问目标网站,本地->代理->Google等被墙的网站。
Requests库提供了代理功能,可以在Python中使用代理去访问网络资源,使用方式非常简单

1
2
3
4
5
6
7
8
9
import requests

proxies = {
"http": "http://127.0.0.1:1087",
"https": "https://127.0.0.1:1087"
}

r = requests.get("https://www.google.com/", proxies=proxies)
print(r.text)

在请求的时候要指定proxies属性值为我们的代理配置,我使用的是自己搭建的VPN服务器,本地是Shadowsokes客户端,这里的配置需要根据实际情况做修改。
代理的使用场景很多,不仅仅是访问被墙的网站,通过一条完美的代理线路以及程序的配合,可以绕过各种限制做各种为所欲为的事情。
使用代理比较常见的是爬虫,通过代理池去访问目标网站降低被反爬虫程序的发现。

更多用法

更多高级用法请访问Requests的官方文档:
http://docs.python-requests.org/zh_CN/latest/user/advanced.html#advanced
快速入门文档:
http://docs.python-requests.org/zh_CN/latest/user/quickstart.html

0%