首页 > 其他分享 >一步一步学爬虫(2)基本库的使用之requests

一步一步学爬虫(2)基本库的使用之requests

时间:2023-01-05 14:05:28浏览次数:31  
标签:httpbin get 一步 爬虫 https print import requests

(一步一步学爬虫(2)基本库的使用之requests)

2.2 requests的使用

2.2.1 准备工作

  • requests库的安装 pip3 install requests

2.2.2 实例引入

import requests

r = requests.get('https://www.baidu.com')
print(type(r))
print(r.status_code)
print(type(r.text))
print(r.text[:100])
print(r.cookies)
  • 运行结果如下:
<class 'requests.models.Response'>
200
<class 'str'>
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charse
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
  • 这里调用了get方法实现了与urlopen方法相同的操作,返回一个Response对象,并将其存放在变量r中,然后,分别输出了响应的类型、状态码,响应体的类型、内容、以及cookie。

2.2.3 get请求

基本实例

import requests

r = requests.get('https://www.httpbin.org/get')
print(r.text)
  • 运行结果为:
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Host": "www.httpbin.org",
    "User-Agent": "python-requests/2.28.1",
    "X-Amzn-Trace-Id": "Root=1-63a6d04f-03ed36847c320a0f32b96d81"
  },
  "origin": "39.69.199.58",
  "url": "https://www.httpbin.org/get"
}
  • 以上结果包含请求头、IP、URL等信息。
  • 额外加信息,两种方式,一是如下方法: https://www.httpbin.org/get?name=germey&age=25 还有就是:
    import requests
    data = {
        'name':'germey',
        'age':25
    }
    
    r = requests.get('https://www.httpbin.org/get',params=data)
    print(r.text)
    
  • 结果就是:
    {
      "args": {
        "age": "25",    
        "name": "germey"
      },
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Host": "www.httpbin.org",
        "User-Agent": "python-requests/2.28.1",
        "X-Amzn-Trace-Id": "Root=1-63a6d158-7e47854b18da5e1747e50cad"    
      },
      "origin": "39.69.199.58",
      "url": "https://www.httpbin.org/get?name=germey&age=25"
    }
    
  • 显然第二种方法,容易操作,不用我们自己构造URL了。
  • 返回的类型是str类型,但却是特殊的JSON格式,所以可以直接调用json方法。
    import requests
    
    r = requests.get('https://www.httpbin.org/get')
    print(type(r.text))
    print(r.json())
    print(type(r.json))
    
    <class 'str'>
    {'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'www.httpbin.org', 'User-Agent': 'python-requests/2.28.1', 'X-Amzn-Trace-Id': 'Root=1-63a6d315-4af0b6be1b0e2ceb155f7fb2'}, 'origin': '39.69.199.58', 'url': 'https://www.httpbin.org/get'}    
    <class 'method'>
    
    从结果看,调用json方法将结果转化为了字典类型。

抓取网页

import requests
import re
r = requests.get('https://ssr1.scrape.center')
pattern = re.compile('<h2.*?>(.*?)</h2>',re.S)
titles = re.findall(pattern,r.text)
print(titles)
  • 运行结果:

    ['霸王别姬 - Farewell My Concubine', '这个杀手不太冷 - Léon', '肖申克的救赎 - The Shawshank Redemption', '泰坦尼克号 - Titanic', '罗马假日 - Roman Holiday', '唐伯虎点秋香 - Flirting Scholar', '乱世佳人 - Gone with the Wind', '喜剧之王 - The King of Comedy', '楚门的世界 - The Truman Show', '狮子王 - The Lion King']

抓取二进制数据

import requests

r = requests.get('https://scrape.center/favicon.ico')
print(r.text)
print(r.content)

在这里插入图片描述

  • 上面是运行结果。r.text中出现了乱码,r.content的前面带有一个b,代表是bytes类型的数据。
  • 然后把信息保存起来。
import requests

r = requests.get('https://scrape.center/favicon.ico')
with open("favicon.ico",'wb') as f:
    f.write(r.content)
  • 得到了一个图标。这里用了 open 方法,它的第一个参数是文件名称,第二个参数代表以二进制写的形式打开,可以向文件里写入二进制数据。 运行结束之后,可以发现在文件夹中出现了名为 favicon.ico 的图标,如图所示。 在这里插入图片描述

添加请求头headers

  • 我们知道,在发起一个 HTTP 请求的时候,会有一个请求头 Request Headers,那么这个怎么来设置呢?

  • 很简单,我们使用 headers 参数就可以完成了。

  • 在刚才的实例中,实际上我们是没有设置 Request Headers 信息的,如果不设置,某些网站会发现这不是一个正常的浏览器发起的请求,网站可能会返回异常的结果,导致网页抓取失败。

  • 要添加 Headers 信息,比如我们这里想添加一个 User-Agent 字段,我们可以这么来写:

    import requests
    
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
    }
    r = requests.get('https://ssr1.scrape.center/', headers=headers)
    print(r.text)
    

    当然,我们可以在 headers 这个参数中任意添加其他的字段信息。

