4. 高级用法1 —— Requests中文文档

高级用法¶

本篇文档涵盖了 Requests 的一些高级特性。

会话Session对象¶

Session对象允许您跨请求保持某些参数。它还保存会话实例的所有请求的cookies,并将使用urllib3的连接池。因此,如果您向同一主机发出多个请求,底层的TCP连接将被重用,这会导致性能显著提高(请参见HTTP persistent connection)。
会话Session对象具有主要的 Requests API 的所有方法。
我们来跨请求保存一些 cookie:

    s = requests.Session()
    
    s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
    r = s.get('https://httpbin.org/cookies')
    
    print(r.text)
    # '{"cookies": {"sessioncookie": "123456789"}}'
    

会话也可用来为请求方法提供缺省数据。这是通过为会话对象的属性提供数据来实现的:

    s = requests.Session()
    s.auth = ('user', 'pass')
    s.headers.update({'x-test': 'true'})
    
    # both 'x-test' and 'x-test2' are sent
    s.get('https://httpbin.org/headers', headers={'x-test2': 'true'})
    

任何传递给请求方法的字典都会与已设置会话层数据合并。方法层数据覆盖会话的数据。
但请注意,即使使用会话,方法级参数也不会跨请求保持。这个例子只在第一个请求中了包含cookie,而第二个请求没有:

    s = requests.Session()
    
    r = s.get('https://httpbin.org/cookies', cookies={'from-my': 'browser'})
    print(r.text)
    # '{"cookies": {"from-my": "browser"}}'
    
    r = s.get('https://httpbin.org/cookies')
    print(r.text)
    # '{"cookies": {}}'
    

如果你要手动为会话添加 cookie,可以使用 Cookie utility 函数 来操纵 Session.cookies。
会话也可以用作上下文管理器:

    with requests.Session() as s:
        s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')    

这将确保会话在with块退出后立即关闭,即使发生未处理的异常也是如此。

从字典中移除一个值:
有时你会想省略字典参数中一些会话层的键。要做到这一点,你只需简单地在方法层参数中将那个键的值设置为 None ,那个键就会被自动省略掉。

会话中包含的所有值都可以直接使用,更多细节请阅读会话 API 文档

请求和响应对象¶

任何时候进行了类似 requests.get() 的调用,你都主要在做两件事:一,你在构建一个 Request 对象, 该对象将被发送到某个服务器请求或查询一些资源;二,一旦 requests 得到一个从服务器返回的响应就会产生一个 Response 对象该,响应对象包含服务器返回的所有信息,也包含你原来创建的 Request 对象。如下是一个简单的请求,从维基百科服务器获取一些重要信息:

    >>> r = requests.get('https://en.wikipedia.org/wiki/Monty_Python')    

如果我们想访问服务器返回给我们的响应头部信息,我们会这样做:

    >>> r.headers
    {'content-length': '56170', 'x-content-type-options': 'nosniff', 'x-cache':
    'HIT from cp1006.eqiad.wmnet, MISS from cp1010.eqiad.wmnet', 'content-encoding':
    'gzip', 'age': '3080', 'content-language': 'en', 'vary': 'Accept-Encoding,Cookie',
    'server': 'Apache', 'last-modified': 'Wed, 13 Jun 2012 01:33:50 GMT',
    'connection': 'close', 'cache-control': 'private, s-maxage=0, max-age=0,
    must-revalidate', 'date': 'Thu, 14 Jun 2012 12:59:39 GMT', 'content-type':
    'text/html; charset=UTF-8', 'x-cache-lookup': 'HIT from cp1006.eqiad.wmnet:3128,
    MISS from cp1010.eqiad.wmnet:80'}
    

但是,如果我们想获取发送给服务器的请求头部信息,我们可以简单地访问请求,然后访问请求的头部:

    >>> r.request.headers
    {'Accept-Encoding': 'identity, deflate, compress, gzip',
    'Accept': '*/*', 'User-Agent': 'python-requests/1.2.0'}
    

准备的请求 (Prepared Request)¶

当你从 API 或者会话调用中收到一个 Response对象时,request 属性其实是使用了PreparedRequest。有时在发送请求之前,你需要对 body 或者 header (或者别的什么东西)做一些额外处理,下面演示了一个简单的做法:

    from requests import Request, Session
    
    s = Session()
    
    req = Request('POST', url, data=data, headers=headers)
    prepped = req.prepare()
    
    # do something with prepped.body
    prepped.body = 'No, I want exactly this as the body.'
    
    # do something with prepped.headers
    del prepped.headers['Content-Type']
    
    resp = s.send(prepped,
        stream=stream,
        verify=verify,
        proxies=proxies,
        cert=cert,
        timeout=timeout
    )
    
    print(resp.status_code)    

上面代码中,没有对Request对象执行任何特殊操作,只是获取PreparedRequest对象并进行了修改。,然后把它和别的参数一起发送到requests.*或者Session.*
然而,上述代码会失去 RequestsSession 对象的一些优势, 尤其 Session 级别的状态,例如 cookie 就不会被应用到你的请求上去。要获取一个带有状态的 PreparedRequest, 请用 Session.prepare_request()取代 Request.prepare()的调用,如下所示:

    from requests import Request, Session
    
    s = Session()
    req = Request('GET',  url, data=data, headers=headers)
    
    prepped = s.prepare_request(req)
    
    # do something with prepped.body
    prepped.body = 'Seriously, send exactly these bytes.'
    
    # do something with prepped.headers
    prepped.headers['Keep-Dead'] = 'parrot'
    
    resp = s.send(prepped,
        stream=stream,
        verify=verify,
        proxies=proxies,
        cert=cert,
        timeout=timeout
    )
    
    print(resp.status_code)
    

使用准备好的请求流时,请记住,它不考虑环境变量。如果使用环境变量更改请求的行为,这可能会导致问题。例如:将不考虑“请求包”中指定的自签名SSL证书。结果SSL:证书验证失败被抛出。您可以通过将环境设置显式合并到会话中来避免此行为:

    from requests import Request, Session
    
    s = Session()
    req = Request('GET', url)
    
    prepped = s.prepare_request(req)
    
    # Merge environment settings into session
    settings = s.merge_environment_settings(prepped.url, {}, None, None, None)
    resp = s.send(prepped, **settings)
    
    print(resp.status_code)
    

SSL证书验证¶

和Web浏览器一样, Requests库验证HTTPS请求的SSL证书。默认情况下已启用SSL验证,如果无法验证证书,则Requests库将抛出SSLError异常:

    >>> requests.get('https://requestb.in')
    requests.exceptions.SSLError: hostname 'requestb.in' doesn't match either of '*.herokuapp.com', 'herokuapp.com'    

我在这个域上没有SSL设置,所以它抛出一个异常。太好了!不过,GitHub设置了 SSL:

    >>> requests.get('https://github.com')
    <Response [200]>    

您可以为verify传入 CA_BUNDLE 文件的路径,或者包含可信任 CA 证书文件的文件夹路径:

    >>> requests.get('https://github.com', verify='/path/to/certfile')    

或将其保存在会话中:

    s = requests.Session()
    s.verify = '/path/to/certfile'    

注解
如果 verify 设为文件夹路径,文件夹必须通过 OpenSSL 提供的 c_rehash 工具处理。

你还可以通过 REQUESTS_CA_BUNDLE环境变量定义可信任 CA 列表。如果未设置,将使用CURL_CA_BUNDLE作为备用。如果将verify设置为False,则Requests库忽将忽略SSL验证:

    >>> requests.get('https://kennethreitz.org', verify=False)
    <Response [200]>    

注意,verify设置为False时,Requests库将接受服务器提供的任何tls证书,并将忽略HostNameMitches或过期证书,这将使您的应用程序容易受到中间人(MitM)攻击。在本地开发或测试期间,将verify设置为False将很有用。
默认情况下verifyTrue。选项verify仅适用于主机证书。

客户端证书¶

您还可以指定一个本地证书用作客户端证书,可以是单个文件(包含密钥和证书)或一个包含两个文件路径的元组:

    >>> requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))
    <Response [200]>    

