python模块之requests模块

requests模块

主要就是使用python的内置模块urllib,模拟浏览器发送http请求,比起内置模块urllib,requests更加便捷

pip install requests

requests发送请求

请求类型

发送get请求和post请求:

import requests
requests.get('访问网址')
requests.post('访问网址')

携带参数和请求头

requests.get('网址?xxx=xxx&yyy=yyy')
requests.get('网址',params={'name':"lqz",'age':19})
requests.get('网址',headers={'cookies':"blabla","User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36'})

现在很多网站都有防爬意识,所以会在检测请求头和cookies等内容,来校验你是否是通过正常渠道来访问网站的,当然这种简单的防爬措施也容易绕过

url编码解码

请求参数中,如果是有中文,那么在地址栏中会做url的编码,如彭于晏:%E5%BD%AD%E4%BA%8E%E6%99%8F

这个编码在内置模块中可以通过

from urllib.parse import quote,unquote

print(quote('彭于晏'))  # url编码
print(unquote('%E5%BD%AD%E4%BA%8E%E6%99%8F'))  # url解码

携带请求体数据

携带请求体数据的方式有三种:

  • urlencoded
  • application/json
  • form-data
# urlencoded格式用data传
requests.get('网址',data={'query_id':"111111",'password':'sdfsdf='})

# json格式数据用json传
requests.post(url='网址',json={'xxx':'yyy'})

# 携带请求头,指定数据类型
requests.post(url='xxxx',
              data={'xx':1,},
              headers={
                  'content-type':'application/json'
              })

携带cookie

cookie其实也是作为请求头数据,只是浏览器会有自动程序对cookie做存储处理,所以比较重要,一般http相关的模块都会对其开设单独的方法。

cookies='从浏览器网路请求中复制过来'
requests.get('网址',cookies=cookies)

requests.session

session是requests的一个方法,它会产生一个session对象,继承了requests发送请求的方法。

并且会将响应数据中的cookies存储到session对象中,下一次再用session发送请求时,就会自动携带上次响应返回的cookies数据了,这种一般用于请求头中返回cookies信息的接口,如登录接口:

data = {
    'username': '',
    'password': '',
}
session = requests.session()
session.post('登录接口网址',data=data)
session.get('其他需要登录认证的网址')  # 自动将登录信息也携带了

响应对象Response

requests进行请求后,会得到一个响应对象的返回值,这个响应对象是一个Response对象,它有:

属性 含义
text 响应体的字符串
content 响应体的二进制
iter_content 二进制内容迭代对象(下载图片视频)
json() 有些http请求回来的是json数据,那么可以直接通过这个方法转成对应格式的数据
status_code 响应状态码
headers 响应头
cookies cookies属性
cookies.items() cookies的键值对
url 请求地址
history 重定向前的请求地址
encoding 响应编码格式

ps:Response的内容,凭借我们的经验,大概可以分为这几种:静态xml文件静态资源(各类文件)接口返的json数据

requests其他功能

ssl认证

http协议明文传输,而https协议其实就是http协议+ssl/tls协议

HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在HTTP与TCP之间)

简单来说ssl层为http传输增加了安全加密的属性,客户端和服务端传输之前,会让服务端将证书发给客户端查看,证书有误时,是否继续通讯由用户决定。

那么在我们使用requests发送请求时,会偶现一些网站没有证书或证书过期,则会给我们的批量请求带来不便。有以下几个方法解决此问题:

  • 不验证证书

    respone=requests.get('https://www.12306.cn',verify=False)
    
  • 关闭警告

    from requests.packages import urllib3
    urllib3.disable_warnings()
    
  • 手动携带证书(一般我们没有)

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

http协议的版本变化

  • 0.9:底层基于tcp,每次http请求,都是建立一个tcp连接,三次握手,请求结束需要四次挥手
  • 1.1:请求头中有个参数Keep-alive,会使三次握手后的tcp连接不断开,让多个http请求共用一个tcp连接
  • 2.x:多路复用,多个请求使用同一个数据包,再根据请求的id号归属响应,所以不同请求可以混杂在一起顺着一次传输进行交互。

目前来说1.1版本仍然是主流的http版本。

使用代理proxy*

客户端通过代理商向服务端发送请求时,会隐藏自己的个人ip,这种代理称为正向代理。我们在用同一个ip批量请求时,可能会触发网站的保护机制,封禁我们ip对网站的访问权限。

所以使用代理爬网站的信息,会安全一些。

res = requests.post('https://www.cnblogs.com',proxies={'http':'60.167.91.34:33080'})
# 键值对 http :代理ip+port , https :代理ip+port

客户端使用代理服务,一般需要上网找代理,有收费的和免费的。

高匿代理和透明代理

透明代理会在请求中携带请求头,X-Forwarded-For: client1, proxy1, proxy2, proxy3,这样服务端就可以拿到发起请求客户端的真实的ip,但现在一般都是高匿代理

搭建代理池

公司一般会花钱买代理池,但是我们也可以通过开源软件proxy_pool去建立免费的代理池:https://github.com/jhao104/proxy_pool

搭建步骤:

  1. git clone https://github.com/jhao104/proxy_pool.git

  2. pycharm打开安装依赖(IDE可能会自动安装)

  3. 修改配置文件中的redis地址(这个项目就是将爬取的免费代理存入redis)

  4. 爬取网上的免费代理

    python proxyPool.py schedule
    
  5. 启动代理池服务端(基于上一步爬到的代理池)

    python proxyPool.py server
    
  6. 地址栏输入对应路由

    http://127.0.0.1:5010/get/  # 随机返回一个代理
    http://127.0.0.1:5010/get/  # 获取所有的代理
    
  7. 使用随机代理发送请求

    import requests
    from requests.packages import urllib3
    urllib3.disable_warnings() #关闭警告
    # 获取代理
    res = requests.get('http://127.0.0.1:5010/get/').json()
    proxies = {}
    if res['https']:
        proxies['https'] = res['proxy']
    else:
        proxies['http'] = res['proxy']
    # 通过随机代理向cnblog发post请求
    res = requests.post('https://www.cnblogs.com', proxies=proxies,verify=False
    print(res)
    
  8. 将上述程序制作成一个循环,那么我们就可以不断的切换ip去获取网站的响应内容了

其他

参数 功能 演示
timeout 设定连接超时 requests.get('网址',timeout=0.01)
ConnectionError 连接异常 可以try...except捕获它
files 上传文件 requests.post('网址', files={'file':文件对象})

使用requests爬取视频网站视频

import requests
from requests.packages import urllib3
from bs4 import BeautifulSoup
from threading import Thread

urllib3.disable_warnings()

# 从本地挂起的代理池随机取出代理
def get_proxy():
    proxy_info = requests.get('http://127.0.0.1:5010/get/').json()
    proxies = {
        'https' if proxy_info['https'] else 'http': proxy_info['proxy']
    }
    return proxies

访问首页,搜集每条信息的id号

除了id号,有一些资源可能还有其他的标识,我们这里就用id号。

在进行翻页或者下拉时,网站一般会向后端服务器发请求拿数据,我们可以通过检测看到这些请求的网址规律

image

查看Response,或者我们拿请求url在地址栏再去请求,看拿到什么数据,这里是拿到了一些li标签,其中包括带网址的a标签,结合页面中点击进详情页,这个信息应当很重要。

image

# 循环请求,拿到多条视频详情的id号
video_id_list = []
for i in range(1, 4):  # 翻页取号
    response = requests.get(
        f'https://www.pearvideo.com/popular_loading.jsp?reqType=41&categoryId=&start={i * 10}&sort={i * 10}')
    soup = BeautifulSoup(response.text, 'lxml')
    a_labels = soup.select('li>a.actplay')
    video_id_list += [a_label.attrs['href'].split('_')[-1]
                      for a_label in a_labels]

根据id号,找到访问资源的请求接口

原思路是访问每个详情页,对视频资源请求的网址进行匹配整理,但是访问详情页,它其中的视频地址是通过再发ajax获取的,所以,我们要在network中找到这个ajax请求,对其进行规律探索,发现就是https://网址?contId={video_id},根据id号即可拼接得到。

而我们手动访问这个网址时,会发现response与它页面上ajax返回的json数据不一样,经过对比,发现原请求中多了一个请求头。

image

Referer:常见的反扒手段,会校验一下此请求之前的请求,所以我们携带这个请求头即可。

def download(video_id):
    proxy = get_proxy()
    # 请求视频信息的ajax请求,这个请求中,需要对Referer做校验
    url = f"https://www.pearvideo.com/videoStatus.jsp?contId={video_id}"
    res = requests.get(url, proxies=proxy, headers={
        'Referer': f'https://www.pearvideo.com/video_{video_id}'
    })
    # 返回的json数据中,有一个为访问视频的网址,并需要经过一定处理变成访问静态视频资源的网址
    src_url = res.json()['videoInfo']['videos']['srcUrl']
    src_url = src_url.replace(src_url.split('/')[-1].split('-')[0], f'cont-{video_id}')
    # 返回的网址:"https://video.pearvideo.com/mp4/adshort/20180517/1678962066841-12085786_adpkg-ad_hd.mp4"
	# 渲染的网址:"https://video.pearvideo.com/mp4/adshort/20180517/cont-1346772-12085786_adpkg-ad_hd.mp4"
    video = requests.get(src_url, proxies=proxy)
    # 存入本地
    with open(f"videos/{video_id}.mp4", 'wb') as f:
        for line in video.iter_content():
            f.write(line)

提交异步任务去下载

下载是IO操作,不占用cpu性能,所以用异步可以大大提高效率。

# download(video_id_list[0])

# 提交异步任务
for video_id in video_id_list:
    print(f'{video_id}正爬取中。。。')
    t = Thread(target=download, args=(video_id,))
    t.start()
posted @ 2023-03-15 17:28  leethon  阅读(152)  评论(0编辑  收藏  举报