2.2.4 post请求

  • 前面我们了解了最基本的 GET 请求,另外一种比较常见的请求方式是 POST。使用 requests 实现 POST 请求同样非常简单,示例如下:

    import requests
    
    data = {'name': 'germey', 'age': '25'}
    r = requests.post("https://httpbin.org/post", data=data)
    print(r.text)
    
  • 这里还是请求 https://httpbin.org/post,该网站可以判断如果请求是 POST 方式,就把相关请求信息返回。

  • 运行结果如下:

    {
      "args": {},
      "data": "",
      "files": {},
      "form": {
        "age": "25",
        "name": "germey"
      },
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Content-Length": "18",
        "Content-Type": "application/x-www-form-urlencoded",
        "Host": "httpbin.org",
        "User-Agent": "python-requests/2.22.0",
        "X-Amzn-Trace-Id": "Root=1-5e6e3b52-0f36782ea980fce53c8c6524"
      },
      "json": null,
      "origin": "17.20.232.237",
      "url": "https://httpbin.org/post"
    }
    

    可以发现,我们成功获得了返回结果,其中 form 部分就是提交的数据,这就证明 POST 请求成功发送了。

2.2.5 响应

  • 发送请求后,得到的自然就是响应。在上面的实例中,我们使用 text 和 content 获取了响应的内容。此外,还有很多属性和方法可以用来获取其他信息,比如状态码、响应头、Cookie 等。示例如下:

    import requests
    
    r = requests.get('https://ssr1.scrape.center/')
    print(type(r.status_code), r.status_code)
    print(type(r.headers), r.headers)
    print(type(r.cookies), r.cookies)
    print(type(r.url), r.url)
    print(type(r.history), r.history)
    

    这里分别打印输出 status_code 属性得到状态码,输出 headers 属性得到响应头,输出 cookies 属性得到 Cookie,输出 url 属性得到 URL,输出 history 属性得到请求历史。

  • 运行结果如下:

    <class 'int'> 200
    <class 'requests.structures.CaseInsensitiveDict'> {'Server': 'nginx/1.17.8', 'Date': 'Sat, 30 May 2020 16:56:40 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'DENY', 'X-Content-Type-Options': 'nosniff', 'Strict-Transport-Security': 'max-age=15724800; includeSubDomains', 'Content-Encoding': 'gzip'}
    <class 'requests.cookies.RequestsCookieJar'> <RequestsCookieJar[]>
    <class 'str'> https://ssr1.scrape.center/
    <class 'list'> []
    
    • 可以看到,headers 和 cookies 这两个属性得到的结果分别是 CaseInsensitiveDict 和 RequestsCookieJar 类型。
    • 在第一章我们知道,状态码是用来表示响应状态的,比如返回 200 代表我们得到的响应是没问题的,上面的例子正好输出的结果也是 200,所以我们可以通过判断 Response 的状态码来知道爬取是否爬取成功。
  • requests 还提供了一个内置的状态码查询对象 requests.codes,用法示例如下:

    import requests
    
    r = requests.get('https://ssr1.scrape.center/')
    exit() if not r.status_code == requests.codes.ok else print('Request Successfully')
    
    • 这里通过比较返回码和内置的成功的返回码,来保证请求得到了正常响应,输出成功请求的消息,否则程序终止,这里我们用 requests.codes.ok 得到的是成功的状态码 200。
    • 这样的话,我们就不用再在程序里面写状态吗对应的数字了,用字符串表示状态码会显得更加直观。
  • 当然,肯定不能只有 ok 这个条件码。 下面列出了返回码和相应的查询条件:

    # 信息性状态码
    100: ('continue',),
    101: ('switching_protocols',),
    102: ('processing',),
    103: ('checkpoint',),
    122: ('uri_too_long', 'request_uri_too_long'),
    
    # 成功状态码
    200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'),
    201: ('created',),
    202: ('accepted',),
    203: ('non_authoritative_info', 'non_authoritative_information'),
    204: ('no_content',),
    205: ('reset_content', 'reset'),
    206: ('partial_content', 'partial'),
    207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'),
    208: ('already_reported',),
    226: ('im_used',),
    
    # 重定向状态码
    300: ('multiple_choices',),
    301: ('moved_permanently', 'moved', '\\o-'),
    302: ('found',),
    303: ('see_other', 'other'),
    304: ('not_modified',),
    305: ('use_proxy',),
    306: ('switch_proxy',),
    307: ('temporary_redirect', 'temporary_moved', 'temporary'),
    308: ('permanent_redirect',
         'resume_incomplete', 'resume',), # These 2 to be removed in 3.0
    
    # 客户端错误状态码
    400: ('bad_request', 'bad'),
    401: ('unauthorized',),
    402: ('payment_required', 'payment'),
    403: ('forbidden',),
    404: ('not_found', '-o-'),
    405: ('method_not_allowed', 'not_allowed'),
    406: ('not_acceptable',),
    407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'),
    408: ('request_timeout', 'timeout'),
    409: ('conflict',),
    410: ('gone',),
    411: ('length_required',),
    412: ('precondition_failed', 'precondition'),
    413: ('request_entity_too_large',),
    414: ('request_uri_too_large',),
    415: ('unsupported_media_type', 'unsupported_media', 'media_type'),
    416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'),
    417: ('expectation_failed',),
    418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'),
    421: ('misdirected_request',),
    422: ('unprocessable_entity', 'unprocessable'),
    423: ('locked',),
    424: ('failed_dependency', 'dependency'),
    425: ('unordered_collection', 'unordered'),
    426: ('upgrade_required', 'upgrade'),
    428: ('precondition_required', 'precondition'),
    429: ('too_many_requests', 'too_many'),
    431: ('header_fields_too_large', 'fields_too_large'),
    444: ('no_response', 'none'),
    449: ('retry_with', 'retry'),
    450: ('blocked_by_windows_parental_controls', 'parental_controls'),
    451: ('unavailable_for_legal_reasons', 'legal_reasons'),
    499: ('client_closed_request',),
    
    # 服务端错误状态码
    500: ('internal_server_error', 'server_error', '/o\\', '✗'),
    501: ('not_implemented',),
    502: ('bad_gateway',),
    503: ('service_unavailable', 'unavailable'),
    504: ('gateway_timeout',),
    505: ('http_version_not_supported', 'http_version'),
    506: ('variant_also_negotiates',),
    507: ('insufficient_storage',),
    509: ('bandwidth_limit_exceeded', 'bandwidth'),
    510: ('not_extended',),
    511: ('network_authentication_required', 'network_auth', 'network_authentication')
    

    比如,如果想判断结果是不是 404 状态,可以用 requests.codes.not_found 来比对。

2.2.6 高级用法

  • 前面我们了解了 requests 的基本用法,如基本的 GET、POST 请求以及 Response 对象。下面我们再来了解下 requests 的一些高级用法,如文件上传、Cookie 设置、代理设置等。

文件上传

  • 我们知道 requests 可以模拟提交一些数据。假如有的网站需要上传文件,我们也可以用它来实现,这非常简单,示例如下:

    import requests
    
    files = {'file': open('favicon.ico', 'rb')}
    r = requests.post('https://httpbin.org/post', files=files)
    print(r.text)
    

    在前一节中我们保存了一个文件 favicon.ico,这次用它来模拟文件上传的过程。需要注意的是,favicon.ico 需要和当前脚本在同一目录下。如果有其他文件,当然也可以使用其他文件来上传,更改下代码即可。 运行结果如下:

    {
      "args": {},
      "data": "",
      "files": {
        "file": "data:application/octet-stream;base64,AAABAAI..."
      },
      "form": {},
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Content-Length": "6665",
        "Content-Type": "multipart/form-data; boundary=41fc691282cc894f8f06adabb24f05fb",
        "Host": "httpbin.org",
        "User-Agent": "python-requests/2.22.0",
        "X-Amzn-Trace-Id": "Root=1-5e6e3c0b-45b07bdd3a922e364793ef48"
      },
      "json": null,
      "origin": "16.20.232.237",
      "url": "https://httpbin.org/post"
    }
    

    以上省略部分内容,这个网站会返回响应,里面包含 files 这个字段,而 form 字段是空的,这证明文件上传部分会单独有一个 files 字段来标识。

