原文:https://www.cnblogs.com/wang-yc/p/5623711.html
Python标准库中提供了:urllib等模块以供Http请求,但是,它的 API 太渣了。它是为另一个时代、另一个互联网所创建的。它需要巨量的工作,甚至包括各种方法覆盖,来完成最简单的任务。
发送GET请求
1
2
3
4
|
import urllib.request f = urllib.request.urlopen( 'http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508' ) result = f.read().decode( 'utf-8' ) |
发送携带请求头的GET请求
1
2
3
4
5
6
7
|
import urllib.request req = urllib.request.Request( 'http://www.example.com/' ) req.add_header( 'Referer' , 'http://www.python.org/' ) r = urllib.request.urlopen(req) result = f.read().decode( 'utf-8' ) |
Requests 是使用 Apache2 Licensed 许可证的 基于Python开发的HTTP 库,其在Python内置模块的基础上进行了高度的封装,从而使得Pythoner进行网络请求时,变得美好了许多,使用Requests可以轻而易举的完成浏览器可有的任何操作。
requests库特性:
- Keep-Alive & 连接池
- 国际化域名和 URL
- 带持久 Cookie 的会话
- 浏览器式的 SSL 认证
- 自动内容解码
- 基本/摘要式的身份认证
- 优雅的 key/value Cookie
- 自动解压
- Unicode 响应体
- HTTP(S) 代理支持
- 文件分块上传
- 流下载
- 连接超时
- 分块请求
- 支持 .netrc
1. 安装模块
1
2
3
4
|
安装: pip install requests 更新: pip install - - upgrade requests |
2. 使用模块
HTTP的请求类型有POST,GET,PUT,DELETE,HEAD 以及 OPTIONS,其中POST和GET是最常使用的。
GET请求
import requests # 无参数示例 r = requests.get('https://httpbin.org/get') # 有参数示例 r = requets.get('http://httpbin.org/get', params=d) 传递URL参数: 在URL中常见?符号,http://httpbin.org/get?key=val 这种带有?传递关键字参数的方式,requests可以通过params实现。 d = {'k1':'v1', 'k2':'v2', 'k3':None, 'k4':['v4','v5']} # 字典中键值为None的键不会被添加到URL中 # 多个键值中间用&符号连接 # 键值可是列表 例如'k4' print(r.url) 执行结果为:http://httpbin.org/get?k1=v1&k2=v2&k4=v4&k4=v5
POST请求
# 1、基本POST实例 import requests payload = {'key1': 'value1', 'key2': 'value2'} ret = requests.post("http://httpbin.org/post", data=payload) print(ret.text) # 输出结果 { "args": {}, "data": "", "files": {}, "form": { "key1": "value1", "key2": "value2" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Content-Length": "23", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "python-requests/2.18.4" }, "json": null, "origin": "不告诉你这里返回的是你的IP地址", "url": "http://httpbin.org/post" } # 2、发送请求头和数据实例 import requests import json url = 'https://api.github.com/some/endpoint' payload = {'some': 'data'} headers = {'content-type': 'application/json'} ret = requests.post(url, data=json.dumps(payload), headers=headers) print(ret.text) print(ret.cookies) # 输出结果 {"message":"Not Found","documentation_url":"https://developer.github.com/v3"} <RequestsCookieJar[]>
关于响应内容
requests模块的返回对象是一个Response对象,可以从这个对象中获取需要的信息。下面 r 代表Response对象。
- r.text 文本响应内容
- r.context 二进制响应内容
- r.json() JSON响应内容
- r.raw 原始相应内容
# 文本响应内容 Response对象包含很多信息,Requests可以自动对大多数unicode字符集无缝解码。 请求发出后,Requests会基于HTTP头部对响应的编码做出有根据的推测。 我们可以通过r.encoding得到编码,也可以使用r.encoding属性改变编码 #二进制响应内容 对于非文本请求r.content,Requests会自动解码gzip和deflate传输编码的响应内容。 # JSON相应内容 需要注意如果JSON解码失败,r.json()会抛出异常。然而成功调用r.json()并不意味着响应成功,因为某些服务器失败 的相应中也会包含一个JSON对象,这种JSON会被解码返回。如果要判断请求是否成功,可以使用r.raise_for_status() 或者检查r.status_code是否和预期相同。 # 原始相应内容 如果需要获取服务器的原始套接字相应,可以使用r.raw,使用时要确保在初始请求中设置了 stream=True r = requests.get('https://httpbin.org/get', stream=True) print(r.raw) print(r.raw.read(10)) # 结果输出 <urllib3.response.HTTPResponse object at 0x061665F0> b'{ "args"
定制请求头
如果想要添加HTTP头部,只需要传递一个字典给headers参数即可。注意: 所有的 header 值必须是 string、bytestring 或者 unicode。尽管传递 unicode header 也是允许的,但不建议这样做。
注意:定制header的优先级低于某些特定的信息源,例如:
- 如果在 .netrc 中设置了用户认证信息,使用 headers= 设置的授权就不会生效。而如果设置了 auth= 参数,``.netrc`` 的设置就无效了。
- 如果被重定向到别的主机,授权 header 就会被删除。
- 代理授权 header 会被 URL 中提供的代理身份覆盖掉。
- 在我们能判断内容长度的情况下,header 的 Content-Length 会被改写
更进一步讲,Requests 不会基于定制 header 的具体情况改变自己的行为。只不过在最后的请求中,所有的 header 信息都会被传递进去。
url = 'https://api.github.com/some/endpoint' headers = {'user-agent': 'my-app/0.0.1'} r = requests.get(url, headers=headers)
响应状态码
可以通过响应状态码得知请求的结果,一般 200表示请求成功,Requests还附带一个内置的状态码查询对象 request.codes:
>>> r = requests.get('http://httpbin.org/get') >>> r.status_code 200 >>> r.status_code == requests.codes.ok True # 如果发送了一个错误请求(一个 4XX 客户端错误,或者 5XX 服务器错误响应),我们可以通过 Response.raise_for_status() 来抛出异常: >>> bad_r = requests.get('http://httpbin.org/status/404') >>> bad_r.status_code 404 >>> bad_r.raise_for_status() Traceback (most recent call last): File "requests/models.py", line 832, in raise_for_status raise http_error requests.exceptions.HTTPError: 404 Client Error # 但是,由于我们的例子中 r 的 status_code 是 200 ,当我们调用 raise_for_status() 时,得到的是: >>> r.raise_for_status() None
响应头
>>> r.headers { 'content-encoding': 'gzip', 'transfer-encoding': 'chunked', 'connection': 'close', 'server': 'nginx/1.0.4', 'x-runtime': '148ms', 'etag': '"e1ca502697e5c9317743dc078f67693f"', 'content-type': 'application/json' } #但是这个字典比较特殊:它是仅为 HTTP 头部而生的。根据 RFC 2616, HTTP 头部是大小写不敏感的。 >>> r.headers['Content-Type'] 'application/json' >>> r.headers.get('content-type') 'application/json'
Cookie
>>> url = 'http://example.com/some/cookie/setting/url' >>> r = requests.get(url) >>> r.cookies['example_cookie_name'] 'example_cookie_value' # 如果想要发送你的cookies到服务器,可以使用cookies参数 >>> url = 'http://httpbin.org/cookies' >>> cookies = dict(cookies_are='working') >>> r = requests.get(url, cookies=cookies) >>> r.text '{"cookies": {"cookies_are": "working"}}' # Cookie 的返回对象为 RequestsCookieJar,它的行为和字典类似,但界面更为完整,适合跨域名跨路径使用。你还可以把 Cookie Jar 传到 Requests 中: >>> jar = requests.cookies.RequestsCookieJar() >>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies') >>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere') >>> url = 'http://httpbin.org/cookies' >>> r = requests.get(url, cookies=jar) >>> r.text '{"cookies": {"tasty_cookie": "yum"}}'
超时
你可以告诉 requests 在经过以 timeout
参数设定的秒数时间之后停止等待响应。基本上所有的生产代码都应该使用这一参数。如果不使用,你的程序可能会永远失去响应。
>>> requests.get('http://github.com', timeout=0.001) Traceback (most recent call last): File "<stdin>", line 1, in <module> requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001) # 注意事项 timeout 仅对连接过程有效,与响应体的下载无关。 timeout 并不是整个下载响应的时间限制,而是如果服务器在 timeout 秒内没有应答, 将会引发一个异常(更精确地说,是在 timeout 秒内没有从基础套接字上接收到任何字节的数据时) If no timeout is specified explicitly, requests do not time out.
错误与异常
遇到网络问题(如:DNS 查询失败、拒绝连接等)时,Requests 会抛出一个 ConnectionError 异常。
如果 HTTP 请求返回了不成功的状态码, Response.raise_for_status() 会抛出一个 HTTPError 异常。
若请求超时,则抛出一个 Timeout 异常。
若请求超过了设定的最大重定向次数,则会抛出一个 TooManyRedirects 异常。
所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException 。
其他请求
1
2
3
4
5
6
7
8
9
10
|
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) |
3. Http请求和XML实例
实例:检测QQ账号是否在线
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import urllib import requests from xml.etree import ElementTree as ET # 使用内置模块urllib发送HTTP请求,或者XML格式内容 """ f = urllib.request.urlopen('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508') result = f.read().decode('utf-8') """ # 使用第三方模块requests发送HTTP请求,或者XML格式内容 r = requests.get( 'http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508' ) result = r.text # 解析XML格式内容 node = ET.XML(result) # 获取内容 if node.text = = "Y" : print ( "在线" ) else : print ( "离线" ) |
实例:查看火车停靠信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import urllib import requests from xml.etree import ElementTree as ET # 使用内置模块urllib发送HTTP请求,或者XML格式内容 """ f = urllib.request.urlopen('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=G666&UserID=') result = f.read().decode('utf-8') """ # 使用第三方模块requests发送HTTP请求,或者XML格式内容 r = requests.get( 'http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=G666&UserID=' ) result = r.text # 解析XML格式内容 root = ET.XML(result) for node in root. iter ( 'TrainDetailInfo' ): print (node.find( 'TrainStation' ).text,node.find( 'StartTime' ).text,node.tag,node.attrib) |