——前面讲过,HTTP Requests包含请求方式、请求URL、请求头、请求体(即携带的参数),如果我们爬虫请求URL失败,那很有可能是我们的Requests数据与浏览器的不一样。所以还是那句话,浏览器做什么,爬虫就做什么!
Requests库13个控制访问参数详解:
-
headers : 请求头
通常我们在发送请求时都需要带上请求头,请求头是将自身伪装成浏览器的关键
如下图,是爬"有道翻译"的请求头
笨办法是把所有参数带上,在逐个尝试删除
而实际上,只有Host、Referer、User-Agent、Cookie 是有用的,但不是绝对的
Cookie虽然包含在headers中,但Requests库有单独参数来处理它,headers={}内就不要放它了
范例代码:
import requests
r = requests.get('https://www.zhihu.com/')
print(r.status_code)
headers = {'User-Agent':'Mozilla/5.0'}
r = requests.get('https://www.zhihu.com/',headers = headers)
print(r.status_code)
运行结果:
400
200
>>>
上面的代码中,我们对知乎发起两次请求,不带请求头返回400,可见知乎在headers做了来源审查
把上面的代码修改一下,分别出打印两次访问的请求头
范例代码:
import requests
r = requests.get('https://www.zhihu.com/')
print(r.request.headers)
print('')
headers = {'User-Agent':'Mozilla/5.0'}
r = requests.get('https://www.zhihu.com/',headers = headers)
print(r.request.headers)
运行结果:
{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
{'User-Agent': 'Mozilla/5.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'tgw_l7_route=a37704a413efa26cf3f23813004f1a3b; _zap=94c457cd-7c53-4f60-b463-4f8c024dbe06; _xsrf=3ppe1f3Dh00KARJ3rybWippiTSM2LBFo'}
>>>
我们可以看到,'User-Agent'
字段不同,第一次请求是'User-Agent': 'python-requests/2.22.0'
,很明显,我们第一次请求的代码在告诉知乎:我是一个python爬虫
-
params : 字典或字节序列,作为参数增加到url中
通常为get()请求携带的参数,我们用python开发者测试地址来做演示http://httpbin.org/get
范例代码:
import requests
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.url)
运行结果:
http://httpbin.org/get?key1=value1&key2=value2
>>>
-
params 实例运用
如下,搜索引擎关键字提交接口
# 百度的关键词提交接口
http://www.baidu.com/s?wd=keyword
# 360的关键字词接口
http://www.so.com/s?q=keyword
keyword表示关键字,我们用params={'wd':keywoed}
传入url,实现百度搜索,如下代码:
import requests
kv = {'wd':'python'}
r = requests.get('http://www.baidu.com/s',params = kv)
print(r.url)
-
data : 字典、字节序列或文件对象,作为Request的内容
通常为post()请求携带参数,在上文我们展示了post()传参表单形式,除此之外,还可以是Json数据,文件
post()传参Json数据:
import requests
import json
url = 'http://httpbin.org/post'
payload = {'some': 'data'}
r = requests.post(url, data=json.dumps(payload))
print(r.text)
运行结果:
{
"args": {},
"data": "{\"some\": \"data\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "16",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"json": {
"some": "data"
},
"origin": "119.129.129.70, 119.129.129.70",
"url": "https://httpbin.org/post"
}
>>>
我们看到"some": "data"
被放到了Json字段下,json.dumps()
是字典/列表转Json的方法
post()传参files文件:
如下,在本地新建一个report.xls
文件,写上"Hello world"
运行如下代码:
import requests
url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=files)
print(r.text)
运行结果:
{
"args": {},
"data": "",
"files": {
"file": "Hello World\r\n"
},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "159",
"Content-Type": "multipart/form-data; boundary=f40f0efd2466dba3e629ac1d905e7d04",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"json": null,
"origin": "119.129.130.109, 119.129.130.109",
"url": "https://httpbin.org/post"
}
>>>
我们看到,"Hello world"被放到了 files字段下
-
流式上传
post()支持流式上传,这允许你发送大的数据流或文件而无需先把它们读入内存。要使用流式上传,仅需为你的请求体提供一个类文件对象即可:
import requests
with open('massive-body','rb') as f:
requests.post('http://some.url/streamed', data=f)
-
json : JSON格式的数据,作为Request的内容
用法参考上面post()传参Json数据
-
files : 字典类型,传输文件
用法参考上面post()传参files文件
-
cookies详解:
cookies是什么?
比如一般当你登录一个网站,你都会在登录页面看到一个可勾选的选项“记住我”,如果你勾选了,以后你再打开这个网站就会自动登录,这就是cookie在起作用。当然,cookies也是有时效性的,过期后就会失效。
在Response headers,我们可以看到set cookies
参数。set cookies
是什么意思?就是服务器往浏览器写入了cookies。如下图:
cookies基本展示:
import requests
r = requests.get("https://www.baidu.com/")
print(r.cookies)
print(type(r.cookies))
print('')
r = requests.get("https://www.so.com/")
print(r.cookies)
print(type(r.cookies))
运行结果:
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
<class 'requests.cookies.RequestsCookieJar'>
<RequestsCookieJar[<Cookie QiHooGUID=266A3B3FBBF19BFE07FB2135103F842F.1563469171236 for www.so.com/>, <Cookie _S=2j7n8h174crroeq5a8npi3lm87 for www.so.com/>]>
<class 'requests.cookies.RequestsCookieJar'>
>>>
我们看到,r.cookies返回的是CookieJar对象,仔细看,在Cookie 到 for字段是键值对,如:BDORZ=27315
,也就是说,它的行为跟字典相似,那有没有方法可以让它跟字典互换呢?答案是有的
- cookies、dict互换
import requests
r = requests.get("https://www.baidu.com/")
# cookies、dict互换
cookies_dict = requests.utils.dict_from_cookiejar(r.cookies)
print(type(cookies_dict),'——',cookies_dict)
cookies = requests.utils.cookiejar_from_dict(cookies_dict)
print(type(cookies),'——',cookies)
# 以下方法也可以实现cookies转dict
cookie_dict = r.cookies.get_dict()
print(type(cookie_dict),'——',cookie_dict)
运行结果:
<class 'dict'> —— {'BDORZ': '27315'}
<class 'requests.cookies.RequestsCookieJar'> —— <RequestsCookieJar[<Cookie BDORZ=27315 for />]>
<class 'dict'> —— {'BDORZ': '27315'}
>>>
如果,你想发送你的cookies到服务器,也可以直接使用 cookies 的字典dict
形式
- cookies登录
import requests
r = requests.get(url,cookies = cookies_dict)
r = requests.post(url,data = payload,cookies = cookies_dict)
-
session(会话)
所谓的会话,你可以理解成我们用浏览器上网,到关闭浏览器的这一过程
cookies和session的区别是:
cookies数据存放在客户的浏览器上,session数据存放在服务器上
——以上的请求中,每次请求其实都相当于发起了一个新的请求。也就是相当于我们每个请求都用了不同的浏览器单独打开的效果。也就是它并不是指的一个会话,即使请求的是同一个网址。比如
import requests
requests.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = requests.get("http://httpbin.org/cookies")
print(r.text)
运行结果:
{
"cookies": {}
}
>>>
很明显,这不在一个会话中,无法获取 cookies,那么在一些站点中,我们需要保持一个持久的会话,就像用一个浏览器逛淘宝一样,在不同的选项卡之间跳转,这样其实就是建立了一个长久会话。
- 建立session(会话)
import requests
s = requests.Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")
print(r.text)
运行结果:
{
"cookies": {
"sessioncookie": "123456789"
}
}
>>>
会话中,我们请求了两次,一次是设置 cookies,一次是获得 cookies
我们发现可以成功获取到 cookies 了,这就是建立一个会话起到作用
- session基本框架
范例代码:
import requests,json
session = requests.Session()
headers = {'User-Agent': 'Mozilla/5.0'}
def cookies_read():
f = open('cookies.txt', 'r')
cookies_json = f.read()
f.close()
cookies_dict = json.loads(cookies_json)
cookies = requests.utils.cookiejar_from_dict(cookies_dict)
return cookies
def sign_in():
url = ' XXXXX'
data = {'XXXXX'}
session.post(url,headers=headers,data=data)
cookies_dict = requests.utils.dict_from_cookiejar(session.cookies)
cookies_json = json.dumps(cookies_dict)
f = open('cookies.txt', 'w')
f.write(cookies_json)
f.close()
def run():
url = 'XXXXX'
data = {'XXXXX'}
return (session.post(url, headers=headers, data=data))
try:
session.cookies = cookies_read()
except FileNotFoundError:
sign_in()
session.cookies = cookies_read()
q = run()
if q.status_code == 200:
print('成功啦!')
else:
sign_in()
session.cookies = cookies_read()
q = run()
以上,替换你的url、data或headers试试
- allow_redirects : True/False,默认为True,重定向开关
默认情况下,除了 HEAD, Requests 会自动处理所有重定向。
import requests
r = requests.get('http://github.com')
print(r.url)
print(r.status_code)
print(r.history)
print(type(r.history))
运行结果:
https://github.com/
200
[<Response [301]>]
<class 'list'>
>>>
可以看到,我们的URL由HTTP 请求重定向到 HTTPS
如果,想禁用重定向,可以这么做:
import requests
r = requests.get('http://github.com',allow_redirects=False)
print(r.url)
print(r.status_code)
print(r.history)
运行结果:
http://github.com/
301
[]
>>>
-
timeout : 设定超时时间,秒为单位
你可以告诉 requests 在经过以 timeout 参数设定的秒数时间之后停止等待响应,如果不使用,你的程序可能会永远失去响应
import requests
try:
requests.get('http://github.com', timeout=0.001)
except requests.exceptions.Timeout:
print('0.001秒内未响应,产生超时!')
运行结果:
0.001秒内未响应,产生超时!
>>>
timeout 仅对连接过程有效,与响应体的下载无关。 timeout 并不是整个下载响应的时间限制,而是如果服务器在 timeout 秒内没有应答,将会引发一个异常!
- 异常处理
遇到网络问题(如:DNS 查询失败、拒绝连接等)时,Requests 会抛出一个 ConnectionError
异常
如果 HTTP 请求返回了不成功的状态码, Response.raise_for_status()
会抛出一个 HTTPError
异常
若请求超时,则抛出一个 Timeout
异常
若请求超过了设定的最大重定向次数,则会抛出一个 TooManyRedirects
异常
所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException
- 爬取网页通用代码框架
import requests
def run():
try:
r = requests.get('http://github.com', timeout = 20)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except requests.exceptions.RequestException:
print('产生异常')
run()
-
Requests SSL 证书验证
Requests 可以为 HTTPS 请求验证 SSL 证书,就像 web 浏览器一样。SSL 验证默认是开启的,如果证书验证失败,Requests 会抛出 SSLError:
范例代码:
import requests
url = "https://inv-veri.chinatax.gov.cn/"
headers = {"User-Agent":"Mozilla/5.0"}
r = requests.get(url,headers = headers)
r.encoding = r.apparent_encoding
print(r.status_code)
print(r.text[:500])
运行结果:
SSLError
加上一个参数:verify=证书路径,或verify=False
import requests
url = "https://inv-veri.chinatax.gov.cn/"
headers = {"User-Agent":"Mozilla/5.0"}
r = requests.get(url,headers = headers,verify=False)
r.encoding = r.apparent_encoding
print(r.status_code)
print(r.text[:500])
运行结果:
在urllib3官方文档找到处理warning的方法
禁用SSL警告
通过urllib3设置禁用警告的方式来屏蔽这个警告:
import requests
import urllib3
urllib3.disable_warnings()
url = "https://inv-veri.chinatax.gov.cn/"
headers = {"User-Agent":"Mozilla/5.0"}
r = requests.get(url,headers = headers,verify=False)
r.encoding = r.apparent_encoding
print(r.status_code)
print(r.text[:500])
通过捕获警告到日志的方式忽略警告:
import requests
import logging
logging.captureWarnings(True)
url = "https://inv-veri.chinatax.gov.cn/"
headers = {"User-Agent":"Mozilla/5.0"}
r = requests.get(url,headers = headers,verify=False)
r.encoding = r.apparent_encoding
print(r.status_code)
print(r.text[:500])
运行结果:
- proxies : 字典类型,设定访问代理服务器
问题:为什么爬虫要使用代理?
- 让服务器认为我们
不是同一个客户端
在请求 - 防止我们的
真实地址
被泄露,防止被追究
根据协议类型,选择不同的代理
import requests
proxies= {
"http":"http://127.0.0.1:9999",
"https":"http://127.0.0.1:8888"
}
r = requests.get("http://www.baidu.com",proxies = proxies)
print(r)
proxies= {}内放一个就可以了
你可以使用IP池做随机数切换IP,否则使用单一IP意义不大
如果代理需要设置账户名和密码,只需要将字典更改为如下:
proxies = {
"http":"http://user:password@127.0.0.1:9999"
}
如果你的代理是通过sokces这种方式则需要pip install "requests[socks]"
proxies= {
"http":"socks5://127.0.0.1:9999",
"https":"sockes5://127.0.0.1:8888"
}
-
认证设置
如果碰到需要认证的网站需要添加 auth = (账户名, 密码)
import requests
r = requests.get("http://120.27.34.24:9001/",auth=("user","123"))
print(r.status_code)
-
Response属性
import requests
r = requests.get('http://httpbin.org/get')
print(r.status_code)
print(r.encoding)
print(r.apparent_encoding)
print(r.headers)
print(r.request.headers)
print(r.text)
print(r.content)
print(r.url)
print(r.cookies)
print(r.history)
>>>
阅读更多文章请点击以下链接:
python爬虫从入门到放弃之一:认识爬虫
python爬虫从入门到放弃之二:HTML基础
python爬虫从入门到放弃之三:爬虫的基本流程
python爬虫从入门到放弃之四:Requests库基础
python爬虫从入门到放弃之五:Requests库高级用法
python爬虫从入门到放弃之六:BeautifulSoup库
python爬虫从入门到放弃之七:正则表达式
python爬虫从入门到放弃之八:Xpath
python爬虫从入门到放弃之九:Json解析
python爬虫从入门到放弃之十:selenium库
python爬虫从入门到放弃之十一:定时发送邮件
python爬虫从入门到放弃之十二:多协程
python爬虫从入门到放弃之十三:Scrapy概念和流程
python爬虫从入门到放弃之十四:Scrapy入门使用
网友评论