cookie设置

  • 前面我们使用 urllib 处理过 Cookie,写法比较复杂,而有了 requests,获取和设置 Cookie 只需一步即可完成。

  • 我们先用一个实例看一下获取 Cookie 的过程:

    import requests
    
    r = requests.get('https://www.baidu.com')
    print(r.cookies)
    for key, value in r.cookies.items():
        print(key + '=' + value)
    

    运行结果如下:

    	<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
    BDORZ=27315
    
    • 这里我们首先调用 cookies 属性即可成功得到 Cookie,可以发现它是 RequestCookieJar 类型。然后用 items 方法将其转化为元组组成的列表,遍历输出每一个 Cookie 条目的名称和值,实现 Cookie 的遍历解析。
  • 当然,我们也可以直接用 Cookie 来维持登录状态,下面我们以 GitHub 为例来说明一下,首先我们登录 GitHub,然后将 Headers 中的 Cookie 内容复制下来,如图所示。 在这里插入图片描述

  • 这里可以替换成你自己的 Cookie,将其设置到 Headers 里面,然后发送请求,示例如下:

    import requests
    
    headers = {
        'Cookie': '_octo=GH1.1.1849343058.1576602081; _ga=GA1.2.90460451.1576602111; __Host-user_session_same_site=nbDv62kHNjp4N5KyQNYZ208waeqsmNgxFnFC88rnV7gTYQw_; _device_id=a7ca73be0e8f1a81d1e2ebb5349f9075; user_session=nbDv62kHNjp4N5KyQNYZ208waeqsmNgxFnFC88rnV7gTYQw_; logged_in=yes; dotcom_user=Germey; tz=Asia%2FShanghai; has_recent_activity=1; _gat=1; _gh_sess=your_session_info',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
    }
    r = requests.get('https://github.com/', headers=headers)
    print(r.text)
    
    • 我们发现,结果中包含了登录后才能包含的结果,如图所示: 在这里插入图片描述
    • 可以看到这里包含了我的 GitHub 用户名信息,你如果尝试之后同样可以得到你的用户信息。
    • 得到这样类似的结果,就说明我们用 Cookie 就成功模拟了登录状态,这样我们就能爬取登录之后才能看到的页面了。
  • 当然,我们也可以通过 cookies 参数来设置 Cookie 的信息,这里我们可以构造一个 RequestsCookieJar 对象,然后把刚才复制的 Cookie 处理下并赋值,示例如下:

    import requests
    
    cookies = '_octo=GH1.1.1849343058.1576602081; _ga=GA1.2.90460451.1576602111; __Host-user_session_same_site=nbDv62kHNjp4N5KyQNYZ208waeqsmNgxFnFC88rnV7gTYQw_; _device_id=a7ca73be0e8f1a81d1e2ebb5349f9075; user_session=nbDv62kHNjp4N5KyQNYZ208waeqsmNgxFnFC88rnV7gTYQw_; logged_in=yes; dotcom_user=Germey; tz=Asia%2FShanghai; has_recent_activity=1; _gat=1; _gh_sess=your_session_info'
    jar = requests.cookies.RequestsCookieJar()
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
    }
    for cookie in cookies.split(';'):
        key, value = cookie.split('=', 1)
        jar.set(key, value)
    r = requests.get('https://github.com/', cookies=jar, headers=headers)
    print(r.text)
    

    这里我们首先新建了一个 RequestCookieJar 对象,然后将复制下来的 cookies 利用 split 方法分割,接着利用 set 方法设置好每个 Cookie 的 key 和 value,然后通过调用 requests 的 get 方法并传递给 cookies 参数即可。 测试后,发现同样可以正常登录。

