爬虫之requests模块

爬虫介绍

爬虫即模拟发送http请求获取数据。所以在学习爬虫时,需要熟悉http协议

爬虫的本质

  1. 模拟发送http请求
  2. 数据清洗反扒(有一些网站会有反扒手段,需要我们解决)
  3. 增加并发量(爬取的数据大时可以增加并发量加速爬取)
  4. 入库(保存数据)

爬虫协议

做爬虫要遵循爬虫协议:网站哪些让我们爬,哪些不让。

在网址后面输入/robots.txt就可以看到,比如B站的:

https://www.bilibili.com/robots.txt

requests模块介绍

requests模块可以模拟发送http请求获取网页内容或数据。

安装requests模块:

pip install requests

简单使用:get请求获取博客园首页的网页内容

import requests
# res是http响应封装成了对象,响应中得所有东西,都在这个对象中
res = requests.get('https://www.cnblogs.com/')
print(res.text)  # 网页数据

get请求

发送get请求,返回响应对象

res = requests.get('地址')
print(res.text)  # 响应体的数据

携带get参数

方式一:直接地址带参数

res = requests.get('地址?name=tom&age=18')

方式二:使用params参数

res = requests.get('地址', params={'name':'tom', 'age':18})

补充

有一些网址带有中文,复制出来会变成一串看不懂的字符串,这时候需要编码解码。

from urllib import parse

# 编码
res = parse.quote('博客园')
print(res)  # %E5%8D%9A%E5%AE%A2%E5%9B%AD

# 解码
res = parse.unquote('%E5%8D%9A%E5%AE%A2%E5%9B%AD')
print(res)  # 博客园

携带请求头

有些网站做了一些反扒手段,就比如必须是通过浏览器(客户端)发送的请求,而判断方法就是请求头中的user-agent(客户端类型)。

所以能不能爬取成功,就看你的请求模仿的像不像。

当被反扒了,一般都是打开网页,通过 f12-->网络 查看浏览器发送请求时携带了哪些重要参数,我们把这些重要参数加在我们的爬虫程序中。

image

常见请求头

  • user-agent:客户端类型
  • Referer:上一次访问的地址
  • Cookie:Cookie信息虽然包含在请求头里,但requests模块有单独的参数来处理他
  • ...
import requests

res = requests.get('地址', headers={'user-agent': 'Mozilla/5.0.....',})
print(res.text)

携带cookie

携带cookie一般都是用于操作登录用户,携带着说明登录了,这样能干登录的事。

import requests

res = requests.get('地址', cookies={'name': 'tom'})

post请求

基本使用

普通

import requests

res = requests.post('地址')

携带数据:默认数据格式为urlencoded

import requests

res = requests.post(
    '地址',
    data={
        'username': '',
        'password': '',
    }
)
# 数据格式是json格式
res=requests.post('地址',json={})

模拟登录流程

import requests

res = requests.post('地址', data={
    'username': '',
    'password': '',
})
print(res.cookies)  # 登录成功的cookie,cookieJar对象

# 登录成功,携带cookies
res1 = requests.get('地址', cookies=res.cookies)

requests.session

requests.session的使用,整个过程中自动维护cookie

import requests

session = requests.session()
# 使用session发送请求
session.post('地址', data={
    'username': '',
    'password': '',
})
res = session.get('地址')

文件上传

import requests
# 文件字典
files = {'file': open('a.jpg', 'rb')}
response = requests.post('地址', files=files)

response对象

各项属性

import requests

# 获取response对象
response = requests.get('https://www.cnblogs.com/')
print(response.text)  # 响应体的字符串
print(response.content)  # 响应体二进制数据
print(response.status_code)  # 响应状态码
print(response.headers)  # 响应头
print(response.cookies)  # 响应的cookie
print(response.cookies.get_dict())  # cookie转成dict
print(response.cookies.items())  # cookie拿出key和value
print(response.url)  # 请求的地址
print(response.history)  # 列表,有重定向,里面放了重定向之前的地址
print(response.encoding)  # 响应编码格式
print(response.iter_content)  # 响应体二进制数据生成器

res = requests.get('文件地址')
with open('xx', 'wb') as f:  # 保存文件
    for line in res.iter_content(chunk_size=1024):  # 按1024字节写
        f.write(line)

