requests
requests
python中的请求库,相当于php中的curl。是对底层库进一层封装。
资源
https://www.cnblogs.com/lsdb/p/9071015.html 这篇文章还算比较全。
https://www.cnblogs.com/fu-yong/p/9226008.html 这片文章,非常好。
除了requests库,还可以尝试用用urllib3的库。用法非常相似。【链接地址】
安装
pip install requests
使用
简单的用法如下:
import requests
requests.get(url)
requests.post(url)
参数
requests.get,request.post的参数示例如下
| 参数 | 作用 | 请求 | 示例 |
|---|---|---|---|
| url | 设置请求的url | http://www.baidu.com | |
| verify | https时不验证证书 | verify=False | |
| data | post请求参数,json或url | post | data=’username=ls&password=toor’ |
| json | 请求参数,map对象 | {“username”:”ls”,”password”:”toor”} | |
| headers | 请求头,map对象 | key:value形式的对象,可以设置cookie等 | |
| proxies | 设置代理 | proxies={‘http’:’127.0.0.1:80’, ‘https’:’127.0.0.1:8080’} | |
| cookies | 设置cookie | {‘name1’:’cookie1’} 可能会被headers中的设置覆盖 | |
| payload | 请求参数,map对象 | get | {“username”:”ls”,”password”:”toor”} |
| files | 上传文件,map对象 | post | {‘f1’:open(‘xxxx.log’,’rb’)} |
| auth | auth认证 | get | HTTPBasicAuth(‘zhangsan’,’password’) |
| timeout | 设置请求超时 | 1 | |
| 重定向allow_redirects | False | ||
| stream | 大文件下载 | ||
| cert | 证书 | “xxx/xxx/xx.pem” |
大文件下载补充:
from contextlib import closing
with closing(requests.get('http://httpbin.org/get', stream=True)) as r1:
# 在此处理响应。
for i in r1.iter_content():
print(i)
返回对象
response对象的主要参数如下:
| 参数 | 说明 | 示例 |
|---|---|---|
| status_code | 请求成功的返回码 | 200 |
| text | 文本,如html网页内容 | |
| content | 二进制内容,如音乐、图片等 | 直接写入到文件 |
| encoding | 设置text的编码格式,避免乱码。 | reps.encoding=”utf-8” |
| url | 请求的url | |
常用的操作
编码问题:
如果返回是utf-8,而导致乱码,可以使用下面来修正乱码问题。(注意,乱码也有可能是终端显示问题,可能换一个就能正常的显示)
resp = requests.get(href)
resp.encoding= 'utf-8'
其他请求
requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.head(url, **kwargs)
requests.delete(url, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.options(url, **kwargs)
# 以上方法均是在此方法的基础上构建
requests.request(method, url, **kwargs)
下载文件
示例,下载一个图片
核心是response.content以二进制的形式,写入到文件中。
def download_img(src):
arr = src.rsplit('/',1)
name = arr[1] if len(arr) > 1 else arr[0]
name = 'img/%d'%random.randint(1000,9999) + name
with open(name,'wb') as f:
res = requests.get(src)
f.write(res.content)
会话保持
经常很多请求只有在登录后才能进行,实现登录效果一般的做法是执行登录请求,然后从返回结果中提取sessionid放入自定义cookie中。
这种方法在requests中也行得通,但requests提供了更为简单的方法,直接使用request.Session类来请求即可,其保持登录的原理是保留之前请求中服务端通过set-cookie等设置的参数。
s = Session()
url='http://docs.python-requests.org/en/master/'
# 所有方法和直接使用requests时一样用即可
s.get(url)
会话保持,因为避免频繁的建立tcp连接,效率会高一点点。
通过以下方式观察,有无反复建立tcp连接。
strace -p 54206 -e trace=connect # p 进程id
netstat -an | awk '/^tcp/ {++State[$NF]}END{for(key in State)print key "\t" State[key]}'
# 无回话保持时 TIME_WAIT也多
示例代码+header
def get(url):
try:
user_agent ='Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0'
response = requests.get(url, headers={'User-Agent': user_agent})
response.raise_for_status() # 如果返回的状态码不是200, 则抛出异常;
response.encoding = response.apparent_encoding # 判断网页的编码格式, 便于respons.text知道如何解码;
except Exception as e:
print("爬取错误")
print(e)
else:
print(response.url)
print("爬取成功!")
return response.content
cookie
有两种方式,直接使用cookie模式
cookies = {
'sessionid':'',
'csrftoken':''
}
res = requests.get('http://archery.yundasys.com:9123/sqlquery/',cookies=cookies)
或者,在header中指明,注意,整体拼接成字符串格式,放在里面。
header = {
'Cookie':'sessionid=3uf4;',
'X-CSRFToken':'z2Lv7qWG8YkQY',
'Referer': 'http://:9123/sqlquery/',
'Host': '',
'Origin': '',
}
res = requests.post(url,data= data,headers=header,cookies=cookies)
如果,两者都使用了,貌似,cookie的方式会覆盖header中指明的方式。
请求响应的返回体,处理cookies response.cookies
cookies = res.cookies
# 转换成字典格式 方式1
cookie = requests.utils.dict_from_cookiejar(cookies)
# 方式2:
cookie = req.cookies.get_dict(cookies)
# 方式3: kv 遍历
cookies = res.cookies.items()
for k,v in cookies
# 方式4: 直接以字段去访问
phpsessid = cookies['phpsessid']
env_orgcode = cookies['env_orgcode']
仅获取响应头,不想获取内容
想测试某个url指定的位置,是否存在某个文件,而不打算下载该文件时,则按增加请求参数,stream=True即可。但是注意:不能获取resp.text、resp.content等属性,如果获取该响应,则会触发下载流类容。
def get_id(uid):
for i in range(10):
try:
resp = requests.get(url,headers=headers,stream=True)
break
except:
print('网络可能超时 id -- %s'%uid )
sleep(1)
print(resp.status_code)
# print(resp.text) 如果调用 resp.text 等属性,则会触发下载。
# 仅仅查看 响应状态,则不会触发
print('ok')
对于要下载的文件,我们不下载,但是想知道文件多大,也可以用这种方式。
resp.headers['Content-Length']
失败重试
import requests
from requests.adapters import HTTPAdapter, Retry
s = requests.Session()
retries = Retry(total=5,
backoff_factor=0.1,
status_forcelist=[ 500, 502, 503, 504 ])
s.mount('http://', HTTPAdapter(max_retries=retries))
s.get('http://httpstat.us/500')
# 或者简单的
s.mount('http://', HTTPAdapter(max_retries=3))
示例
模拟登录
参见 snippet/ython/export_archery.py 登录的示例。
异常
常用的异常类有:
异常捕捉
乱码
乱码始终是困扰着我的,不管是python、还是php语言,我都遇到过这样的问题。对于php来讲,将所有的代码均保存为utf-8格式,读取的txt、数据库等也都设置为utf-8格式,一般来说,就很少出现乱码问题。
使用requests库请求网页,也可能会出现乱码问题。针对乱码,可以尝试:
"""
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
print('你好') # 首先,脚本使用utf-8格式,查看,能否正常的输出中文字符,确保不是终端显示的问题
# 尝试使用下面两种编码,查看能否正常的输出中文。
resp = requests.get(url,headers=headers())
# resp.encoding = 'utf-8' # 编码问题
resp.encoding = 'gbk' # 编码问题
print(resp.text)
# 实在不知道是什么编码,先保存成文件,再查看是何种编码
with open('t.txt','wb') as fo:
fo.write(resp.content)
# 打开模式是 'wb',所以,写入的是字节流。
# 如果打开的是 'w',则需要字符串。
resp.content应该是原始的,未经解码的字节流。
resp.text 应该是解码后的字符串。resp.encoding 对resp.text有效,对resp.content无效。
resp.content.decode('gbk')
# 等价于下面
resp.encoding = 'gbk' # 编码问题
resp.text
问题
遇到一个奇怪的问题,本地指定HTTP_TOKEN,php 那边使用HTTP_TOKEN无法获取到token,打印后,发现变成了HTTP_HTTP_TOKEN,只需要提交的时候,token即可,大小写都转换为大写。