session维持

  • 在 requests 中,如果直接利用 get 或 post 等方法的确可以做到模拟网页的请求,但是这实际上是相当于不同的 Session,也就是说相当于你用了两个浏览器打开了不同的页面。

  • 设想这样一个场景,第一个请求利用 requests 的 post 方法登录了某个网站,第二次想获取成功登录后的自己的个人信息,又用了一次 requests 的 get 方法去请求个人信息页面。

  • 实际上,这相当于打开了两个浏览器,是两个完全独立的操作,对应两个完全不相关的 Session,能成功获取个人信息吗?那当然不能。

  • 有人可能说了,我在两次请求时设置一样的 Cookies 不就行了?可以,但这样做起来显得很烦琐,我们有更简单的解决方法。

  • 其实解决这个问题的主要方法就是维持同一个 Session,也就是相当于打开一个新的浏览器选项卡而不是新开一个浏览器。但是我又不想每次设置 Cookies,那该怎么办呢?这时候就有了新的利器 —— Session 对象。

  • 利用它,我们可以方便地维护一个 Session,而且不用担心 Cookie 的问题,它会帮我们自动处理好。

  • 我们先做一个小实验吧,如果沿用之前的写法,示例如下:

    import requests
    
    requests.get('https://httpbin.org/cookies/set/number/123456789')
    r = requests.get('https://httpbin.org/cookies')
    print(r.text)
    

    这里我们请求了一个测试网址 https://httpbin.org/cookies/set/number/123456789。请求这个网址时,可以设置一个 Cookie 条目,名称叫作 number,内容是 123456789,随后又请求了 https://httpbin.org/cookies,此网址可以获取当前的 Cookie 信息。 这样能成功获取到设置的 Cookie 吗?试试看。 运行结果如下:

    {
      "cookies": {}
    }
    

    显然不行。 这时候,我们再用刚才所说的 Session 试试看:

    import requests
    
    s = requests.Session()
    s.get('https://httpbin.org/cookies/set/number/123456789')
    r = s.get('https://httpbin.org/cookies')
    print(r.text)
    

    再看结果:

    {
      "cookies": {"number": "123456789"}
    }
    
    • 这些可以看到 Cookies 被成功获取了!这下能体会到同一个会话和不同会话的区别了吧!
  • 所以,利用 Session,可以做到模拟同一个会话而不用担心 Cookie 的问题。它通常用于模拟登录成功之后再进行下一步的操作。

  • Session 在平常用得非常广泛,可以用于模拟在一个浏览器中打开同一站点的不同页面,后面会有专门的章节来讲解这部分内容。

