爬虫基本库:requests

requests

    在 urllib 的应用中,有一些不方便的地方,比如处理网页验证和 Cookies 时,需要写 Opener 和 Handler 来处理。为了更加方便地实现这些操作,需要用到更强大的库:requests。

1. 基本用法

1.1. 简单示例

    urllib 库中的 urlopen() 方法以 GET 方式请求网页,而 requests 中相应的就是 get() 方法。

import requests

r = requests.get('https://www.baidu.com/')

print(type(r))
# 

print(r.status_code)
# 200

# 响应体的类型
print(type(r.text))
# 

# 响应体的内容
print(r.text)

# Cookies的类型
print(r.cookies)
# ]>

1.2. GET请求

    HTTP中最常见的请求之一就是GET请求。构建一个最简单的GET请求,链接为 http://httpbin.org/get,该网站会判断请求方式,如果是GET请求的话就返回相应的请求信息。

1.2.1. 基本实例

import requests

r = requests.get('http://httpbin.org/get')
print(r.text)

"""
运行结果:
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Connection": "close", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.20.1"
  }, 
  "origin": "123.160.224.118", 
  "url": "http://httpbin.org/get"
}
"""

    如果要在GET请求中附加额外的信息,一般用字典来存储:

import requests

data = {
    'name': 'germey',
    'age': 22
}
r = requests.get('http://httpbin.org/get', params=data)
print(r.text)

"""
{
  "args": {
    "age": "22", 
    "name": "germey"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Connection": "close", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.20.1"
  }, 
  "origin": "123.160.224.118", 
  "url": "http://httpbin.org/get?name=germey&age=22"
}
"""

    网页的返回类型实际上是 str 类型,但是它很特殊,是JSON格式的。如果想直接解析返回结果,得到一个字典格式的话,可以直接调用 json() 方法。

import requests

r = requests.get('http://httpbin.org/get')
print(type(r.text))
print(r.json())
print(type(r.json()))

"""
运行结果:

{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.20.1'}, 'origin': '123.160.224.118', 'url': 'http://httpbin.org/get'}

"""

    调用 json() 方法可以将返回结果是JSON格式的字符串转化为字典,但是在返回结果不是JSON格式时会出现解析错误,抛出 json.decoder.JSONDecoderError 异常。

1.2.2. 抓取网页

    以“知乎”的“发现”页面为例:

import requests
import re

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://www.zhihu.com/explore', headers=headers)
pattern = re.compile('explore-feed.*?question_link.*?>(.*?)', re.S)
titles = re.findall(pattern, r.text)
print(titles)

"""
运行结果:
['\n历史上有那些长期流传的,错误的地理记载,后来是如何被推翻的?\n', 
'\n人生应该活成什么样子,该以什么样的方式活着?\n', 
'\nfgo里面的从者和礼装卡面有哪些不仔细看看不出来的小彩蛋?\n', 
'\n如何看待新浪娱乐的对话特辑《听老高鹿晗说》?\n', 
'\n如何评价《群星(Stellaris)》新DLC《巨型企业(Megacorp)》?\n', 
'\n有哪些句子是真正写到你的心里去了?\n', 
'\n经过此次马思纯回怼风波后,杨紫后续的资源是否更差?\n', 
'\n你有过哪些像段子的亲身经历?\n', 
'\n如何看待网传朱一龙抽烟并随地扔烟头?\n', 
'\n怎么评价防弹续约7年?\n']
"""

    User-Agent 字段信息是浏览器标识信息,不加会被禁止抓取。

1.2.3. 抓取二进制数据

    以 GitHub 的站点图标为例:

import requests

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

结果如下:
r.text 部分结果:�������t������������������������������
r.content 部分结果:
b'\x00\x00\x01\x00\x02\x00\x10\x10\x00\x00\x01\x00
图片是二进制数据,前者在打印时转化为 str 类型,图片直接转化为字符串,会出现乱码

将提取的图片保存下来

import requests

r = requests.get('https://github.com/favicon.ico')
with open('favicon.ico', 'wb') as f:
    f.write(r.content)

    使用 open() 方法,第一个参数是文件名称,第二个参数代表以二进制形式打开,可以向文件中写入二进制数据。运行结束会在文佳家中产生名为 favicon.ico 的图片文件。
    同样,音频和视频文件也可以用这种方法获取。

1.2.4. 添加 headers

    与 urllib.request 一样,requests 也通过 headers 来传递头消息。例如前面的“知乎”例子中,如果不传递 headers,就不能正常请求:

import requests

r = requests.get('https://www.zhihu.com/explore')
print(r.text)

"""
运行结果:

400 Bad Request

400 Bad Request


openresty
"""

1.3. POST请求

    请求 http://httpbin.org/post,该网站判断是POST请求后把相关信息返回,其中 form 部分就是提交的数据,证明POST请求成功。

import requests

data = {'name': 'germey', 'age': '22'}
r = requests.post('http://httpbin.org/post', data=data)
print(r.text)

"""
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "age": "22", 
    "name": "germey"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Connection": "close", 
    "Content-Length": "18", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.20.1"
  }, 
  "json": null, 
  "origin": "123.160.224.118", 
  "url": "http://httpbin.org/post"
}
"""

1.4. 响应

    发送请求后,可以使用 text 和 content 得到的响应内容,此外还有很多属性和方法可以用来获取其他信息,如状态码、响应头、Cookies 等。

import requests

