爬虫基础库之Requests模块
发送GET请求
直接请求
import requests response=requests.get("https://movie.douban.com/top250") print(response.text)
发送参数
你也许经常想为 URL 的查询字符串(query string)传递某种数据。如果你是手工构建 URL,那么数据会以键/值对的形式置于 URL 中,跟在一个问号的后面。
import requests r = requests.get('https://www.baidu.com/s?wd=%E8%80%81%E7%94%B7%E5%AD%A9', headers={ "User-Agent":"..." } ) print(r.text)
Requests 允许你使用 params
关键字参数,以一个字符串字典来提供这些参数。
import requests r = requests.get('https://www.baidu.com/s',params={"wd":"老男孩"}, headers={ "User-Agent":"..." } )
响应Response
import requests respone=requests.get('https://github.com') # respone属性
print(respone.text) print(respone.content) print(respone.status_code) print(respone.headers) print(respone.cookies) print(respone.cookies.get_dict()) print(respone.cookies.items()) print(respone.url) print(respone.history) print(respone.encoding)
定制请求头
如果你想为请求添加 HTTP 头部,只要简单地传递一个 dict
给 headers
参数就可以了。
#通常我们在发送请求时都需要带上请求头,请求头是将自身伪装成浏览器的关键,常见的有用的请求头如下 Host Referer #大型网站通常都会根据该参数判断请求的来源 User-Agent #客户端 Cookie #Cookie信息虽然包含在请求头里,但requests模块有单独的参数来处理他,headers={}内就不要放它了
#添加headers(浏览器会识别请求头,不加可能会被拒绝访问,比如访问https://www.zhihu.com/explore) import requests response=requests.get('https://www.zhihu.com/explore') print(response.status_code) #500 #自己定制headers headers={ 'User-Agent':'......', } respone=requests.get('https://www.zhihu.com/explore', headers=headers) print(respone.status_code) #200
设置cookies
要想发送你的cookies到服务器,可以使用 cookies
参数:
import requests url = 'http://httpbin.org/cookies' cookies = dict(cookies_are='working on') r = requests.get(url, cookies=cookies) print(r.text)
重定向与请求历史
默认情况下,除了 HEAD, Requests 会自动处理所有重定向。可以使用响应对象的 history
方法来追踪重定向。
Response.history
是一个 Response
对象的列表,为了完成请求而创建了这些对象。这个对象列表按照从最老到最近的请求进行排序。
>>> r = requests.get('http://github.com') >>> r.url 'https://github.com/' >>> r.status_code 200 >>> r.history [<Response [301]>]
另外,还可以通过 allow_redirects
参数禁用重定向处理:
>>> r = requests.get('http://github.com', allow_redirects=False) >>> r.status_code 301 >>> r.history []
超时
你可以告诉 requests 在经过以 timeout
参数设定的秒数时间之后停止等待响应。基本上所有的生产代码都应该使用这一参数。如果不使用,你的程序可能会永远失去响应:
requests.get('http://github.com', timeout=0.001)
Traceback (most recent call last): File "<stdin>", line 1, in <module> requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)
注意 timeout 仅对连接过程有效,与响应体的下载无关。 timeout 并不是整个下载响应的时间限制,而是如果服务器在 timeout 秒内没有应答,
将会引发一个异常(更精确地说,是在 timeout 秒内没有从基础套接字上接收到任何字节的数据时)
If no timeout is specified explicitly, requests do not time out.
错误与异常
''' 遇到网络问题(如:DNS 查询失败、拒绝连接等)时,Requests 会抛出一个 ConnectionError 异常。 如果 HTTP 请求返回了不成功的状态码, Response.raise_for_status() 会抛出一个 HTTPError 异常。 若请求超时,则抛出一个 Timeout 异常。 若请求超过了设定的最大重定向次数,则会抛出一个 TooManyRedirects 异常。 所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException 。 '''
发送POST请求
通常,你想要发送一些编码为表单形式的数据——非常像一个 HTML 表单。要实现这个,只需简单地传递一个字典给 data 参数。
你的数据字典在发出请求时会自动编码为表单形式:
payload = {'key1': 'value1', 'key2': 'value2'} response = requests.post("http://httpbin.org/post", data=payload) print(response.text)
你还可以为 data
参数传入一个元组列表。在表单中多个元素使用同一 key 的时候,这种方式尤其有效:
>>> payload = (('key1', 'value1'), ('key1', 'value2')) >>> r = requests.post('http://httpbin.org/post', data=payload) >>> print(r.text) { ... "form": { "key1": [ "value1", "value2" ] }, ... }
很多时候你想要发送的数据并非编码为表单形式的。如果你传递一个 string
而不是一个 dict
,那么数据会被直接发布出去。
例如,Github API v3 接受编码为 JSON 的 POST/PATCH 数据:
>>> import json >>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, data=json.dumps(payload))
此处除了可以自行对 dict
进行编码,你还可以使用 json
参数直接传递,然后它就会被自动编码。这是 2.4.2 版的新加功能:
>>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, json=payload)
提到json数据,如果响应的数据是json数据,直接可以如下解析:
import requests response=requests.get('http://httpbin.org/get') res=response.json() #不需要 json.loads(response.text)
post请求其他设置参照get请求。
应用
模拟GitHub登录:
import requests import re #请求1: r1=requests.get('https://github.com/login') r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授权) authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN print("authenticity_token",authenticity_token) #第二次请求:带着初始cookie和TOKEN发送POST请求给登录页面,带上账号密码 data={ 'commit':'Sign in', 'utf8':'✓', 'authenticity_token':authenticity_token, 'login':'yuanchenqi0316@163.com', 'password':'yuanchenqi0316' } #请求2: r2=requests.post('https://github.com/session', data=data, cookies=r1_cookie, # allow_redirects=False ) print(r2.status_code) #200 print(r2.url) #看到的是跳转后的页面:https://github.com/ print(r2.history) #看到的是跳转前的response:[<Response [302]>] print(r2.history[0].text) #看到的是跳转前的response.text with open("y.html","wb") as f: f.write(r2.content)