SSL 证书验证

  • 现在很多网站都要求使用 HTTPS 协议,但是有些网站可能并没有设置好 HTTPS 证书,或者网站的 HTTPS 证书可能并不被 CA 机构认可,这时候,这些网站可能就会出现 SSL 证书错误的提示。

  • 比如这个示例网站:https://ssr2.scrape.center/,如果我们用 Chrome 浏览器打开这个 URL,则会提示「您的连接不是私密连接」这样的错误,如图所示: 在这里插入图片描述 我们可以在浏览器中通过一些设置来忽略证书的验证。 但是如果我们想用 requests 来请求这类网站,会遇到什么问题呢?我们用代码来试一下:

    import requests
    
    response = requests.get('https://ssr2.scrape.center/')
    print(response.status_code)
    

    运行结果如下:

    requests.exceptions.SSLError: HTTPSConnectionPool(host='ssr2.scrape.center', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)')))
    
    • 可以看到,这里直接抛出了 SSLError 错误,原因就是因为我们请求的 URL 的证书是无效的。
  • 那如果我们一定要爬取这个网站怎么办呢?我们可以使用 verify 参数控制是否验证证书,如果将其设置为 False,在请求时就不会再验证证书是否有效。如果不加 verify 参数的话,默认值是 True,会自动验证。

  • 我们改写代码如下:

    import requests
    
    response = requests.get('https://ssr2.scrape.center/', verify=False)
    print(response.status_code)
    

    这样就会打印出请求成功的状态码:

    /usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py:857: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
      InsecureRequestWarning)
    200
    
  • 不过我们发现报了一个警告,它建议我们给它指定证书。我们可以通过设置忽略警告的方式来屏蔽这个警告:

    import requests
    from requests.packages import urllib3
    
    urllib3.disable_warnings()
    response = requests.get('https://ssr2.scrape.center/', verify=False)
    print(response.status_code)
    
  • 或者通过捕获警告到日志的方式忽略警告:

    import logging
    import requests
    
    logging.captureWarnings(True)
    response = requests.get('https://ssr2.scrape.center/', verify=False)
    print(response.status_code)
    
  • 当然,我们也可以指定一个本地证书用作客户端证书,这可以是单个文件(包含密钥和证书)或一个包含两个文件路径的元组:

    import requests
    
    response = requests.get('https://ssr2.scrape.center/', cert=('/path/server.crt', '/path/server.key'))
    print(response.status_code)
    

    当然,上面的代码是演示实例,我们需要有 crt 和 key 文件,并且指定它们的路径。另外注意,本地私有证书的 key 必须是解密状态,加密状态的 key 是不支持的。