r = requests.get('http://www.jianshu.com')
# 输出状态码
print(type(r.status_code), r.status_code)
# 输出响应头
print(type(r.headers), r.headers)
# 输出Cookies
print(type(r.cookies), r.cookies)
# 输出URL
print(type(r.url), r.url)
# 输出请求历史
print(type(r.history), r.history)

403
{'Date': 'Sat, 24 Nov 2018 09:26:34 GMT', 'Content-Type': 'text/html', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Server': 'Tengine', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'Content-Encoding': 'gzip', 'X-Via': '1.1 PSzjwzdx11at80:10 (Cdn Cache Server V2.0), 1.1 PShbycdx6yh51:11 (Cdn Cache Server V2.0)'}

https://www.jianshu.com/
[]
headers 和 cookies 两个属性得到的结果分别是CaseInsensitiveDict 和 RequestsCookieJar 类型

    状态码常用来判断请求是否成功,而 requests 还提供了一个内置的状态码查询对象 requests.Codes,示例如下:

import requests

r = requests.get('http://www.jianshu.com')
exit() if not r.status_code == requests.codes.ok else print('Request Successfully')

    通过比较返回码和内置的成功的返回码,来保证请求得到了正常响应,输出成功请求的消息,否则程序终止,用 requests.codes.ok 得到的成功的状态码是 200。

一些返回码和相应的查询条件:
爬虫基本库:requests_第1张图片
信息性状态码、成功状态码、重定向状态吗

爬虫基本库:requests_第2张图片
客户端错误状态码

爬虫基本库:requests_第3张图片
服务端错误状态码

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

2. 高级用法

2.1. 文件上传

import requests

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

    上传的部分会在一个单独的 files 字段里标识出来。

2.2. Cookies

import requests

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

    可以直接用 Cookies 维持登录状态,登录后将 Headers 中的 Cookie 内容复制下来,替换成自己的 Cookie, 将其设置到 Headers 里,然后发送请求。

2.3. 会话维持

import requests

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

运行结果为:
{
"cookies": {}
}
不能获取到设置的 Cookies。

import requests

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

运行结果为:
{
"cookies": {
"number": "123456789"
}
}
Yes,获取成功!

2.4. SSL 证书验证

    requests 还提供了证书验证的功能。当发送 HTTP 请求的时候,它会检查 SSL 证书,我们可以使用 verify 参数控制是否检查此证书.其实如果不加 verify 参数的话,默认是 True ,会自动验证。

import requests

response = requests.get('https://www.12306.cn')
print(response.status_code)
"""
requests.exceptions.SSLError: ("bad handshske: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",)
"""

    这里提示一个错误 SSLError ,表示证书验证错误。所以,如果请求一个 HTTPS 站点,但是证书验证错误的页面时,就会报这样的错误,那么如何避免这个错误呢?很简单,把 verify 参数设置为 False 即可,相关代码如下:

import requests

response = requests.get('https://www.12306.cn', verify=False)
print(response.status_code)

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

import requests

response = requests.get('https://www.12306.cn', cert=('path/server.crt', 'path/key'))
print(response.status_code)

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

2.5. 代理设置

    对于某些网站,在测试的时候请求几次,能正常获取内容。但是一旦开始大规模爬取,对于大规模且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面 更甚者可能会直接封禁客户端的 IP,导致一定时间段内无法访问。
    那么,为了防止这种情况发生,需要设置代理来解决这个问题,这就需要用到 proxies 参数,可以用这样的方式设置:

import requests

proxies = {
    "http": "http://10.10.1.10:3128",
    "https": "https://10.10.1.10:1080"
}

requests.get("https://www.taobao.com", proxies=proxies)

# 如果代理需要使用 HTTP Basic Auth ,可以使用类似 http://user:password@host:port 这样的语法来设置代理
# requests.get("https://www.taobao.com", proxies=proxies)

2.6. 超时设置

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

import requests

r = requests.get("https://www.taobao.com", timeout=1)
print(r.status_code)

    超时时间设置为1秒,1秒内没有响应就抛出异常。实际上请求分为两个阶段:连接(connect)和读取(read),上面设置的 timeout 是两者用时的总和。

其他设置方式:
如果需要分开指定,可以传入一个元组:
r = requests.get('https://www.taobao.com', timeout=(5, 11, 30))
如果想永久等待,timeout 默认值为 None ,可以直接设置为 None:
r = requests.get("https://www.taobao.com", timeout=None)
也可以直接不加参数:
r = requests.get("https://www.taobao.com")

2.7. 身份认证

    requests 自带的身份认证功能:

import requests
from requests.auth import HTTPBasicAuth

r = requests.get('http://localhost:5000', auth=HTTPBasicAuth('username', 'password'))
print(r.status_code)

    如果用户名和密码正确,请求时会自动认证成功,返回 200 状态码;如果认证失败,则返回 401 状态码。
    还有一种简单的写法,不用传 HTTPBasicAuth 类参数,直接传一个元组,会默认使用 HTTPBasicAuth 这个类来认证:

import requests

r = requests.get('http://localhost:5000', auth=('username', 'password'))
print(r.status_code)

    requests 还提供了其他认证方式,如 OAuth 认证,不过需要安装 oauth 包,安装命令如下:

pip install requests.oauthlib

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)

更多详细功能请参考 requests_oauthlib 官方文档 https://requests-oauthlib.readthedocs.org/

你可能感兴趣的:(爬虫基本库:requests)