手机版 欢迎访问it开发者社区(www.mfbz.cn)网站

当前位置: > 开发

使用Requests进行爬网

时间:2021/4/19 7:33:05|来源:|点击: 次

使用Requests进行爬网

一 HTTP协议

1.1 http协议概述

HTTPHyper Text Transfer Protocol(超文本传输协议)的缩写。HTTP是一个基于"请求与响应"模式的, 无状态的应用层协议。http协议在TCP/IP协议栈中的位置如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bv5uVWOn-1618788216403)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210418134854577.png)]

HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS, 默认HTTP的端口号为80,HTTPS的端口号为443.

1.2 http的请求响应模型

http协议永远都是客户端发起请求, 服务器回送响应. 如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yCqoeLNf-1618788216407)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210418135128431.png)]

http协议时一个无状态协议, 也就是说同一个客户端的这次请求和上次请求没有对应关系.

1.3 工作流程

一次http操作一般包括如下几步:

  1. 首先客户机与服务器建立连接.

  2. 客户机向服务器发送一个资源请求

  3. 服务器接到请求后, 给予相应的响应

  4. 客户端接收返回信息后进行解析

1.4 http请求方法

HTTP/1.1协议中共定义了八种方法(也叫“动作”)来以不同方式操作指定的资源, 下面是常用的请求方法:

方法说明
GET请求获取URL位置的资源
HEAD请求获取URL位置资源的响应消息报告, 即获得该资源的头部信息
POST请求向URL位置的资源后附件新的数据
PUT请求向URL位置存储一个资源, 覆盖原URL位置的资源
PATCH请求局部更新URL位置的资源, 即改变该处资源的部分内容
DELETE请求删除URL位置存储的资源

1.5 URL

URL(Uniform Resource Location) 统一资源定位符, 也就是网页地址. 是互联网上标准的资源的地址.

HTTP协议采用URL做为定位资源的标识.

1.5.1 URL格式

http://host[:port][path]

  • host: 合法的Internet主机域名或者IP地址.

  • port: 端口号, 缺省端口为80

  • path: 请求资源的路径

1.5.2 URL示例

https://www.cup.edu.cn/指的是中国石油大学(北京)的校园网主页.

https://www.cup.edu.cn/cise指的是中国石油大学(北京)这个主机域名下cise目录下的资源, 也就是信息科学与工程学院的主页

URL可以这样理解: 它是HTTP协议存取资源的Internet路径, 一个URL对应一个数据资源.

二 Requests库

Requests是Python的一个优雅而简单的HTTP库,是为人类构建的。通过requests可以非常容易的发送http/1.1请求, 不需要将查询字符串添加到url, 也不需要对post数据进行表单编码.

requests是一个第三方库, 因此要使用前必须进行安装. 建议大家使用anaconda集成环境, 里面已经安装了requests库及其依赖.

2.1 RequestResponse对象

无论何时调用requests.get()及其伙伴方法, 实际上都是正在做两件主要事情: 首先你正在构建一个Request对象, 它将被发送到服务器以便请求或查询一些资源. 其次, 一旦请求从服务器获得响应, 就会生成Response对象. 它包含服务器返回的所有信息, 还包含最初创建的Request对象.

下面是一个请求示例, 用来从https://httpbin.org获取一些信息:

>>> import requests
>>> r=requests.get("https://httpbin.org")

如果我们希望访问服务器返回的头部信息, 可以通过如下代码:

>>> r.headers
{'Date': 'Sun, 18 Apr 2021 11:15:57 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '9593', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}

然而, 如果我们想要获取发送给服务器的头部信息, 就要通过响应的request对象来访问了, 比如:

>>> r.request.headers
{'User-Agent': 'python-requests/2.19.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

2.2 主要接口

所有Requests的功能都可以通过7中方法访问. 它们都返回Response对象的一个实例. 其中requests.request()方法最为重要, 是所有其它6个方法的基础.

2.2.1 requests.request(method, url, **kwargs)

该方法用于构造和发送一个Request.

参数:

  • method: 也就是发送的HTTP请求, 可以是GET, HEAD, POST,PUT

  • url: HTTP请求的地址.

  • **kwargs: 控制访问的参数, 均为可选项

返回值:requests.Response

2.2.1.1 request控制参数

**kwargs一共有13个可选参数, 分别说明如下:

  • params: 字典或字节序列, 做为参数增加到url中.
>>> import requests
>>> r = requests.request('GET','https://httpbin.org', params={'key1':'val1', 'key2':'val2'})
>>> print(r.url)
https://httpbin.org/?key1=val1&key2=val2
  • data: 字典, 字节序列或文件对象, 做为Request的内容
>>> import requests
>>> r = requests.post('https://httpbin.org/post', data={'key':'value'})
>>> r = requests.post('https://httpbin.org/post', data='main content') 
  • json: JSON格式数据, 做为Request的内容
>>> import requests
>>> kv = {'key':"value"}
>>> r = requests.request('POST', 'http://python123.io/ws', json=kv)
  • headers: 字典, HTTP定制头
>>> hd={'user-agent': "Chrome/10"} # 浏览器伪装
>>> r = requests.request('POST', 'http://python123.io/ws', headers=hd)
>>> r.request.headers
{'user-agent': 'Chrome/10', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '0'}
  • cookies: 字典或CookieJar, Request中的cookie

  • auth: 元组, 支持HTTP认证功能.

  • files: 字典类型, 传输文件.

>>> fs = {'file': open('data.xls', 'rb')}
>>> r = requests.request('POST', 'http://python123.io/ws', files=fs)
  • timeout: 设定的超时时间, 秒为单位
>>> r = requests.request('GET', 'http://www.baidu.com', timeout=10)
  • proxies: 字典类型, 设定访问代理服务器, 可以增加登录认证, 使用代理可以增加反爬溯源的难度
>>> pxs = {'http': 'http://user:pass@10.10.10.1:1234', 'https':'https://10.10.10.1:4321'}
>>> r = requests.request('GET', 'http://www.baidu.com', proxies=pxs)
  • allow_redirects: True/False, 默认为True, 重定向开关

  • stream:True/False, 默认为True,获取内容立即下载开关

  • verify:True/False, 默认为True, 认证SSL证书开关

  • cert: 本地SSL证书路径

2.2.2 requests.get(url, params=None, **kwargs)

以HTTP的GET方式发起请求.

主要参数:

  • url: 拟获取页面的url链接

  • params: url中的额外参数, 字典或字节流格式, 可选

  • **kwargs: 12个控制范围参数参数

返回值:requests.Response

2.2.3 requests.head(url, **kwargs)

以HTTP的HEAD方式发起请求.

参数:

  • url: 拟获取页面的url链接

  • **kwargs: 13个访问控制参数

返回值:requests.Response

2.2.4 requests.post(url, data=None, json=None, **kwargs)

以HTTP的POST方式发起请求.

参数:

  • url: 拟获取页面的url链接

  • data: 字典, 字节序列或文件对象, 做为Request的内容

  • json: JSON格式数据, 做为Request的内容

  • **kwargs: 11个访问控制参数

返回值:requests.Response

2.2.5 requests.put(url, data=None, **kwargs)

以HTTP的PUT方式发起请求.

参数:

  • url: 拟获取页面的url链接

  • data: 字典, 字节序列或文件对象, 做为Request的内容

  • json: JSON格式数据, 做为Request的内容

  • **kwargs: 11个访问控制参数

返回值:requests.Response

2.2.6 requests.patch(url, data=None, **kwargs)

以HTTP的PATCH方式发起请求.

参数:

  • url: 拟获取页面的url链接

  • data: 字典, 字节序列或文件对象, 做为Request的内容

  • json: JSON格式数据, 做为Request的内容

  • **kwargs: 11个访问控制参数

返回值:requests.Response

2.2.7 requests.delete(url, **kwargs)

以HTTP的delete方式发起请求.

参数:

  • url: 拟获取页面的url链接

  • **kwargs: 13个访问控制参数

返回值:requests.Response

三 案例: 爬取慕课网所有免费课程的封面图片

通过打开网址https://www.imooc.com/course/list并且审查其中每一张图片地址的格式,然后确定图片地址的模式, 整个爬取代码如下:

import requests
import re

url = "https://www.imooc.com/course/list"
# 请求内容
try:
    r = requests.get(url)
    r.raise_for_status()
except:
    print("发生错误了!")

else:
    r.encoding = r.apparent_encoding

# 将内容保存在变量html中
html = r.text

# 使用正则表达式, 查找所有图片的地址
images=re.findall(r'//img\d\.mukewang\.com/\w+\.(?:png|jpg)', html)

# 构造完整的地址
images_url=['https:' + url for url in images]

i = 0
for url in images_url:
    # 截取图片文件的后缀
    prefix = re.search(r'\w{3}$',url).group()
    # 构造下载后图片文件存储位置, images提前建立好的
    filename = './images/{}.{}'.format(i,prefix)

    # 针对每一张图片,爬取其二进制内容, 并存入本地文件
    f = open(filename, 'wb')
    r = requests.get(url)
    f.write(r.content)
    f.close()

    i += 1

上述代码存在两个不尽人意的地方: 一是要提前建立本地存放图片的目录, 二是命名图片的时候引入了一个变量i.下面是针对这两个问题的优化代码:

import requests
import re
import os

url = "https://www.imooc.com/course/list"
# 请求内容
try:
    r = requests.get(url)
    r.raise_for_status()
except:
    print("发生错误了!")

else:
    r.encoding = r.apparent_encoding

# 将内容保存在变量html中
html = r.text

# 使用正则表达式, 查找所有图片的地址
images=re.findall(r'//img\d\.mukewang\.com/\w+\.(?:png|jpg)', html)

# 构造完整的地址
images_url=['https:' + url for url in images]

# 构造存放图片的目录
if not os.path.isdir('imgs'):
    os.mkdir('imgs')
else:
    os.chdir('./imgs')
    for f1 in os.listdir():
        os.remove(f1)
    os.chdir('..')

# 使用enumerate方法遍历列表
for i, url in enumerate(images_url):
    prefix = re.search(r'\w{3}$',url).group()
    filename = './imgs/{}.{}'.format(i,prefix)
    
    f = open(filename, 'wb')
    r = requests.get(url)
    f.write(r.content)
    f.close()

欢迎大家收看Python视频课程:https://www.bilibili.com/video/BV1sh411Q7mz

Copyright © 2002-2019 某某自媒体运营 版权所有