超时设置

  • 在本机网络状况不好或者服务器网络响应太慢甚至无响应时,我们可能会等待特别久的时间才可能收到响应,甚至到最后收不到响应而报错。为了防止服务器不能及时响应,应该设置一个超时时间,即超过了这个时间还没有得到响应,那就报错。这需要用到 timeout 参数。这个时间的计算是发出请求到服务器返回响应的时间。示例如下:

    import requests
    
    r = requests.get('https://httpbin.org/get', timeout=1)
    print(r.status_code)
    
  • 通过这样的方式,我们可以将超时时间设置为 1 秒,如果 1 秒内没有响应,那就抛出异常。

  • 实际上,请求分为两个阶段,即连接(connect)和读取(read)。

  • 上面设置的 timeout 将用作连接和读取这二者的 timeout 总和。

  • 如果要分别指定,就可以传入一个元组: r = requests.get('https://httpbin.org/get', timeout=(5, 30))

  • 如果想永久等待,可以直接将 timeout 设置为 None,或者不设置直接留空,因为默认是 None。这样的话,如果服务器还在运行,但是响应特别慢,那就慢慢等吧,它永远不会返回超时错误的。其用法如下: r = requests.get('https://httpbin.org/get', timeout=None) 或直接不加参数: r = requests.get('https://httpbin.org/get')

