广东南粤风采36选7走势图

  • 热门专题

正确认识python的request库

作者:  发布日期:2019-06-10 18:49:54
Tag标签:request库,python  
  • 2015年我触及 Python 的那时候,就得闻 Python 的网络编程能力非常强悍。因而,在了解 Python 的基础语法以后,我就和几个小伙伴们一块儿协作,试着用 Python 的 urllib 和 urllib2 库构建了一个百度贴吧 Python 客户端。
    然而,应用的过程中,我发现了两个标准库的语法并不自然,以至于可以说非常反人类——用着很不舒服。又有,我平日应用 Python 甚少涉及网络编程的内容。因而,Python 的网络编程就被我放下了,直至我了解了 requests 库。

    初次了解 requests
    requests 库的宣言是
     
    HTTP for Humans (给人用的 HTTP 库)
     
    我们最先来检验一下。
     
    在网络编程中,最为基础的任务包括:
     
        发送请求
        登入
        获取数据
        解析数据
        反序列化重新打印获得的内容
     
    我们以 GitHub 为例,先看一下应用 urllib2 要怎样做。因为要把事儿弄简单,我们假设实现已经知道,GET 请求 https://api.github.com/ 返回的内容是个 JSON 格式的数据(事实上通过 content-type 也可以判定)。
     
    import urllib2
    import json
     
    gh_url  = 'https://api.github.com'
    cs_user = 'user'
    cs_psw  = 'password'
     
    req = urllib2.Request(gh_url)
     
    password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
    password_manager.add_password(None, gh_url, cs_user, cs_psw)
     
    auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
    opener = urllib2.build_opener(auth_manager)
     
    urllib2.install_opener(opener)
     
    handler = urllib2.urlopen(req)
     
    if handler.getcode() == requests.codes.ok:
        text = handler.read()
        d_text = json.loads(text)
        for k, v in d_text.items():
            print k, v
     
    如果运行正确,那么代码应该返回:
     
    issues_url https://api.github.com/issues
    current_user_repositories_url https://api.github.com/user/repos{?type,page,per_page,sort}
    rate_limit_url https://api.github.com/rate_limit
    repository_url https://api.github.com/repos/{owner}/{repo}
    ...
    user_repositories_url https://api.github.com/users/{user}/repos{?type,page,per_page,sort}
    team_url https://api.github.com/teams
     
    一样的作用,用 requests 库则有如下代码:
     
    import requests
     
    cs_url  = 'https://api.github.com'
    cs_user = 'user'
    cs_psw  = 'password'
    r = requests.get(cs_url, auth=(cs_user, cs_psw))
    if r.status_code == requests.codes.ok
        for k, v in r.json().items():
            print k, v
     
    溢美之词就不比说了,读完在这里的你内心一定会只有一声「握草,这才算 Python 该有的模样」。那么,接下去让我们看一下 requests 还有哪几种黑魔法。
     
    安装
     
    最受欢迎的方式,是直接安装推荐过的 Anaconda。
     
    当然如果你不愿安装 Anaconda,那我建议你采用 pip 安装;只需在命令行下执行:
     
    pip install requests

    基本用法
     
    requests 的主要使用方法,呃,简直不能再主要了。最主要的操作方法,就是说以某种 HTTP 方式向远端服务器发送1个请求不过如此;而 requests 库就是这样做的:
     
    import requests
     
    cs_url = 'http://httpbin.org'
     
    r = requests.get("%s/%s" % (cs_url, 'get'))
    r = requests.post("%s/%s" % (cs_url, 'post'))
    r = requests.put("%s/%s" % (cs_url, 'put'))
    r = requests.delete("%s/%s" % (cs_url, 'delete'))
    r = requests.patch("%s/%s" % (cs_url, 'patch'))
    r = requests.options("%s/%s" % (cs_url, 'get'))
     
    从语法上看,requests 库设计构思的十分自然。说白了 requests.get,就是说以 GET 方式发送1个 REQUEST,得到1个 Response 类的结果,储存为 r。
     
    你能在 r 中获得全部你想要的和 HTTP 有关的信息。下面,让我们以 GET 方式为例,先后详细介绍。
     
    URL 传参 / 获得请求的 URL
     
    如果要是你常常上网(屁话,看到这儿的都上过网吧……),一定会见过相似下边的链接:
     
    https://encrypted.google.com/search?q=hello
     
    即:
     
    <协议>://<网站域名>/<接口>?<键1>=<值1>&<键2>=<值2>
     
    requests 库给出的 HTTP 方式方法,都提供了名为 params 的基本参数。这一基本参数能够接收1个 Python 字典,并自动格式化为上述文件格式。
     
    import requests
     
    cs_url = 'http://www.so.com/s'
    param  = {'ie':'utf-8', 'q':'query'}
     
    r = requests.get (cs_url, params = param)
    print r.url
     
    执行将获得:
     
    http://www.so.com/s?q=query&ie=utf-8
     
    HTTP 情况码 / 重定向跳转
     
    requests 库定义的 Response 类能够便捷地获得请求的 HTTP 状态码和重定向情况。
     
    360 公司的搜索引擎,以前的名字叫「好搜」,如今改为「360 搜索」;网站域名也从 www.haosou.com 改为了 www.so.com。要是你在浏览器的地址栏中输入 www.haosou.com,那样会通过 302 跳转到 www.so.com。让我们借此机会来演试。

    import requests
     
    cs_url = 'http://www.so.com/s'
    param  = {'ie':'utf-8', 'q':'query'}
    r = requests.get (cs_url, params = param)
    print r.url, r.status_code
     
    cs_url = 'http://www.haosou.com/s'
    r = requests.get (cs_url, params = param)
    print r.url, r.status_code, r.history
     
    结果是:
    http://www.so.com/s?q=query&ie=utf-8 200
    http://www.so.com/s?q=query&ie=utf-8 200 [302]>]
     
    我们发现,requests 默认自动地处理了 302 跳转。在经过跳转的请求中,返回的 URL 和状态码都是跳转之后的信息;唯独在 history 中,用 Python 列表记录了跳转情况。
    大多数情况下,自动处理是挺好的。不过,有时候我们也想单步追踪页面跳转情况。此时,可以给请求加上 allow_redirects = False 参数。
     
    import requests
     
    cs_url = 'http://www.so.com/s'
    param  = {'ie':'utf-8', 'q':'query'}
    r = requests.get (cs_url, params = param)
    print r.url, r.status_code
     
    cs_url = 'http://www.haosou.com/s'
    r = requests.get (cs_url, params = param, allow_redirects = False)
    print r.url, r.status_code, r.history
     
    输出结果:
     
    http://www.so.com/s?q=query&ie=utf-8 200
    http://www.haosou.com/s?q=query&ie=utf-8 302 []
     
    不容许 requests 自动处置重定向跳转后,反回的 URL 和状态码都合乎预估了。
     
    请求超时设定
     
    requests 的请求超时设定以秒为基本单位。比如,对请求加主要参数 timeout = 5 就可设定请求超时为 5 秒。
     
    # a very short timeout is set intentionally
     
    import requests
     
    cs_url = 'http://www.zhihu.com'
    r = requests.get (cs_url, timeout = 0.000001)
     
    反回错误码:
     
    Traceback (most recent call last):
      File "D:\test\py\test.py", line 6, in <module>
        r = requests.get (cs_url, timeout = 0.000001)
      File "C:\Users\username\AppData\Local\Continuum\Anaconda\lib\site-packages\requests\api.py", line 69, in get
        return request('get', url, params=params, **kwargs)
      File "C:\Users\username\AppData\Local\Continuum\Anaconda\lib\site-packages\requests\api.py", line 50, in request
        response = session.request(method=method, url=url, **kwargs)
      File "C:\Users\username\AppData\Local\Continuum\Anaconda\lib\site-packages\requests\sessions.py", line 465, in request
        resp = self.send(prep, **send_kwargs)
      File "C:\Users\username\AppData\Local\Continuum\Anaconda\lib\site-packages\requests\sessions.py", line 573, in send
        r = adapter.send(request, **kwargs)
      File "C:\Users\username\AppData\Local\Continuum\Anaconda\lib\site-packages\requests\adapters.py", line 419, in send
        raise ConnectTimeout(e, request=request)
    requests.exceptions.ConnectTimeout: HTTPConnectionPool(host='www.zhihu.com', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(object at 0x0000000002AFABE0>, 'Connection to www.zhihu.com timed out. (connect timeout=1e-06)'))
     
    请求头
     
    我们使用 httpbin 这一个网站,先了解一下 requests 发出的 HTTP 报文默认的请求头是啥样子的。
     
    import requests
     
    cs_url = 'http://httpbin.org/get'
    r = requests.get (cs_url)
    print r.content
     
    反回结果:
    {
      "args": {},
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Host": "httpbin.org",
        "User-Agent": "python-requests/2.7.0 CPython/2.7.10 Windows/7"
      },
      "origin": "xx.xx.xx.xx",
      "url": "http://httpbin.org/get"
    }
    需注意,在这里采用 r.content 来查询请求头部是由于 httpbin 这一个网站的特别性——它什么活都不干,就把对方请求的具体内容反回给请求者。在 requests 之中,应该采用 r.request.headers 来查询请求的头部。
    一般而言让我们较为关心其中的 User-Agent 和 Accept-Encoding。要是让我们要改动 HTTP 头中的这两项具体内容,只需用将1个适合的字典基本参数传到 headers 即可。
     
    import requests
     
    my_headers = {'User-Agent' : 'From Liam Huang', 'Accept-Encoding' : 'gzip'}
    cs_url = 'http://httpbin.org/get'
    r = requests.get (cs_url, headers = my_headers)
    print r.content
     
    反回:
    {
      "args": {},
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip",
        "Host": "httpbin.org",
        "User-Agent": "From Liam Huang"
      },
      "origin": "xx.xx.xx.xx",
      "url": "http://httpbin.org/get"
    }
     
    可以看到,UA 和 AE 都已经被改动了。
     
    响应头
     
    作为 HTTP 请求的响应,返回的内容中也有 HTTP 头。它是一个反序列化为 Python 字典的数据结构,可以通过 Response.headers 来查看。
     
    import requests
     
    cs_url = 'http://httpbin.org/get'
    r = requests.get (cs_url)
    print r.headers
    返回:
     
    {
        "content-length": "263",
        "server": "nginx",
        "connection": "keep-alive",
        "access-control-allow-credentials": "true",
        "date": "Fri, 26 Feb 2016 10:26:17 GMT",
        "access-control-allow-origin": "*",
        "content-type": "application/json"
    }
     
    响应内容
     
    字节模式 / 自动解包
     
    长期以来,互联网都存在带宽有限的情况。因此,网络上传输的数据,很多情况下都是经过压缩的。经由 requests 发送的请求,当收到的响应内容经过 gzip 或 deflate 压缩时,requests 会自动为我们解包。我们可以用 Response.content 来获得以字节形式返回的相应内容。
     
    import requests
     
    cs_url = 'http://www.zhihu.com'
    r = requests.get (cs_url)
     
    if r.status_code == requests.codes.ok:
        print r.content
     
    这相当于 urllib2.urlopen(url).read()。
     
    如果相应内容不是文本,而是二进制数据(比如图片),那么上述打印结果可能会糊你一脸。这里以图片为例,示例一下该怎么办。
     
    import requests
    from PIL import Image
    from StringIO import StringIO
     
    cs_url = 'http://liam0205.me/uploads/avatar/avatar-2.jpg'
    r = requests.get (cs_url)
     
    if r.status_code == requests.codes.ok:
        Image.open(StringIO(r.content)).show()
     
    运行无误的话,能看到我和我爱人的照片。
     
    文本模式 / 编码
     
    如果响应返回是文本,那么你可以用 Response.text 获得 Unicode 编码的响应返回内容。
     
    import requests
     
    cs_url = 'http://www.zhihu.com'
    r = requests.get (cs_url)
     
    if r.status_code == requests.codes.ok:
        print r.text
     
    要获得 Unicode 编码的结果,意味着 requests 会为我们做解码工作。那么 requests 是按照何种编码去对返回结果解码的呢?
     
    requests 会读取 HTTP header 中关于字符集的内容。如果获取成功,则会依此进行解码;若不然,则会根据响应内容对编码进行猜测。具体来说,我们可以用 Response.encoding 来查看/修改使用的编码。
     
    import requests
     
    cs_url = 'http://www.zhihu.com'
    r = requests.get (cs_url)
     
    if r.status_code == requests.codes.ok:
        print r.encoding
     
    反序列化 JSON 数据
     
    开篇给出的第一个 requests 示例中,特别吸引人的一点就是 requests 无需任何其他库,就能解析序列化为 JSON 格式的数据。
     
    我们以 IP 查询 Google 公共 DNS 为例:
     
    import requests
     
    cs_url   = 'http://ip.taobao.com/service/getIpInfo.php'
    my_param = {'ip':'8.8.8.8'}
     
    r = requests.get(cs_url, params = my_param)
     
    print r.json()['data']['country'].encode('utf-8')
     
    结果将输出:
     
    美国
     
    模拟登录 GitHub 看看
     
    Cookie 介绍
     
    HTTP 协议是无状态的。因此,若不借助其他手段,远程的服务器就无法知道以前和客户端做了哪些通信。Cookie 就是「其他手段」之一。
     
    Cookie 一个典型的应用场景,就是用于记录用户在网站上的登录状态。
     
        用户登录成功后,服务器下发一个(通常是加密了的)Cookie 文件。
        客户端(通常是网页浏览器)将收到的 Cookie 文件保存起来。
        下次客户端与服务器连接时,将 Cookie 文件发送给服务器,由服务器校验其含义,恢复登录状态(从而避免再次登录)。

    Cookie 在 requests 中
     
    Cookie? 你说的是小甜点吧!
     
    别忘了,requests 是给人类设计的 Python 库。想想使用浏览器浏览网页的时候,我们没有手工去保存、重新发送 Cookie 对吗?浏览器都为我们自动完成了。
     
    在 requests 中,也是这样。
     
    当浏览器作为客户端与远端服务器连接时,远端服务器会根据需要,产生一个 SessionID,并附在 Cookie 中发给浏览器。接下来的时间里,只要 Cookie 不过期,浏览器与远端服务器的连接,都会使用这个 SessionID;而浏览器会自动与服务器协作,维护相应的 Cookie。
     
    在 requests 中,也是这样。我们可以创建一个 requests.Session,尔后在该 Session 中与远端服务器通信,其中产生的 Cookie,requests 会自动为我们维护好。
     
    POST 表单
     
    POST 方法可以将一组用户数据,以表单的形式发送到远端服务器。远端服务器接受后,依照表单内容做相应的动作。
     
    调用 requests 的 POST 方法时,可以用 data 参数接收一个 Python 字典结构。requests 会自动将 Python 字典序列化为实际的表单内容。例如:
     
    import requests
     
    cs_url    = 'http://httpbin.org/post'
    my_data   = {
        'key1' : 'value1',
        'key2' : 'value2'
    }
     
    r = requests.post (cs_url, data = my_data)
    print r.content
    返回:
     
    {
      ...
      "form": {
        "key1": "value1",
        "key2": "value2"
      },
      ...
    }
    实际模拟登录 GitHub 试试看
     
    模拟登录的第一步,首先是要搞清楚我们用浏览器登录时都发生了什么。
     
    GitHub 登录页面是 https://github.com/login。我们首先清空浏览器 Cookie 记录,然后用 Chrome 打开登录页面。
     
    填入 Username 和 Password 之后,我们打开 Tamper Chrome 和 Chrome 的元素审查工具(找到 Network 标签页),之后点登录按钮。
     
    在 Tamper Chrome 中,我们发现:虽然登录页面是 https://github.com/login,但实际接收表单的是 https://github.com/session。若登录成功,则跳转到 https://github.com/ 广东南粤风采36选7走势图,返回状态码 200。


     
    而在 Chrome 的审查元素窗口中,我们可以看到提交给 session 接口的表单信息。内里包含
     
        commit
        utf8
        authenticity_token
        login
        password



     
    其中,commit 和 utf8 两项是定值;login 和 password 分别是用户名和密码,这很好理解。唯独 authenticity_token 是一长串无规律的字符,我们不清楚它是什么。
     
    POST 动作发生在与 session 接口交互之前,因此可能的信息来源只有 login 接口。我们打开 login 页面的源码,试着搜索 authenticity_token 就不难发现有如下内容:
     
    <input name="authenticity_token" type="hidden" value="......" />
     
    原来,所谓的 authenticity_token 是明白卸载 HTML 页面里的,只不过用 hidden 模式隐藏起来了。为此,我们只需要使用 Python 的正则库解析一下,就好了。
     
    这样一来,事情就变得简单起来,编码吧!
     
    模拟登录 GitHub
     
    import requests
    import re
     
    cs_url  = 'https://github.com/login'
    cs_user = 'user'
    cs_psw  = 'psw'
    my_headers = {
        'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36',
        'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Encoding' : 'gzip',
        'Accept-Language' : 'zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4'
    }
    sss     = requests.Session()
    r       = sss.get(cs_url, headers = my_headers)
    reg     = r'<input name="authenticity_token" type="hidden" value="(.*)" />'
    pattern = re.compile(reg)
    result  = pattern.findall(r.content)
    token   = result[0]
    my_data = {
        'commit' : 'Sign in',
        'utf8' : '%E2%9C%93',
        'authenticity_token' : token,
        'login' : cs_user,
        'password' : cs_psw
    }
    cs_url  = 'https://github.com/session'
    r       = sss.post(cs_url, headers = my_headers, data = my_data)
    print r.url, r.status_code, r.history
    输出:
     
    https://github.com/ 200 [<Response [302]>]
    代码很好理解,其实只是完全地模拟了浏览器的行为。
     
    首先,我们准备好了和 Chrome 一致的 HTTP 请求头部信息。具体来说,其中的 User-Agent 是比较重要的。而后,仿照浏览器与服务器的通信,我们创建了一个 requests.Session。接着,我们用 GET 方法打开登录页面,并用正则库解析到 authenticity_token。随后,将所需的数据,整备成一个 Python 字典备用。最后,我们用 POST 方法,将表单提交到 session 接口。
     
    最终的结果也是符合预期的:经由 302 跳转,打开了(200)GitHub 广东南粤风采36选7走势图。
     

延伸阅读:

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规
福彩双色球双期走势图南粤风采26选5走势图体彩排列3和值遗漏福彩双色球201走势图河南福彩22选5大小走势图体彩排列3和值走势图体彩排列3历史开奖号码辽宁福彩35选7走势图辽宁福彩35选7走势图广东南粤风采36选7走势图浙江体彩6 1号码分布河南福彩22选5复式计算表浙江体彩6 1历史开奖号码体彩超级大乐透周一走势图双色球开奖信息体彩排列5和值走势图排列三和值走势图浙江体彩6 1走势图体彩22选5走势图辽宁福彩35选7重号分布图江苏体彩七位数201分析