编码问题

大部分网站都是utf-8编码,老网站中文编码可能使用gbk,gb2312等,所以获取数据时需要将响应对象的编码格式改变。

import requests

response = requests.get('地址')
response.encoding = 'gbk'
print(response.text)  # 默认使用utf-8可能会导致中文乱码

获取二进制数据

import requests

response = requests.get('地址')

# 一次性写入
with open('xx', 'wb') as f:
    f.write(response.content)
# 分批写入
with open('xx', 'wb') as f: 
    for line in response.iter_content(chunk_size=1024):  # 按1024字节写
        f.write(line)

解析json

方式一:通过自带方法

import requests
response = requests.get('地址').json()

方式二:通过json模块

import requests
response = requests.get('地址')
import json
res = json.loads(response.text)

代理

我们在爬取网站数据时,如果频率过高,可能会被封ip,让我们无法访问,所以就需要用到代理,通过代理ip来访问网站。

手动获取代理

免费代理可以从这个网站获取:国内高匿免费HTTP代理IP - 快代理 (kuaidaili.com)

import requests
# 代理ip,有一些是http的,有一些是https的
proxies = {
    'http': '112.14.47.6:52024',
    # 'https': '112.14.47.6:52024',
}
response = requests.get('地址', proxies=proxies)
print(response.text)

代理池

代理池即有很多代理ip,每次随机从里面取出一个ip使用。

搭建

基于网上别人开源的代理池的python代码,自己搭建(本质是爬取的免费代理,验证)————GitHub - jhao104/proxy_pool: Python爬虫代理IP池(proxy pool)

第一步:下载开源项目,地址:GitHub - jhao104/proxy_pool: Python爬虫代理IP池(proxy pool)

第二步:打开项目,安装依赖:

pip install -r requirements.txt

第三步:配置配置文件(setting.py),redis数据库连接地址

DB_CONN = 'redis://127.0.0.1:6379/0'

第四步:启动项目:如果报错,那就是依赖的版本问题,具体问题具体分析。

爬虫程序(爬取代理ip地址)

python proxyPool.py schedule

web服务程序

python proxyPool.py server

获取代理ip:

http://127.0.0.1:5010/get/

代码中使用:

import requests
# 获取代理ip
res = requests.get('http://127.0.0.1:5010/get/').json()
# 判断代理ip是http还是https的
if res['https']:
    h = 'https'
else:
    h = 'http'

proxies = {
    h: res['proxy'],
}
# 通过代理ip发送请求
res1 = requests.get('地址', proxies=proxies)

超时与异常处理

超时设置

超过时间还没有收到响应就报错

import requests
response = requests.get('https://www.cnblogs.com/', timeout=0.01)

异常处理

import requests
from requests.exceptions import *

try:
    response = requests.get('http://www.baidu.com', timeout=0.00001)
except ReadTimeout:
    print('获取超时')
except ConnectionError:
    print('网络不通')
except Timeout:
    print('超时')
except Exception:
    print('请求失败')

爬取梨视频

# https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=5&start=0

import requests
import re

res = requests.get('https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=5&start=0')
# print(res.text)

video_list = re.findall('<a href="(.*?)" class="vervideo-lilink actplay">', res.text)
print(video_list)
# https://www.pearvideo.com/video_1768482
for video in video_list:
    video_id = video.split('_')[-1]
    video_url = 'https://www.pearvideo.com/' + video
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
        'Referer': video_url
    }
    res1 = requests.get('https://www.pearvideo.com/videoStatus.jsp?contId=%s&mrd=0.5602821872545047' % video_id,
                        headers=header
                        ).json()
    # print(res1['videoInfo']['videos']['srcUrl'])
    mp4_url = res1['videoInfo']['videos']['srcUrl']
    real_mp4_url = mp4_url.replace(mp4_url.split('/')[-1].split('-')[0], 'cont-%s' % video_id)
    print(real_mp4_url)
    # 下载视频
    res2 = requests.get(real_mp4_url)
    with open('video/%s.mp4' % video_id, 'wb') as f:
        for line in res2.iter_content(1024):
            f.write(line)
posted @ 2022-08-01 20:14  Yume_Minami  阅读(69)  评论(0编辑  收藏  举报