身份认证

  • 在上一节我们讲到,在访问启用了基本身份认证的网站时,我们会首先遇到一个认证窗口,例如:https://ssr3.scrape.center/,如图所示。 在这里插入图片描述

  • 这个网站就是启用了基本身份认证,在上一节中我们可以利用 urllib 来实现身份的校验,但实现起来相对繁琐。那在 reqeusts 中怎么做呢?当然也有办法。

  • 我们可以使用 requests 自带的身份认证功能,通过 auth 参数即可设置,示例如下:

    import requests
    from requests.auth import HTTPBasicAuth
    
    r = requests.get('https://ssr3.scrape.center/', auth=HTTPBasicAuth('admin', 'admin'))
    print(r.status_code)
    
  • 这个示例网站的用户名和密码都是 admin,在这里我们可以直接设置。

  • 如果用户名和密码正确的话,请求时就会自动认证成功,会返回 200 状态码;如果认证失败,则返回 401 状态码。

  • 当然,如果参数都传一个 HTTPBasicAuth 类,就显得有点烦琐了,所以 requests 提供了一个更简单的写法,可以直接传一个元组,它会默认使用 HTTPBasicAuth 这个类来认证。

  • 所以上面的代码可以直接简写如下:

    import requests
    
    r = requests.get('https://ssr3.scrape.center/', auth=('admin', 'admin'))
    print(r.status_code)
    
  • 此外,requests 还提供了其他认证方式,如 OAuth 认证,不过此时需要安装 oauth 包,安装命令如下:

  • pip3 install requests_oauthlib

  • 使用 OAuth1 认证的示例方法如下:

    import requests
    from requests_oauthlib import OAuth1
    
    url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
    auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET',
                  'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET')
    requests.get(url, auth=auth)
    

    代理设置

  • 对于某些网站,在测试的时候请求几次,能正常获取内容。但是一旦开始大规模爬取,对于大规模且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面,更甚者可能会直接封禁客户端的 IP,导致一定时间段内无法访问。

  • 那么,为了防止这种情况发生,我们需要设置代理来解决这个问题,这就需要用到 proxies 参数。可以用这样的方式设置:

    import requests
    
    proxies = {
      'http': 'http://10.10.10.10:1080',
      'https': 'http://10.10.10.10:1080',
    }
    requests.get('https://httpbin.org/get', proxies=proxies)
    
    • 当然,直接运行这个实例可能不行,因为这个代理可能是无效的,可以直接搜索寻找有效的代理并替换试验一下。
  • 若代理需要使用上文所述的身份认证,可以使用类似 http://user:password@host:port 这样的语法来设置代理,示例如下:

    import requests
    
    proxies = {'https': 'http://user:[email protected]:1080/',}
    requests.get('https://httpbin.org/get', proxies=proxies)
    
  • 除了基本的 HTTP 代理外,requests 还支持 SOCKS 协议的代理。

  • 首先,需要安装 socks 这个库:

  • pip3 install "requests[socks]"

  • 然后就可以使用 SOCKS 协议代理了,示例如下:

    import requests
    
    proxies = {
        'http': 'socks5://user:password@host:port',
        'https': 'socks5://user:password@host:port'
    }
    requests.get('https://httpbin.org/get', proxies=proxies)
    

Prepared Request

  • 我们使用 requests 库的 get 和 post 方法当然直接可以发送请求,但有没有想过,这个请求在 requests 内部是怎么实现的呢?

  • 实际上,requests 在发送请求的时候,是在内部构造了一个 Request 对象,并给这个对象赋予了各种参数,包括 url、headers、data 等等,然后直接把这个 Request 对象发送出去,请求成功后会再得到一个 Response 对象,再解析即可。

  • 那么这个 Request 是什么类型呢?实际上它就是 Prepared Request。

  • 我们深入一下,不用 get 方法,直接构造一个 Prepared Request 对象来试试,代码如下:

    from requests import Request, Session
    
    url = 'https://httpbin.org/post'
    data = {'name': 'germey'}
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
        }
    s = Session()
    req = Request('POST', url, data=data, headers=headers)
    prepped = s.prepare_request(req)
    r = s.send(prepped)
    print(r.text)
    

    这里我们引入了 Request 这个类,然后用 url、data 和 headers 参数构造了一个 Request 对象,这时需要再调用 Session 的 prepare_request 方法将其转换为一个 Prepared Request 对象,然后调用 send 方法发送,运行结果如下:

    {
      "args": {},
      "data": "",
      "files": {},
      "form": {
        "name": "germey"
      },
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Content-Length": "11",
        "Content-Type": "application/x-www-form-urlencoded",
        "Host": "httpbin.org",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36",
        "X-Amzn-Trace-Id": "Root=1-5e5bd6a9-6513c838f35b06a0751606d8"
      },
      "json": null,
      "origin": "167.220.232.237",
      "url": "http://httpbin.org/post"
    }
    

    可以看到,我们达到了同样的 POST 请求效果。 有了 Request 这个对象,就可以将请求当作独立的对象来看待,这样在一些场景中我们可以直接操作这个 Request 对象,更灵活地实现请求的调度和各种操作。

标签:httpbin,get,一步,爬虫,https,print,import,requests
From: https://blog.51cto.com/u_15930659/5991013

相关文章