mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-08 15:04:05 +08:00
396 lines
46 KiB
HTML
396 lines
46 KiB
HTML
<div class="body" role="main">
|
||
|
||
<div class="section" id="module-requests.models">
|
||
<div class="section" id="id2">
|
||
<h2>发送请求</h2>
|
||
<p>使用 Requests 发送网络请求非常简单。</p>
|
||
<p>一开始要导入 Requests 模块:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">requests</span>
|
||
</code></pre>
|
||
<p>然后,尝试获取某个网页。本例子中,我们来获取 Github 的公共时间线:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'https://api.github.com/events'</span><span class="p">)</span>
|
||
</code></pre>
|
||
<p>现在,我们有一个名为 <code class="docutils literal"><span class="pre">r</span></code> 的 <a class="reference internal" href="../api.html#requests.Response" title="requests.Response"><code class="xref py py-class docutils literal"><span class="pre">Response</span></code></a>
|
||
对象。我们可以从这个对象中获取所有我们想要的信息。</p>
|
||
<p>Requests 简便的 API 意味着所有 HTTP 请求类型都是显而易见的。例如,你可以这样发送一个
|
||
HTTP POST 请求:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s1">'http://httpbin.org/post'</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'key'</span><span class="p">:</span><span class="s1">'value'</span><span class="p">})</span>
|
||
</code></pre>
|
||
<p>漂亮,对吧?那么其他 HTTP 请求类型:PUT,DELETE,HEAD 以及 OPTIONS 又是如何的呢?都是一样的简单:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="s1">'http://httpbin.org/put'</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'key'</span><span class="p">:</span><span class="s1">'value'</span><span class="p">})</span>
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="s1">'http://httpbin.org/delete'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="s1">'http://httpbin.org/get'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">options</span><span class="p">(</span><span class="s1">'http://httpbin.org/get'</span><span class="p">)</span>
|
||
</code></pre>
|
||
<p>都很不错吧,但这也仅是 Requests 的冰山一角呢。</p>
|
||
</div>
|
||
<div class="section" id="url">
|
||
<h2>传递 URL 参数</h2>
|
||
<p>你也许经常想为 URL 的查询字符串(query string)传递某种数据。如果你是手工构建 URL,那么数据会以键/值对的形式置于 URL 中,跟在一个问号的后面。例如, <code class="docutils literal"><span class="pre">httpbin.org/get?key=val</span></code>。
|
||
Requests 允许你使用 <code class="docutils literal"><span class="pre">params</span></code> 关键字参数,以一个字符串字典来提供这些参数。举例来说,如果你想传递
|
||
<code class="docutils literal"><span class="pre">key1=value1</span></code> 和 <code class="docutils literal"><span class="pre">key2=value2</span></code> 到 <code class="docutils literal"><span class="pre">httpbin.org/get</span></code> ,那么你可以使用如下代码:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">payload</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'key1'</span><span class="p">:</span> <span class="s1">'value1'</span><span class="p">,</span> <span class="s1">'key2'</span><span class="p">:</span> <span class="s1">'value2'</span><span class="p">}</span>
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"http://httpbin.org/get"</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="n">payload</span><span class="p">)</span>
|
||
</code></pre>
|
||
<p>通过打印输出该 URL,你能看到 URL 已被正确编码:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
|
||
<span class="go">http://httpbin.org/get?key2=value2&key1=value1</span>
|
||
</code></pre>
|
||
<p>注意字典里值为 <code class="docutils literal"><span class="pre">None</span></code> 的键都不会被添加到 URL 的查询字符串里。</p>
|
||
<p>你还可以将一个列表作为值传入:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">payload</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'key1'</span><span class="p">:</span> <span class="s1">'value1'</span><span class="p">,</span> <span class="s1">'key2'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'value2'</span><span class="p">,</span> <span class="s1">'value3'</span><span class="p">]}</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'http://httpbin.org/get'</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="n">payload</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
|
||
<span class="go">http://httpbin.org/get?key1=value1&key2=value2&key2=value3</span>
|
||
</code></pre>
|
||
</div>
|
||
<div class="section" id="id3">
|
||
<h2>响应内容</h2>
|
||
<p>我们能读取服务器响应的内容。再次以 GitHub 时间线为例:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">requests</span>
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'https://api.github.com/events'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">text</span>
|
||
<span class="go">u'[{"repository":{"open_issues":0,"url":"https://github.com/...</span>
|
||
</code></pre>
|
||
<p>Requests 会自动解码来自服务器的内容。大多数 unicode 字符集都能被无缝地解码。</p>
|
||
<p>请求发出后,Requests 会基于 HTTP 头部对响应的编码作出有根据的推测。当你访问 <code class="docutils literal"><span class="pre">r.text</span></code>
|
||
之时,Requests 会使用其推测的文本编码。你可以找出 Requests 使用了什么编码,并且能够使用
|
||
<code class="docutils literal"><span class="pre">r.encoding</span></code> 属性来改变它:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">encoding</span>
|
||
<span class="go">'utf-8'</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">encoding</span> <span class="o">=</span> <span class="s1">'ISO-8859-1'</span>
|
||
</code></pre>
|
||
<p>如果你改变了编码,每当你访问 <code class="docutils literal"><span class="pre">r.text</span></code> ,Request 都将会使用 <code class="docutils literal"><span class="pre">r.encoding</span></code>
|
||
的新值。你可能希望在使用特殊逻辑计算出文本的编码的情况下来修改编码。比如 HTTP 和 XML
|
||
自身可以指定编码。这样的话,你应该使用 <code class="docutils literal"><span class="pre">r.content</span></code> 来找到编码,然后设置 <code class="docutils literal"><span class="pre">r.encoding</span></code>
|
||
为相应的编码。这样就能使用正确的编码解析 <code class="docutils literal"><span class="pre">r.text</span></code> 了。</p>
|
||
<p>在你需要的情况下,Requests 也可以使用定制的编码。如果你创建了自己的编码,并使用
|
||
<code class="docutils literal"><span class="pre">codecs</span></code> 模块进行注册,你就可以轻松地使用这个解码器名称作为 <code class="docutils literal"><span class="pre">r.encoding</span></code> 的值,
|
||
然后由 Requests 来为你处理编码。</p>
|
||
</div>
|
||
<div class="section" id="id4">
|
||
<h2>二进制响应内容</h2>
|
||
<p>你也能以字节的方式访问请求响应体,对于非文本请求:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">content</span>
|
||
<span class="go">b'[{"repository":{"open_issues":0,"url":"https://github.com/...</span>
|
||
</code></pre>
|
||
<p>Requests 会自动为你解码 <code class="docutils literal"><span class="pre">gzip</span></code> 和 <code class="docutils literal"><span class="pre">deflate</span></code> 传输编码的响应数据。</p>
|
||
<p>例如,以请求返回的二进制数据创建一张图片,你可以使用如下代码:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">PIL</span> <span class="k">import</span> <span class="n">Image</span>
|
||
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">io</span> <span class="k">import</span> <span class="n">BytesIO</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">i</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">content</span><span class="p">))</span>
|
||
</code></pre>
|
||
</div>
|
||
<div class="section" id="json">
|
||
<h2>JSON 响应内容</h2>
|
||
<p>Requests 中也有一个内置的 JSON 解码器,助你处理 JSON 数据:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">requests</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'https://api.github.com/events'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
|
||
<span class="go">[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...</span>
|
||
</code></pre>
|
||
<p>如果 JSON 解码失败, <code class="docutils literal"><span class="pre">r.json()</span></code> 就会抛出一个异常。例如,响应内容是 401 (Unauthorized),尝试访问 <code class="docutils literal"><span class="pre">r.json()</span></code> 将会抛出 <code class="docutils literal"><span class="pre">ValueError:</span> <span class="pre">No</span> <span class="pre">JSON</span> <span class="pre">object</span> <span class="pre">could</span> <span class="pre">be</span> <span class="pre">decoded</span></code> 异常。</p>
|
||
<p>需要注意的是,成功调用 <code class="docutils literal"><span class="pre">r.json()</span></code> 并**不**意味着响应的成功。有的服务器会在失败的响应中包含一个 JSON 对象(比如 HTTP 500 的错误细节)。这种 JSON 会被解码返回。要检查请求是否成功,请使用 <code class="docutils literal"><span class="pre">r.raise_for_status()</span></code> 或者检查 <code class="docutils literal"><span class="pre">r.status_code</span></code> 是否和你的期望相同。</p>
|
||
</div>
|
||
<div class="section" id="id5">
|
||
<h2>原始响应内容</h2>
|
||
<p>在罕见的情况下,你可能想获取来自服务器的原始套接字响应,那么你可以访问 <code class="docutils literal"><span class="pre">r.raw</span></code>。
|
||
如果你确实想这么干,那请你确保在初始请求中设置了 <code class="docutils literal"><span class="pre">stream=True</span></code>。具体你可以这么做:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'https://api.github.com/events'</span><span class="p">,</span> <span class="n">stream</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">raw</span>
|
||
<span class="go"><requests.packages.urllib3.response.HTTPResponse object at 0x101194810></span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">raw</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
|
||
<span class="go">'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'</span>
|
||
</code></pre>
|
||
<p>但一般情况下,你应该以下面的模式将文本流保存到文件:</p>
|
||
<pre><code class="language-python"><span></span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fd</span><span class="p">:</span>
|
||
<span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">r</span><span class="o">.</span><span class="n">iter_content</span><span class="p">(</span><span class="n">chunk_size</span><span class="p">):</span>
|
||
<span class="n">fd</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">chunk</span><span class="p">)</span>
|
||
</code></pre>
|
||
<p>使用 <code class="docutils literal"><span class="pre">Response.iter_content</span></code> 将会处理大量你直接使用 <code class="docutils literal"><span class="pre">Response.raw</span></code> 不得不处理的。
|
||
当流下载时,上面是优先推荐的获取内容方式。 Note that <code class="docutils literal"><span class="pre">chunk_size</span></code> can be freely adjusted to a number that
|
||
may better fit your use cases.</p>
|
||
</div>
|
||
<div class="section" id="id6">
|
||
<h2>定制请求头</h2>
|
||
<p>如果你想为请求添加 HTTP 头部,只要简单地传递一个 <code class="docutils literal"><span class="pre">dict</span></code> 给 <code class="docutils literal"><span class="pre">headers</span></code> 参数就可以了。</p>
|
||
<p>例如,在前一个示例中我们没有指定 content-type:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'https://api.github.com/some/endpoint'</span>
|
||
<span class="gp">>>> </span><span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'user-agent'</span><span class="p">:</span> <span class="s1">'my-app/0.0.1'</span><span class="p">}</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
|
||
</code></pre>
|
||
<p>注意: 定制 header 的优先级低于某些特定的信息源,例如:</p>
|
||
<ul class="simple">
|
||
<li>如果在 <code class="docutils literal"><span class="pre">.netrc</span></code> 中设置了用户认证信息,使用 <cite>headers=</cite> 设置的授权就不会生效。而如果设置了
|
||
<code class="docutils literal"><span class="pre">auth=</span></code> 参数,``.netrc`` 的设置就无效了。</li>
|
||
<li>如果被重定向到别的主机,授权 header 就会被删除。</li>
|
||
<li>代理授权 header 会被 URL 中提供的代理身份覆盖掉。</li>
|
||
<li>在我们能判断内容长度的情况下,header 的 Content-Length 会被改写。</li>
|
||
</ul>
|
||
<p>更进一步讲,Requests 不会基于定制 header 的具体情况改变自己的行为。只不过在最后的请求中,所有的
|
||
header 信息都会被传递进去。</p>
|
||
<p>注意: 所有的 header 值必须是 <code class="docutils literal"><span class="pre">string</span></code>、bytestring 或者 unicode。尽管传递 unicode
|
||
header 也是允许的,但不建议这样做。</p>
|
||
</div>
|
||
<div class="section" id="post">
|
||
<h2>更加复杂的 POST 请求</h2>
|
||
<p>通常,你想要发送一些编码为表单形式的数据——非常像一个 HTML 表单。要实现这个,只需简单地传递一个字典给 <cite>data</cite> 参数。你的数据字典在发出请求时会自动编码为表单形式:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">payload</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'key1'</span><span class="p">:</span> <span class="s1">'value1'</span><span class="p">,</span> <span class="s1">'key2'</span><span class="p">:</span> <span class="s1">'value2'</span><span class="p">}</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"http://httpbin.org/post"</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">payload</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
|
||
<span class="go">{</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go"> "form": {</span>
|
||
<span class="go"> "key2": "value2",</span>
|
||
<span class="go"> "key1": "value1"</span>
|
||
<span class="go"> },</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go">}</span>
|
||
</code></pre>
|
||
<p>你还可以为 <code class="docutils literal"><span class="pre">data</span></code> 参数传入一个元组列表。在表单中多个元素使用同一 key 的时候,这种方式尤其有效:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">payload</span> <span class="o">=</span> <span class="p">((</span><span class="s1">'key1'</span><span class="p">,</span> <span class="s1">'value1'</span><span class="p">),</span> <span class="p">(</span><span class="s1">'key1'</span><span class="p">,</span> <span class="s1">'value2'</span><span class="p">))</span>
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s1">'http://httpbin.org/post'</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">payload</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
|
||
<span class="go">{</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go"> "form": {</span>
|
||
<span class="go"> "key1": [</span>
|
||
<span class="go"> "value1",</span>
|
||
<span class="go"> "value2"</span>
|
||
<span class="go"> ]</span>
|
||
<span class="go"> },</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go">}</span>
|
||
</code></pre>
|
||
<p>很多时候你想要发送的数据并非编码为表单形式的。如果你传递一个 <code class="docutils literal"><span class="pre">string</span></code> 而不是一个 <code class="docutils literal"><span class="pre">dict</span></code>,那么数据会被直接发布出去。</p>
|
||
<p>例如,Github API v3 接受编码为 JSON 的 POST/PATCH 数据:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">json</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'https://api.github.com/some/endpoint'</span>
|
||
<span class="gp">>>> </span><span class="n">payload</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'some'</span><span class="p">:</span> <span class="s1">'data'</span><span class="p">}</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">payload</span><span class="p">))</span>
|
||
</code></pre>
|
||
<p>此处除了可以自行对 <code class="docutils literal"><span class="pre">dict</span></code> 进行编码,你还可以使用 <code class="docutils literal"><span class="pre">json</span></code> 参数直接传递,然后它就会被自动编码。这是 2.4.2 版的新加功能:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'https://api.github.com/some/endpoint'</span>
|
||
<span class="gp">>>> </span><span class="n">payload</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'some'</span><span class="p">:</span> <span class="s1">'data'</span><span class="p">}</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">json</span><span class="o">=</span><span class="n">payload</span><span class="p">)</span>
|
||
</code></pre>
|
||
</div>
|
||
<div class="section" id="post-multipart-encoded">
|
||
<h2>POST一个多部分编码(Multipart-Encoded)的文件</h2>
|
||
<p>Requests 使得上传多部分编码文件变得很简单:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'http://httpbin.org/post'</span>
|
||
<span class="gp">>>> </span><span class="n">files</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'file'</span><span class="p">:</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'report.xls'</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)}</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">files</span><span class="o">=</span><span class="n">files</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">text</span>
|
||
<span class="go">{</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go"> "files": {</span>
|
||
<span class="go"> "file": "<censored...binary...data>"</span>
|
||
<span class="go"> },</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go">}</span>
|
||
</code></pre>
|
||
<p>你可以显式地设置文件名,文件类型和请求头:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'http://httpbin.org/post'</span>
|
||
<span class="gp">>>> </span><span class="n">files</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'file'</span><span class="p">:</span> <span class="p">(</span><span class="s1">'report.xls'</span><span class="p">,</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'report.xls'</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">),</span> <span class="s1">'application/vnd.ms-excel'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'Expires'</span><span class="p">:</span> <span class="s1">'0'</span><span class="p">})}</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">files</span><span class="o">=</span><span class="n">files</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">text</span>
|
||
<span class="go">{</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go"> "files": {</span>
|
||
<span class="go"> "file": "<censored...binary...data>"</span>
|
||
<span class="go"> },</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go">}</span>
|
||
</code></pre>
|
||
<p>如果你想,你也可以发送作为文件来接收的字符串:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'http://httpbin.org/post'</span>
|
||
<span class="gp">>>> </span><span class="n">files</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'file'</span><span class="p">:</span> <span class="p">(</span><span class="s1">'report.csv'</span><span class="p">,</span> <span class="s1">'some,data,to,send</span><span class="se">\n</span><span class="s1">another,row,to,send</span><span class="se">\n</span><span class="s1">'</span><span class="p">)}</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">files</span><span class="o">=</span><span class="n">files</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">text</span>
|
||
<span class="go">{</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go"> "files": {</span>
|
||
<span class="go"> "file": "some,data,to,send\\nanother,row,to,send\\n"</span>
|
||
<span class="go"> },</span>
|
||
<span class="go"> ...</span>
|
||
<span class="go">}</span>
|
||
</code></pre>
|
||
<p>如果你发送一个非常大的文件作为 <code class="docutils literal"><span class="pre">multipart/form-data</span></code> 请求,你可能希望将请求做成数据流。默认下 <code class="docutils literal"><span class="pre">requests</span></code> 不支持, 但有个第三方包 <code class="docutils literal"><span class="pre">requests-toolbelt</span></code> 是支持的。你可以阅读
|
||
<a class="reference external" href="https://toolbelt.rtfd.org">toolbelt 文档</a> 来了解使用方法。</p>
|
||
<p>在一个请求中发送多文件参考 <a class="reference internal" href="advanced.html#advanced"><span class="std std-ref">高级用法</span></a> 一节。</p>
|
||
<div class="admonition- admonition">
|
||
<p class="first admonition-title">警告</p>
|
||
<p class="last">我们强烈建议你用二进制模式(<a class="reference external" href="https://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files">binary mode</a>)打开文件。这是因为 Requests 可能会试图为你提供
|
||
<code class="docutils literal"><span class="pre">Content-Length</span></code> header,在它这样做的时候,这个值会被设为文件的字节数(<em>bytes</em>)。如果用文本模式(text mode)打开文件,就可能会发生错误。</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="id7">
|
||
<h2>响应状态码</h2>
|
||
<p>我们可以检测响应状态码:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'http://httpbin.org/get'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">status_code</span>
|
||
<span class="go">200</span>
|
||
</code></pre>
|
||
<p>为方便引用,Requests还附带了一个内置的状态码查询对象:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="n">requests</span><span class="o">.</span><span class="n">codes</span><span class="o">.</span><span class="n">ok</span>
|
||
<span class="go">True</span>
|
||
</code></pre>
|
||
<p>如果发送了一个错误请求(一个 4XX 客户端错误,或者 5XX 服务器错误响应),我们可以通过
|
||
<a class="reference internal" href="../api.html#requests.Response.raise_for_status" title="requests.Response.raise_for_status"><code class="xref py py-meth docutils literal"><span class="pre">Response.raise_for_status()</span></code></a>
|
||
来抛出异常:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">bad_r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'http://httpbin.org/status/404'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">bad_r</span><span class="o">.</span><span class="n">status_code</span>
|
||
<span class="go">404</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">bad_r</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
File <span class="nb">"requests/models.py"</span>, line <span class="m">832</span>, in <span class="n">raise_for_status</span>
|
||
<span class="k">raise</span> <span class="n">http_error</span>
|
||
<span class="gr">requests.exceptions.HTTPError</span>: <span class="n">404 Client Error</span>
|
||
</code></pre>
|
||
<p>但是,由于我们的例子中 <code class="docutils literal"><span class="pre">r</span></code> 的 <code class="docutils literal"><span class="pre">status_code</span></code> 是 <code class="docutils literal"><span class="pre">200</span></code> ,当我们调用
|
||
<code class="docutils literal"><span class="pre">raise_for_status()</span></code> 时,得到的是:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
|
||
<span class="go">None</span>
|
||
</code></pre>
|
||
<p>一切都挺和谐哈。</p>
|
||
</div>
|
||
<div class="section" id="id8">
|
||
<h2>响应头</h2>
|
||
<p>我们可以查看以一个 Python 字典形式展示的服务器响应头:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">headers</span>
|
||
<span class="go">{</span>
|
||
<span class="go"> 'content-encoding': 'gzip',</span>
|
||
<span class="go"> 'transfer-encoding': 'chunked',</span>
|
||
<span class="go"> 'connection': 'close',</span>
|
||
<span class="go"> 'server': 'nginx/1.0.4',</span>
|
||
<span class="go"> 'x-runtime': '148ms',</span>
|
||
<span class="go"> 'etag': '"e1ca502697e5c9317743dc078f67693f"',</span>
|
||
<span class="go"> 'content-type': 'application/json'</span>
|
||
<span class="go">}</span>
|
||
</code></pre>
|
||
<p>但是这个字典比较特殊:它是仅为 HTTP 头部而生的。根据
|
||
<a class="reference external" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">RFC 2616</a>,
|
||
HTTP 头部是大小写不敏感的。</p>
|
||
<p>因此,我们可以使用任意大写形式来访问这些响应头字段:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">headers</span><span class="p">[</span><span class="s1">'Content-Type'</span><span class="p">]</span>
|
||
<span class="go">'application/json'</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'content-type'</span><span class="p">)</span>
|
||
<span class="go">'application/json'</span>
|
||
</code></pre>
|
||
<p>它还有一个特殊点,那就是服务器可以多次接受同一 header,每次都使用不同的值。但 Requests
|
||
会将它们合并,这样它们就可以用一个映射来表示出来,参见
|
||
<a class="reference external" href="http://tools.ietf.org/html/rfc7230#section-3.2">RFC 7230</a>:</p>
|
||
<blockquote>
|
||
<div><p>A recipient MAY combine multiple header fields with the same field name
|
||
into one "field-name: field-value" pair, without changing the semantics
|
||
of the message, by appending each subsequent field value to the combined
|
||
field value in order, separated by a comma.</p>
|
||
<p>接收者可以合并多个相同名称的 header 栏位,把它们合为一个 "field-name: field-value"
|
||
配对,将每个后续的栏位值依次追加到合并的栏位值中,用逗号隔开即可,这样做不会改变信息的语义。</p>
|
||
</div></blockquote>
|
||
</div>
|
||
<div class="section" id="cookie">
|
||
<h2>Cookie</h2>
|
||
<p>如果某个响应中包含一些 cookie,你可以快速访问它们:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'http://example.com/some/cookie/setting/url'</span>
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">cookies</span><span class="p">[</span><span class="s1">'example_cookie_name'</span><span class="p">]</span>
|
||
<span class="go">'example_cookie_value'</span>
|
||
</code></pre>
|
||
<p>要想发送你的cookies到服务器,可以使用 <code class="docutils literal"><span class="pre">cookies</span></code> 参数:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'http://httpbin.org/cookies'</span>
|
||
<span class="gp">>>> </span><span class="n">cookies</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">cookies_are</span><span class="o">=</span><span class="s1">'working'</span><span class="p">)</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">cookies</span><span class="o">=</span><span class="n">cookies</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">text</span>
|
||
<span class="go">'{"cookies": {"cookies_are": "working"}}'</span>
|
||
</code></pre>
|
||
<p>Cookie 的返回对象为 <a class="reference internal" href="../api.html#requests.cookies.RequestsCookieJar" title="requests.cookies.RequestsCookieJar"><code class="xref py py-class docutils literal"><span class="pre">RequestsCookieJar</span></code></a>,它的行为和字典类似,但接口更为完整,适合跨域名跨路径使用。你还可以把 Cookie Jar 传到 Requests 中:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">jar</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">RequestsCookieJar</span><span class="p">()</span>
|
||
<span class="gp">>>> </span><span class="n">jar</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s1">'tasty_cookie'</span><span class="p">,</span> <span class="s1">'yum'</span><span class="p">,</span> <span class="n">domain</span><span class="o">=</span><span class="s1">'httpbin.org'</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="s1">'/cookies'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">jar</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s1">'gross_cookie'</span><span class="p">,</span> <span class="s1">'blech'</span><span class="p">,</span> <span class="n">domain</span><span class="o">=</span><span class="s1">'httpbin.org'</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="s1">'/elsewhere'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'http://httpbin.org/cookies'</span>
|
||
<span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">cookies</span><span class="o">=</span><span class="n">jar</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">text</span>
|
||
<span class="go">'{"cookies": {"tasty_cookie": "yum"}}'</span>
|
||
</code></pre>
|
||
</div>
|
||
<div class="section" id="id9">
|
||
<h2>重定向与请求历史</h2>
|
||
<p>默认情况下,除了 HEAD, Requests 会自动处理所有重定向。</p>
|
||
<p>可以使用响应对象的 <code class="docutils literal"><span class="pre">history</span></code> 方法来追踪重定向。</p>
|
||
<p><a class="reference internal" href="../api.html#requests.Response.history" title="requests.Response.history"><code class="xref py py-attr docutils literal"><span class="pre">Response.history</span></code></a> 是一个
|
||
<a class="reference internal" href="../api.html#requests.Response" title="requests.Response"><code class="xref py py-class docutils literal"><span class="pre">Response</span></code></a> 对象的列表,为了完成请求而创建了这些对象。这个对象列表按照从最老到最近的请求进行排序。</p>
|
||
<p>例如,Github 将所有的 HTTP 请求重定向到 HTTPS:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'http://github.com'</span><span class="p">)</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">url</span>
|
||
<span class="go">'https://github.com/'</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">status_code</span>
|
||
<span class="go">200</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">history</span>
|
||
<span class="go">[<Response [301]>]</span>
|
||
</code></pre>
|
||
<p>如果你使用的是GET、OPTIONS、POST、PUT、PATCH 或者 DELETE,那么你可以通过 <code class="docutils literal"><span class="pre">allow_redirects</span></code>
|
||
参数禁用重定向处理:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'http://github.com'</span><span class="p">,</span> <span class="n">allow_redirects</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">status_code</span>
|
||
<span class="go">301</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">history</span>
|
||
<span class="go">[]</span>
|
||
</code></pre>
|
||
<p>如果你使用了 HEAD,你也可以启用重定向:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="s1">'http://github.com'</span><span class="p">,</span> <span class="n">allow_redirects</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">url</span>
|
||
<span class="go">'https://github.com/'</span>
|
||
<span class="gp">>>> </span><span class="n">r</span><span class="o">.</span><span class="n">history</span>
|
||
<span class="go">[<Response [301]>]</span>
|
||
</code></pre>
|
||
</div>
|
||
<div class="section" id="id10">
|
||
<h2>超时</h2>
|
||
<p>你可以告诉 requests 在经过以 <code class="docutils literal"><span class="pre">timeout</span></code> 参数设定的秒数时间之后停止等待响应。基本上所有的生产代码都应该使用这一参数。如果不使用,你的程序可能会永远失去响应:</p>
|
||
<pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'http://github.com'</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mf">0.001</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
|
||
<span class="gr">requests.exceptions.Timeout</span>: <span class="n">HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)</span>
|
||
</code></pre>
|
||
<div class="admonition- admonition">
|
||
<p class="first admonition-title">注意</p>
|
||
<p class="last"><code class="docutils literal"><span class="pre">timeout</span></code> 仅对连接过程有效,与响应体的下载无关。 <code class="docutils literal"><span class="pre">timeout</span></code> 并不是整个下载响应的时间限制,而是如果服务器在 <code class="docutils literal"><span class="pre">timeout</span></code> 秒内没有应答,将会引发一个异常(更精确地说,是在
|
||
<code class="docutils literal"><span class="pre">timeout</span></code> 秒内没有从基础套接字上接收到任何字节的数据时)If no timeout is specified explicitly, requests do
|
||
not time out.</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="id11">
|
||
<h2>错误与异常</h2>
|
||
<p>遇到网络问题(如:DNS 查询失败、拒绝连接等)时,Requests 会抛出一个
|
||
<code class="xref py py-exc docutils literal"><span class="pre">ConnectionError</span></code> 异常。</p>
|
||
<p>如果 HTTP 请求返回了不成功的状态码, <a class="reference internal" href="../api.html#requests.Response.raise_for_status" title="requests.Response.raise_for_status"><code class="xref py py-meth docutils literal"><span class="pre">Response.raise_for_status()</span></code></a>
|
||
会抛出一个 <code class="xref py py-exc docutils literal"><span class="pre">HTTPError</span></code> 异常。</p>
|
||
<p>若请求超时,则抛出一个 <code class="xref py py-exc docutils literal"><span class="pre">Timeout</span></code> 异常。</p>
|
||
<p>若请求超过了设定的最大重定向次数,则会抛出一个 <code class="xref py py-exc docutils literal"><span class="pre">TooManyRedirects</span></code> 异常。</p>
|
||
<p>所有Requests显式抛出的异常都继承自 <code class="xref py py-exc docutils literal"><span class="pre">requests.exceptions.RequestException</span></code> 。</p>
|
||
<hr class="docutils">
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div id="rtd-o510oasz" class="ethical-alabaster"></div></div> |