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模式

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即可,大小写都转换为大写。