了解urllib模块:
文档:urllib.note 链接:http://note.youdao.com/noteshare?id=df7416274cfb2e7a1feaf412fe7a5e93&sub=820D89C5C96741769347AC1FEA05F977
requests模块
学习目标:
掌握requests对应的response属性方法 掌握发送带headers请求及过滤headers中的键值对 掌握发送带参数的请求有两种方式
**作用:**发送http请求,获取响应数据
官方文档:https://requests.readthedocs.io/zh_CN/latest/index.html
requests模块是需要在你身上的第三方模块python在(虚拟)环境中额外安装 pip/pip3 install requests 源安装:pip install requests -i https://mirrors.aliyun.com/pypi/simple
1.requests模块发送get请求,获得响应
需求:通过requests向百度主页发送请求,获取页面源代码,观察输出结果
# 简单的代码实现 import requests # 目标url url = 'https://www.baidu.com' # 向目标url发送get请求 response = requests.get(url) # 打印响应内容 print(response.text)
2.response响应对象
观察上述代码的操作结果,发现有许多无序代码;这是由于编解码使用的字符集不同;我们试图使用以下方法来解决中文无序代码的问题
# response.content import requests # 目标url url = 'https://www.baidu.com' # 向目标url发送get请求 response = requests.get(url) # 打印响应内容 # print(response.text) print(response.content.decode()) # 注意这里!
- 网络传输的字符串都是bytes类型的,所以response.text = response.content.decode(‘推测编码字符集’)
- 我们可以在网页源码中搜索
charset
,试着参考编码字符集,注意不准确的情况
response.text 和response.content的区别:
- response.text
- 类型:str
- 解码类型: requests自动根据模块HTTP 头部对响应的编码进行了基本的推测,推测了文本编码
- response.content
- 类型:bytes
- 解码类型: 没有指定
通过对response.content进行decode,解决中文乱码
response.content.decode()
默认utf-8response.content.decode("GBK")
- 常见的编码字符集
- utf-8
- gbk
- gb2312
- ascii (发音:阿斯克码)
- iso-8859-1
3.response响应对象的其他常用属性或方法
response = requests.get(url)
中response是发送请求获得的响应对象;response响应对象中除了text、content除响应内容外,还有其他常用的属性或方法:
response.url
响应的url;有时响应url和请求的url并不一致response.status_code
响应状态码response.request.headers
响应相应的请求头response.headers
响应头response.request._cookies
响应相应的要求cookie;返回cookieJar类型response.cookies
响应的cookie(经过了set-cookie动作;返回cookieJar类型response.json()
自动将json字符串类型的响应内容转换为python对象(dict or list)
import requests # 发送请求,获取response响应 response = requests.get("http://www.baidu.com")
# 查看响应内容,response.text 返回的是str类型
print(response.text)
# 查看响应内容,response.content返回的字节流数据
print(respones.content)
# 查看响应的url地址
print(response.url)
# 查看响应头部字符编码
print(response.encoding)
# 查看响应状态码
print(response.status_code)
4.发送带header的请求
headers是一个字典
import requests
url = 'https://www.baidu.com'
response = requests.get(url)
print(response.content.decode()) # 源码内容获取不完整
# 打印响应对应请求的请求头信息
print(response.request.headers)
# -------------------------------------------分割线-------------------------------------------------------------
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
# 在请求头中带上User-Agent,模拟浏览器发送请求
response1 = requests.get(url, headers=headers)
print(response1.content.decode()) # 源码获取完整
# 打印请求头信息
print(response1.request.headers)
5.发送带参数的请求
我们在使用百度搜索的时候经常发现url地址中会有一个
?
,那么该问号后边的就是请求参数,又叫做查询字符串
1.在url携带参数
直接对含有参数的url发起请求
import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
url = 'https://www.baidu.com/s?wd=python'
response = requests.get(url, headers=headers)
print(response.content.decode())
2.通过params携带参数字典
1.构建请求参数字典
2.向接口发送请求的时候带上参数字典,参数字典设置给params
import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
# 这是目标url
# url = 'https://www.baidu.com/s?wd=python'
# 最后有没有问号结果都一样
url = 'https://www.baidu.com/s?'
# 请求参数是一个字典 即wd=python
kw = {
'wd': 'python'}
# 带上请求参数发起请求,获取响应
response = requests.get(url, headers=headers, params=kw)
print(response.content.decode())
3.关于参数的注意点
在url地址中,很多参数是没有用的,比如百度搜索的url地址,其中参数只有一个有用,其他的都可以删除
对应的,在后续的爬虫中,越到很多参数的url地址,都可以尝试删除参数
requests模块处理cookie相关的请求
网站经常利用请求头中的Cookie字段来做用户访问状态的保持,那么我们可以在headers参数中添加Cookie,模拟普通用户的请求
学习目标:
- 掌握 headers中携带cookie
- 掌握 cookies参数的使用
- 掌握 cookieJar的转换方法
后端请求过程
请求过程(原理)
第一次请求过程
1.我们的浏览器第一次请求服务器的时候,不会携带任何cookie信息
2.服务器接受到请求之后,发现 请求中没有任何cookie信息
3.服务器设置一个cookie信息,这个cookie设置在响应中
4.我们的浏览器接受到这个响应之后,发现响应中有cookie信息,浏览器会将这个cookie信息保存起来
第二次及其之后的请求过程
5.当我们的浏览器第二次及其之后的请求都会携带cookie信息,cookie信息是携带在请求头中的
6.我们的服务器接收到请求之后,发现请求中的cookie信息,就知道是谁的请求了
1.在headers参数中携带cookie
- 打开浏览器,右键-检查,点击Net work,勾选Preserve log
- 访问github登陆的url地址 https://movie.douban.com/
- 输入账号密码点击登陆后,刷新首页
- 确定url之后,再确定发送该请求所需要的请求头信息中的User-Agent和Cookie
import requests
url = 'https://movie.douban.com/'
# 构造请求头字典
headers = {
# 从浏览器中复制过来的User-Agent
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
# 从浏览器中复制过来的Cookie
'Cookie': 'xxx这里是复制过来的cookie字符串'
}
# 请求头参数字典中携带cookie字符串
resp = requests.get(url, headers=headers)
print(resp.text) # 在输出结果中,看到有用户信息,说明是获取登录之后的信息
总结:
带上cookie的好处:
能够访问登录后的页面
正常的浏览器在请求服务器的时候会带上cookie(第一次请求除外),所以对方服务器有可能会通过是否携带cookie来判断我们是否是一个爬虫,对应的能起到一定的反爬效果
带上cookie的坏处:
一套cookie往往对应的是一个用户的信息,请求太频繁有更大可能性被对方识别为爬虫
那么,面对这种情况如何解决---->使用多个账号
2.cookies参数的使用
-
cookies参数的形式:字典
cookies = { "cookie的name":"cookie的value"}
- 该字典对应请求头中Cookie字符串,以分号、空格分割每一对字典键值对
- 等号左边的是一个cookie的name,对应cookies字典的key
- 等号右边对应cookies字典的value
-
cookies参数的使用方法
response = requests.get(url, cookies)
-
将cookie字符串转换为cookies参数所需的字典:
cookies_dict = { cookie.split('=')[0]:cookie.split('=')[-1] for cookie in cookies_str.split('; ')}
-
注意:
import requests
url = 'https://movie.douban.com/'
# 构造请求头字典
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'
}
# 构造cookies字典
cookies_str = '从浏览器中copy过来的cookies字符串'
cookies_dict = {
cookie.split('=')[0]:cookie.split('=')[-1] for cookie in cookies_str.split('; ')}
# 请求头参数字典中携带cookie字符串
resp = requests.get(url, headers=headers, cookies=cookies_dict)
print(resp.text)
3.cookieJar对象转换为cookies字典的方法
使用requests获取的resposne对象,具有cookies属性。该属性值是一个cookieJar类型,包含了对方服务器设置在本地的cookie。我们如何将其转换为cookies字典呢?
requests.utils.dict_from_cookiejar 把cookiejar对象转化为字典
import requests
url = "https://www.baidu.com"
response = requests.get(url)
print(type(response.cookies) # cookiejar 类型
cookies = requests.utils.dict_from_cookiejar(response.cookies)
print(cookies) # 字典类型
在前面的requests的session类中,我们不需要处理cookie的任何细节,如果有需要,我们可以使用上述方法来解决
4. 超时参数的使用
在平时冲浪的过程中,我们经常会遇到网络波动,这个时候,一个请求等了很久可能任然没有结果。
对应的,在爬虫中,一个请求很久没有获取结果,就会让整个项目的效率变得非常低,这个时候,我们就需要对请求进行强制要求,让他必须在特定时间内返回结果,否则就报错
使用方法如下:
response = requests.get(url, timeout=3)
通过添加timeout参数,能够保证在3秒钟之类返回响应,否则就报错
这个方法还能用来检测IP代理的质量,如果一个代理IP在很长时间没有响应,那么添加超时参数,通过报错,达到筛选IP的目的
5. retrying模块的使用
上述方法能够加快我们整体的请求速度,但是在正常的网页浏览浏览过程中,如果发生速度很慢的情况,我们会点击刷新页面,那么,在代码中,我们是否也能刷新请求呢?
retrying模块的地址:https://pypi.org/project/retrying/
retrying模块的使用
使用retrying模块提供的retry方法
通过装饰器的方式使用,让被装饰的函数反复执行
retry中可以传入参数,stop_max_attempt_number让函数报错后继续重新执行,达到最大执行次数的上限,如果每次都报错,整个函数报错,如果中间有一个成功,程序继续往后执行
代码参考:
import requests
from retrying import retry
@retry(stop_max_attempt_number=3)
def _parse_url(url):
# 前面加_代表私有,这里代表私有方法,其他文件调用此包,此属性不能被调用
print('*' * 20)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Appl\
eWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"}
response = requests.get(url, headers=headers, timeout=3)
# 断言:状态码为200,否则报错
assert response.status_code == 200
return response.content.decode()
def parse_url(url):
try:
html_str = _parse_url(url)
except Exception as e:
print(e)
html_str = None
return html_str
if __name__ == '__main__':
# url = 'http://www.baidu.com'
url = 'www.baidu.com'
# print(parse_url(url)[:20]) # 字符串切片,取前二十个字符
print(parse_url(url))