昨日内容回顾
-
标签的两大属性
id class
-
列表标签
页面上有规则排列的横向或者纵向布局一般使用的都是无序列表 无序列表 ul li 有序列表 标题列表
-
表格标签
类似于excel表格一样 用于展示数据 table thead 表头 tr 一行 th 字段名称 tbody 表单 tr 一行 td 字段数据
-
表单标签
用于获取用户数据并提交给后端服务器 input标签 type属性 text password email radio checkbox file date submit reset button select标签 option子标签 textarea标签 获取大段文本内容 """ 获取用户数据的标签一般都有name属性 类似于字典的key 用户输入的数据会自动传入标签的value属性中 类似于字典的value 你可以理解为在发送数据的时候form表单会自动构造成字典的形式发送 """
-
requests模块
能够模拟网络请求获取页面数据 但是不支持执行js代码 pip3 install requests # 发送get请求 res = requests.get(url) # 响应状态码 res.status_code # 文本内容 res.text # 二进制数据 res.content # 指定编码 res.encoding # url问号后面如何携带参数 res = requests.get(url,params={'k':'v'}) # url?k=v # 携带定制请求头数据 res = requests.get(url,headers={}) """ 防爬措施 1.校验当前请求是否由浏览器发出 通过请求头里面的User-Agent参数 我们只需要在代码的请求头中加上该参数即可 """ # 携带cookie数据 res = requests.get(url,cookies={})
-
cookie与session
HTTP协议 无状态 的特性导致了上述技术的产生 cookie 服务端让客户端浏览器保存的数据 session 服务端保存的用户相关的数据 """ 客户端浏览器保存随机字符串 服务端保存用户数据 """ # session需要依赖于cookie才能工作(目前所有的网址都是依赖于cookie做用户登录相关的保存状态类功能)
今日内容概要
-
发送post请求
有些网址的数据必须是登录之后的用户才可以查看 同理我们的爬虫需要也必须登录之后才能爬取 也就意味着我们需要在代码层面上完成用户登录的操作
-
代码模拟登录
post请求结合cookie操作
-
获取文件数据
-
json格式数据(重要)
-
防爬措施补充(重要)
-
bs4数据筛选模块
可以理解为是内部封装了正则表达式的模块
今日内容详细
发送post请求
res = requests.post(url)
# 请求体数据
res = requests.post(url,data={...})
模拟登录
"""
1.先用浏览器正常登录
获取登录数据提交的地址(到底提交到哪儿)
2.post请求用户提交的数据存放在哪里发送给服务端的
存放在请求体里面(构造浏览器请求体一样的数据结构)
3.通过代码模拟发送用户数据
正确之后需要获取服务端发送过来的cookie数据
4.保存cookie用于后续的登录
代码携带cookie需要是字典格式 而服务端返回的cookie却不是字典
所以需要我们自己处理一下
"""
提交地址:http://www.aa7a.cn/user.php
请求体数据格式:
username: 616564099@qq.com
password: 213213213
captcha: hr53
remember: 1
ref: http://www.aa7a.cn/
act: act_login
正确的用户名密码得到的cookie数据
<RequestsCookieJar[<Cookie ECS[password]=4a5e6ce9d1aba9de9b31abdf303bbdc2 for www.aa7a.cn/>, <Cookie ECS[user_id]=61399 for www.aa7a.cn/>, <Cookie ECS[username]=616564099%40qq.com for www.aa7a.cn/>, <Cookie ECS[visit_times]=1 for www.aa7a.cn/>, <Cookie ECS_ID=a6326573338371fecd25866bc57f0f59226d9d43 for www.aa7a.cn/>]>
错误的用户名密码得到的cookie数据
<RequestsCookieJar[<Cookie ECS[visit_times]=1 for www.aa7a.cn/>, <Cookie ECS_ID=170d24ff87ba9fce1b6920b85b5e7b534fd320a8 for www.aa7a.cn/>]>
模拟登录代码
import requests
res = requests.post('http://www.aa7a.cn/user.php',
data={
"username": "616564099@qq.com",
"password": "lqz123",
"captcha": "hr53",
"remember": 1,
"ref": "http://www.aa7a.cn/",
"act": "act_login"
}
)
# print(res.cookies) # 获取原生的cookie数据
# print(res.cookies.get_dict()) # 获取处理成字典的cookie数据
user_cookie = res.cookies.get_dict()
"""
获取到的字典数据 可以保存到文件中 之后直接读取文件内容即可
但是我们之前学习的文件操作只能读写字符串内容或者二进制
"""
res = requests.get('http://www.aa7a.cn/',cookies=user_cookie)
"""
代码层面如何判断当前请求是否登录???
"""
if '616564099@qq.com' in res.text:
print('登录状态访问')
else:
print('非登录状态访问')
json格式数据
序列化
将非字符串类型的数据转换成字符串(json格式字符串)
# 普通字符串与json格式字符串的区别
json格式字符串所有的引号都是双引号
也只有json格式的数据引号才会是双引号
json格式字符串能否打破语言限制 实现不同编程语言之间的数据交互
import json
user_dict = {
"username":"jason",
"password":123
}
# with open(r'a.txt','w',encoding='utf8') as f:
# json.dump(user_dict,f)
with open(r'a.txt','r',encoding='utf8') as f:
res = json.load(f)
print(res,type(res))
print(user_dict)
# 单纯的转字符串 不是序列化
res = str(user_dict)
print(res,type(res)) # {'username': 'jason', 'password': 123} <class 'str'>
res = json.dumps(user_dict) # 序列化
print(res,type(res)) # {"username": "jason", "password": 123} <class 'str'>
res1 = json.loads(res) # 反序列化
print(res1,type(res1)) # {'username': 'jason', 'password': 123} <class 'dict'>
反序列
将json格式字符串反序列化成某一门编程语言里面某个具体的数据类型
获取较大数据
读取方式与我们之前学习的文件操作一致 都是一行行读取防止内存溢出(爆了)
res = request.get(url,stream=True)
for i in res.iter_content(): # 一行行读取
pass
#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)
'''
防爬措施
1.请求头User-Agent
校验是否是一个浏览器
解决措施:请求头加上即可
2.请求头referer
校验当前请求从何而来
解决措施:请求头加上即可
3.IP访问次数限制
在限定的时间内访问次数不能超标
解决措施
1.程序层面加time.sleep()主动阻塞
import time
for i in range(10):
time.sleep(3)
print(i)
2.IP代理池(重要)
提前准备好一堆IP地址 发送请求的时候每次都随机从池子里面
获取一个地址
直接去第三方获取使用即可 分为免费的和收费的
免费的IP可能无效甚至响应较慢
收费的IP基本都有效并且速度快 还可以自定义地区等数据
requests.get(url,proxies={
'http':'ip地址1',
'http':'ip地址2',
'http':'ip地址3',
...
})
4.cookie访问次数限制
在限定的时间内访问次数不能超标
解决措施
1.程序层面加time.sleep()主动阻塞
2.Cookie代理池(重要)
先使用很多账户密码登录获取对应的cookie
然后全部保存起来 之后每次请求携带不同的cookie数据即可
没有第三方服务需要自己制作代理池
异常处理
我们在写代码的时候可能会出现某一段代码不知道会不会报错的情况
但是我们又不想它报错 那么就可以使用异常处理提前制定好报错之后的解决方案
异常的分类
语法错误
不能被允许 遇到立刻修改
逻辑错误
可以被允许
如何处理逻辑错误
try:
可能会出错的代码
except 错误的类型:
错误的解决措施
bug三个区域
Traceback (most recent call last):
File "D:/数据分析五期/pa_day03/05 异常处理.py", line 15, in <module> # 1.代码出错的文件位置
NameError: name 'name' is not defined
# 2.错误的类型 # 3.错误的详细信息
# 万能异常
try:
# name
l[100]
except Exception as e: # e就是错误的详细信息
print('任何错误都逃不过我的眼睛')
"""
try的子代码要尽可能的少 因为异常处理也是需要消耗资源的
过多的时候会影响程序的效率
"""
解析库之BS4
去网页中筛选出我们需要的数据 操作方法非常简单
下载
pip3 install beautifulsoup4
还需要配套下载解析器
pip3 install lxml
导入
from bs4 import BeautifulSoup
基本使用
from bs4 import BeautifulSoup
# 假设下述文档就是通过网络请求获取到的HTML页面
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" id="p1">111
<b>The Dormouse's story</b>
</p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
# 1.先生成一个soup对象
soup = BeautifulSoup(html_doc,'lxml')
# 2.基于soup对象调用各式方法
#2、获取所有的a标签
# print(soup.find_all(name='a')) # 列表套一个个标签对象
# 获取页面上第一个a标签
# print(soup.a)
# print(soup.find_all(name='a')[0])
# print(soup.find(name='a')) # 从上往下找到一个就结束
#3、获取标签的属性
# print(soup.p.get('class')) # get指名道姓的获取对应属性的值
# print(soup.p.attrs) # 获取标签所有的属性名和属性值 字典形式
#4、获取标签的内容
# print(soup.p.text) # 包含了内部所有子标签的文本
#5、嵌套选择
# print(soup.p.b.text) # 连续的点表示拿对应的内部第一个标签
#6、子节点、子孙节点
# print(soup.p.children)
for i in soup.find_all(name='p')[1].children:
print(i)
#7、父节点、祖先节点
#8、兄弟节点
"""
<div>
<span>是div的儿子 是p的哥哥</span>
<p>是div的儿子 是内部span的父亲
<span>是p的儿子 是div的孙子</span>
</p>
<span>是div的儿子 是p的弟弟</span>
</div>
"""
作业
1.整理今日内容
2.使用bs4解析抽屉网
比如获取所有的a标签 所有的链接地址等等
3.尝试寻找其他网址实现模拟登录 如果找不到类似的则将课上的重新写一遍