请求库之requests库
一 介绍
#介绍:使用requests可以模拟浏览器的请求,比起之前用到的urllib,requests模块的api更加便捷(本质就是封装了urllib3) #注意:requests库发送请求将网页内容下载下来以后,并不会执行js代码,这需要我们自己分析目标站点然后发起新的request请求 #安装:pip3 install requests #各种请求方式:常用的就是requests.get()和requests.post() >>> import requests >>> r = requests.get('https://api.github.com/events') >>> r = requests.post('http://httpbin.org/post', data = {'key':'value'}) >>> r = requests.put('http://httpbin.org/put', data = {'key':'value'}) >>> r = requests.delete('http://httpbin.org/delete') >>> r = requests.head('http://httpbin.org/get') >>> r = requests.options('http://httpbin.org/get') #建议在正式学习requests前,先熟悉下HTTP协议 http://www.cnblogs.com/linhaifeng/p/6266327.html
二 基于GET请求
1、基本请求
import requests response=requests.get('http://dig.chouti.com/') print(response.text)
2、请求地址带参数的GET请求->params
请求地址中携带数据(两种方式,推荐第二种)
方式一:
import requests header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36', } res=requests.get('https://www.baidu.com/s?wd=美女',headers=header) print(res.text)
方法二:通过params参数
import requests header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36', } res=requests.get('https://www.baidu.com/s',headers=header,params={'wd':'美女'}) print(res.url) # https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3 print(res.text)
如果就想把搜索的参数放在url中,最好用urlencode进行一下编码再进行拼接,如下:
#如果查询关键词是中文或者有其他特殊符号,则不得不进行url编码 import requests from urllib.parse import urlencode,unquote # url的编码和解码 wd='egon老师' # egon%E8%80%81%E5%B8%88 encode_res=urlencode({'k':wd},encoding='utf-8') keyword=encode_res.split('=')[1] print(keyword) # 然后拼接成url url='https://www.baidu.com/s?wd=%s&pn=1' %keyword response=requests.get(url, headers={ 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36', }) print(response.url) print(response.text)
3、带参数的GET请求->headers
#通常我们在发送请求时都需要带上请求头,请求头是将自身伪装成浏览器的关键,常见的有用的请求头如下 Host Referer #大型网站通常都会根据该参数判断请求的来源,例如防盗链 User-Agent #客户端 Cookie #Cookie信息虽然包含在请求头里,但requests模块有单独的参数来处理他,headers={}内就不要放它了
示例:添加User-Agent
#添加headers(浏览器会识别请求头,不加可能会被拒绝访问,比如访问https://www.zhihu.com/explore) import requests response=requests.get('https://www.zhihu.com/explore') response.status_code #500 #自己定制headers headers={ 'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36', } respone=requests.get('https://www.zhihu.com/explore', headers=headers) print(respone.status_code) #200
示例:解决防盗链的referer参数
import requests # 发送get请求 # res是python的对象,对象里,响应头,响应体。。。。 # referer用于图片防盗链 header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36', 'referer': 'https://www.mzitu.com/225078/2' } # res = requests.get('https://www.mzitu.com/', headers=header) # print(res.text) res = requests.get('https://i3.mmzztt.com/2020/03/14a02.jpg', headers=header) print(res.text) print(res.content) # 二进制内容 with open('a.jpg', 'wb')as f: for line in res.iter_content(): f.write(line)
4、带参数的GET请求->cookies
方式一:(不推荐)
import requests # 方式一,在header中放 header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36', 'cookie':'key=asdfasdfasdfsdfsaasdf;key2=asdfasdf;key3=asdfasdf' } res=requests.get('http://127.0.0.1:8000/index/',headers=header) print(res)
方式二:(推荐方式)
import requests # 方式二 header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36', } # cookies是一个字典或者CookieJar对象 res=requests.get('http://127.0.0.1:8000/index/',headers=header,cookies={'key':'asdfasdf'}) print(res.text) # 你的网站从request.COOKIES取出cookie来,
三 基于POST请求
1、介绍
#GET请求 HTTP默认的请求方法就是GET * 没有请求体 * 数据必须在1K之内! * GET请求数据会暴露在浏览器的地址栏中 GET请求常用的操作: 1. 在浏览器的地址栏中直接给出URL,那么就一定是GET请求 2. 点击页面上的超链接也一定是GET请求 3. 提交表单时,表单默认使用GET请求,但可以设置为POST #POST请求 (1). 数据不会出现在地址栏中 (2). 数据的大小没有上限 (3). 有请求体 (4). 请求体中如果存在中文,会使用URL编码! #!!!requests.post()用法与requests.get()完全一致,特殊的是requests.post()有一个data参数,用来存放请求体数据
2、发送post请求(携带的数据有urlencoded和json)
import requests # 没有指定请求头,但是用data传值,默认的请求头:application/x-www-form-urlencoded,服务端可以正常在request.POST和request.body中取到 # res = requests.post(url='http://127.0.0.1:8000/home/', # data={'name': 'alias'}) # print(res.text) # 如果我们自定义请求头是application/json,并且用data传值, 则服务端在request.POST取不到值,只能在request.body中取到值 # res = requests.post(url='http://127.0.0.1:8000/home/', # data={'name': 'alias'}, # headers={ # 'content-type': 'application/json' # }) # print(res) # 没有指定请求头,但是用json传值,默认的请求头:application/json,服务端在request.POST取不到值,只能在request.body中取到值 res = requests.post(url='http://127.0.0.1:8000/home/', json={'name': 'alias'}, ) print(res)
3 发送post请求,模拟浏览器的登录行为
#对于登录来说,应该输错用户名或密码然后分析抓包流程,用脑子想一想,输对了浏览器就跳转了,还分析个毛线,累死你也找不到包
自动登录github(自己处理cookie信息)
一 目标站点分析 浏览器输入https://github.com/login 然后输入错误的账号密码,抓包 发现登录行为是post提交到:https://github.com/session 而且请求头包含cookie 而且请求体包含: commit:Sign in utf8:✓ authenticity_token:lbI8IJCwGslZS8qJPnof5e7ZkCoSoMn6jmDTsL1r/m06NLyIbw7vCrpwrFAPzHMep3Tmf/TSJVoXWrvDZaVwxQ== login:egonlin password:123 二 流程分析 先GET:https://github.com/login拿到初始cookie与authenticity_token 返回POST:https://github.com/session, 带上初始cookie,带上请求体(authenticity_token,用户名,密码等) 最后拿到登录cookie ``` ps:如果密码时密文形式,则可以先输错账号,输对密码,然后到浏览器中拿到加密后的密码,github的密码是明文 ``` ''' import requests import re #第一次请求 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 #第二次请求:带着初始cookie和TOKEN发送POST请求给登录页面,带上账号密码 data={ 'commit':'Sign in', 'utf8':'✓', 'authenticity_token':authenticity_token, 'login':'317828332@qq.com', 'password':'alex3714' } r2=requests.post('https://github.com/session', data=data, cookies=r1_cookie ) login_cookie=r2.cookies.get_dict() #第三次请求:以后的登录,拿着login_cookie就可以,比如访问一些个人配置 r3=requests.get('https://github.com/settings/emails', cookies=login_cookie) print('317828332@qq.com' in r3.text) #True
实践示例:
import requests data = { 'username': '616564099@qq.com', 'password': 'lqz123', 'captcha': 'zdu4', 'remember': 1, 'ref': 'http://www.aa7a.cn/user.php?act=logout', 'act': 'act_login', } r1=requests.post('http://www.aa7a.cn/user.php',data=data) cookie = r1.cookies.get_dict() r2=requests.get('http://www.aa7a.cn/index.php', cookies=cookie) print('616564099@qq.com' in r2.text) #True
requests.session()自动帮我们保存cookie信息
import requests import re session=requests.session() #第一次请求 r1=session.get('https://github.com/login') authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN #第二次请求 data={ 'commit':'Sign in', 'utf8':'✓', 'authenticity_token':authenticity_token, 'login':'317828332@qq.com', 'password':'alex3714' } r2=session.post('https://github.com/session', data=data, ) #第三次请求 r3=session.get('https://github.com/settings/emails') print('317828332@qq.com' in r3.text) #True
四 响应Response对象
1、response对象属性
import requests respone=requests.get('http://127.0.0.1:8000/index/') # respone对象属性 print(respone.text) # text响应的文本 print(respone.content) # 响应体的二进制 print(respone.status_code) # 响应状态码 print(respone.headers) # 响应头 print(respone.cookies) # cookie print(respone.cookies.get_dict()) # 把cookie转成字典 print(respone.cookies.items()) # key和value print(respone.url) # 请求的url print(respone.history) #[],一个列表放重定向之前的地址 print(respone.encoding) # 响应的编码方式 respone.iter_content() # 图片,视频,大文件,一点一点循环取出来 # 例如: with open('a.jpg', 'wb')as f: for line in res.iter_content(): f.write(line)
2、编码问题
import requests res=requests.get('http://www.autohome.com/news') # 一旦打印出来出现乱码问题 # 方式一:知道网址编码格式,手动指定编码格式 res.encoding='gb2312' # 方式二:如果不知道网址编码格式,通过apparent_encoding自动获取 # res.encoding=res.apparent_encoding print(res.text)
3、获取二进制数据
import requests response=requests.get('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1509868306530&di=712e4ef3ab258b36e9f4b48e85a81c9d&imgtype=0&src=http%3A%2F%2Fc.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F11385343fbf2b211e1fb58a1c08065380dd78e0c.jpg') with open('a.jpg','wb') as f: f.write(response.content)
获取二进制流:
#stream参数:一点一点的取,比如下载视频时,如果视频100G,用response.content然后一下子写到文件中是不合理的 import requests response=requests.get('https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo-transcode/1767502_56ec685f9c7ec542eeaf6eac93a65dc7_6fe25cd1347c_3.mp4', stream=True) with open('b.mp4','wb') as f: for line in response.iter_content(): f.write(line)
4、解析json
#解析json import requests import json respone=requests.post('http://127.0.0.1:8000/index/',data={'name':'lqz'}) # print(type(respone.text)) # 响应的文本,json格式字符串,{"name","lqz","age",18} # print(json.loads(respone.text)) print(respone.json()) # 相当于上面的loads print(type(respone.json())) # dict
5、Redirection and History
官网解释:
By default Requests will perform location redirection for all verbs except HEAD. We can use the history property of the Response object to track redirection. The Response.history list contains the Response objects that were created in order to complete the request. The list is sorted from the oldest to the most recent response. For example, GitHub redirects all HTTP requests to HTTPS: >>> r = requests.get('http://github.com') >>> r.url 'https://github.com/' >>> r.status_code 200 >>> r.history [<Response [301]>] If you're using GET, OPTIONS, POST, PUT, PATCH or DELETE, you can disable redirection handling with the allow_redirects parameter: >>> r = requests.get('http://github.com', allow_redirects=False) >>> r.status_code 301 >>> r.history [] If you're using HEAD, you can enable redirection as well: >>> r = requests.head('http://github.com', allow_redirects=True) >>> r.url 'https://github.com/' >>> r.history [<Response [301]>]
示例:
import requests import re #第一次请求 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 #第二次请求:带着初始cookie和TOKEN发送POST请求给登录页面,带上账号密码 data={ 'commit':'Sign in', 'utf8':'✓', 'authenticity_token':authenticity_token, 'login':'317828332@qq.com', 'password':'alex3714' } #测试一:没有指定allow_redirects=False,则响应头中出现Location就跳转到新页面,r2代表新页面的response r2=requests.post('https://github.com/session', data=data, cookies=r1_cookie ) print(r2.status_code) #200 print(r2.url) #看到的是跳转后的页面 print(r2.history) #看到的是跳转前的response print(r2.history[0].text) #看到的是跳转前的response.text #测试二:指定allow_redirects=False,则响应头中即便出现Location也不会跳转到新页面,r2代表的仍然是老页面的response r2=requests.post('https://github.com/session', data=data, cookies=r1_cookie, allow_redirects=False ) print(r2.status_code) #302 print(r2.url) #看到的是跳转前的页面https://github.com/session print(r2.history) #[]
五 高级用法
1、SSL Cert Verification
#证书验证(大部分网站都是https) import requests respone=requests.get('https://www.12306.cn') #如果是ssl请求,首先检查证书是否合法,不合法则报错,程序终端 #改进1:去掉报错,但是会报警告 import requests respone=requests.get('https://www.12306.cn',verify=False) #不验证证书,报警告,返回200 print(respone.status_code) #改进2:去掉报错,并且去掉警报信息 import requests from requests.packages import urllib3 urllib3.disable_warnings() #关闭警告 respone=requests.get('https://www.12306.cn',verify=False) print(respone.status_code) #改进3:加上证书 #很多网站都是https,但是不用证书也可以访问,大多数情况都是可以携带也可以不携带证书 #知乎\百度等都是可带可不带 #有硬性要求的,则必须带,比如对于定向的用户,拿到证书后才有权限访问某个特定网站 import requests respone=requests.get('https://www.12306.cn', cert=('/path/server.crt', '/path/key')) print(respone.status_code)
2、使用代理
#网上免费代理: http://www.goubanjia.com/ #代理设置:先发送请求给代理,然后由代理帮忙发送(封ip是常见的事情) import requests # 代理,免费代理,收费代理花钱买 # 代理池:列表放了一堆代理ip,每次随机取一个,再发请求就不会封ip了 # 高匿和透明代理?如果使用高匿代理,后端无论如何拿不到你的ip,使用透明,后端能够拿到你的ip # 后端如何拿到使用透明代理的ip的真正访问者, 后端:request.META中的HTTP_X_FORWARDED_FOR参数 proxies={ # 'http':'http://egon:123@localhost:9743',#带用户名密码的代理,@符号前是用户名与密码,没有用户名和密码就不填 'http':'http://61.163.32.88:3128', 'https':'183.166.21.202:9999', } respone=requests.get('https://www.12306.cn', proxies=proxies) print(respone.status_code) #支持socks代理,安装:pip install requests[socks] import requests proxies = { 'http': 'socks5://user:pass@host:port', 'https': 'socks5://user:pass@host:port' } respone=requests.get('https://www.12306.cn', proxies=proxies) print(respone.status_code)
3、超时设置
#超时设置 #两种超时:float or tuple #timeout=0.1 #代表接收数据的超时时间 #timeout=(0.1,0.2)#0.1代表链接超时 0.2代表接收数据的超时时间 import requests respone=requests.get('https://www.baidu.com', timeout=0.0001)
4、 认证设置(现在网址基本不用了,以前老的路由器登录页面(弹窗式的))
#官网链接:http://docs.python-requests.org/en/master/user/authentication/ #认证设置:登陆网站是,弹出一个框,要求你输入用户名密码(与alter很类似),此时是无法获取html的 # 但本质原理是拼接成请求头发送 # r.headers['Authorization'] = _basic_auth_str(self.username, self.password) # 一般的网站都不用默认的加密方式,都是自己写 # 那么我们就需要按照网站的加密方式,自己写一个类似于_basic_auth_str的方法 # 得到加密字符串后添加到请求头 # r.headers['Authorization'] =func('.....') #看一看默认的加密方式吧,通常网站都不会用默认的加密设置 import requests from requests.auth import HTTPBasicAuth r=requests.get('xxx',auth=HTTPBasicAuth('user','password')) print(r.status_code) #HTTPBasicAuth可以简写为如下格式 import requests r=requests.get('xxx',auth=('user','password')) print(r.status_code)
5、异常处理
#异常处理 import requests from requests.exceptions import * #可以查看requests.exceptions获取异常类型 try: r=requests.get('http://www.baidu.com',timeout=0.00001) # except ReadTimeout: # print('===:') except Exception as e: # 总的异常 print(e)
6、上传文件
import requests files={'file':open('a.jpg','rb')} respone=requests.post('http://127.0.0.1:8000/index/',files=files) print(respone.status_code) print(respone.text)
练习
import requests data = { 'username': '616564099@qq.com', 'password': 'lqz123', 'captcha': 'zdu4', 'remember': 1, 'ref': 'http://www.aa7a.cn/user.php?act=logout', 'act': 'act_login', } rest = requests.post('http://www.aa7a.cn/user.php',data=data) print(rest.text) # 拿到cookie cookie=rest.cookies print(cookie) # 携带着cookies,表示登录了,页面中会有我们的用户信息616564099@qq.com rest1=requests.get('http://www.aa7a.cn/index.php',cookies=cookie) # rest1=requests.get('http://www.aa7a.cn/index.php') print('616564099@qq.com' in rest1.text)
使用session
#http://www.aa7a.cn/ import requests session = requests.session() data = { 'username': '616564099@qq.com', 'password': 'lqz123', 'captcha': 'zdu4', 'remember': 1, 'ref': 'http://www.aa7a.cn/user.php?act=logout', 'act': 'act_login', } rest = session.post('http://www.aa7a.cn/user.php',data=data) # 携带着cookies,表示登录了,页面中会有我们的用户信息616564099@qq.com rest1=session.get('http://www.aa7a.cn/index.php') # rest1=requests.get('http://www.aa7a.cn/index.php') print('616564099@qq.com' in rest1.text)
爬取梨视频
import requests import re import time # 爬取梨视频 for i in range(0,25,12): reponse = requests.get('https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=1&start=%s' %i) # print(reponse.text) re_video = '<a href="(.*?)" class="vervideo-lilink actplay">' video_urls = re.findall(re_video, reponse.text) # print(video_urls) # 获取到的是一个列表,然后进行拼接 # https://www.pearvideo.com/ # print(video_urls) for video in video_urls: url = 'https://www.pearvideo.com/' + video # print(url) time.sleep(0.3) # 向视频详情发送get请求 res_video = requests.get(url) re_video_mp4 = 'hdUrl="",sdUrl="",ldUrl="",srcUrl="(.*?)",vdoUrl=srcUrl,skinRes' video_url = re.findall(re_video_mp4, res_video.text)[0] print(video_url) video_name = video_url.rsplit('/', 1)[-1] # print(video_name) res_video_content = requests.get(video_url) with open('video_p/%s'%video_name, 'wb') as f: for line in res_video_content.iter_content(): f.write(line)