或保存在会话中:

    s = requests.Session()
    s.cert = '/path/client.cert'    

如果指定了错误的路径或无效的证书,您将得到一个SSLError异常:

    >>> requests.get('https://kennethreitz.org', cert='/wrong_path/client.pem')
    SSLError: [Errno 336265225] _ssl.c:347: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib    

警告
本地证书的私钥必须为未加密。目前,Requests库不支持使用加密密钥。

CA证书¶

Requests库使用包certifi中的证书,允许用户在不更改Requests版本的情况下更新受信任的证书。
在2.16版本之前,Requests绑定了一组它信任的根CA,这些CA来自Mozilla信任存储库。对于每个Requests版本,证书仅更新一次。当没有安装certifi时,使用老版本的Requests导致证书包非常过时。为了安全起见,我们建议经常升级certifi包!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个比较复杂的任务,需要用到爬虫和数据处理的知识。我将给你提供一个基本的思路: 1. 发送 HTTP 请求获取京东图书销量榜的网页源代码。 2. 使用正则表达式从源代码中提取书名、作者、定价、折扣和售价等信息。 3. 将提取的信息存储到一个数据结构中,比如列表或字典。 4. 使用 Python 中的 pandas 库将数据结构转化为 DataFrame 对象。 5. 将 DataFrame 对象保存为 Excel 文件,可以使用 pandas 的 to_excel() 方法。 下面是一个示例代码供你参考: ```python import requests import re import pandas as pd # 发送 HTTP 请求获取京东图书销量榜的网页源代码 url = 'https://book.jd.com/booktop/0-0-0.html' response = requests.get(url) html = response.text # 使用正则表达式从源代码中提取书名、作者、定价、折扣和售价等信息 pattern = r'<div class="p-name">.*?(.*?).*?<a href=".*?" title="(.*?)".*?</a>.*?<div class="p-bookdetails">.*?<span class="price">(.*?)</span>.*?<div class="p-commit">.*?<strong>(.*?)</strong>.*?<span class="sep">¥</span><strong class="J_price">(.*?)</strong>' items = re.findall(pattern, html, re.S) # 将提取的信息存储到一个数据结构中,比如列表或字典 data = [] for item in items: bookName, author, definePrice, discount, sellPrice = item data.append({ '书名': bookName.strip(), '作者': author.strip(), '定价': definePrice.strip(), '折扣': discount.strip(), '售价': sellPrice.strip() }) # 使用 Python 中的 pandas 库将数据结构转化为 DataFrame 对象 df = pd.DataFrame(data) # 将 DataFrame 对象保存为 Excel 文件 df.to_excel('京东图书销量榜.xlsx', index=False) ``` 注意,这个示例代码只是一个基本的框架,你可能需要根据实际情况进行一些修改和优化。另外,爬取网页数据需要注意法律法规和伦理道德,不要进行非法或有害的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值