首页 > 技术文章 > 爬虫与防爬

kailun-aixuexi 2021-01-18 12:27 原文

昨日内容回顾

  • requests模块

    1.一个第三方模块
    2.该模块的功能是可以模仿浏览器朝服务端
    3.不支持执行js代码和css信息,只支持http的代码运行
    
  • HTTP协议

    规定了浏览器与服务端交互的原则
    	1.四大特性
        	1.基于tcp.ip应用层之上的协议运行
            2.基于请求响应
            3.无状态
            	不保存用户状态
            4.无/短连接
            	交互后直接断开
    # 长连接
        2.数据格式
        	请求数据格式
            	请求首行(请求方法,协议版本)
                请求头(一堆K:V键值对)
                (空格)    
               请求体(敏感数据)     
            响应数据格式
        3.响应状态码
    用一串数字表示浏览器与服务端访问状态的结构
    	1XX
        2XX
        3XX
        4XX
        5XX
    # 有很多公司有自己的状态码
    # 前端与后端 用户直接接触到的就是前端,我们打代码处理的就是后端
    
  • requests模块其他方法

    # 发送网络请求
    requests.get()
    requests.post()
    
    # 发送get请求携带额外的参数
    requests.get(url,params={K:V,K:V...})
    
    # 发送请求携带请求头
    requests.post(url,headers={K:V,...})
    
    # 发送请求携带cookie
    requsets.get(url,cookies={K:V,...})
    
  • cookie与session

    cookie与session都是为了解决掉HTTP协议中无状态产生的
    cookie是将用户的密码和账号记录在浏览器上,让用户不用每次访问浏览器都是需要输入账户和密码
    

session是将用户的信息记录在服务端,服务端将一串特殊符号组合成的代码送给浏览器cookie用作身份信息,记录登录状态




# 今日内容概要

- 利用cookie模拟登陆

- requests其他方法

- json格式

- 简单的防爬措施

```python
#user-agent	
网站会验证是够是一个浏览器访问网页,既请求头,在请求中加入浏览器的请求头即可
#referer		
referer会标记求情数据的网址来源,将其加入post请求之中
#IP代理池	
网站会检验同一个ip在网站上限制时间内的访问次数,如果超过一个制表认为是爬虫软件加以限制
# cookie代理池	
网站会检验同一个ip在网站上限制时间内的访问次数,如果超过一个制表认为是爬虫软件加以限制(这个会封账号=-=)

今日内容详细

利用cookie模拟登陆

# 使用代码模拟登录
华华手机为例
	1.先用浏览器登录
    	查看登录的接口地址(查找数据往哪个地址提交的)
        具体思路:
        	1.打开登录页面
            2.随意填写用户名和密码
            3.左键打开浏览器装懂点击network查看请求
基于上述思路成功获取到接收用户数据的地址:http://www.aa7a.cn/user.php
也就是说我们以后通过代码直接朝上述地址发送请求即可

	2.由于post请求数据是放在请求体中的
    	查看花花手机登录接口数据格式
        具体思路:
        	1.打开登录页面
            2.随意填写用户名和密码
            3.左键打开浏览器装懂点击network查看请求
基于上述思路成功获取到请求体数据格式,也就意味着一会儿我们通过代码模仿构造出一样的数据格式提交即可

requests.post(url="http://www.aa7a.cn/user.php",
# 请求头
	data={
    username:156485484
    password:5151
    captcha:cez3
    remember:1
    ref:http://www.aa7a.cn/category-39-b0.html
    act:act_login

},
     heards={"user-agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36"
)}
# 获取服务端返回的cookie数据
my_cookies = res.cookies.get_dict()
print(my_cookies)
用户名密码正确的情况下
{
'ECS[password]': '4a5e6ce9d1aba9de9b31abdf303bbdc2', 
'ECS[user_id]': '61399', 
'ECS[username]': '616564099%40qq.com', 
'ECS[visit_times]': '1', 
'ECS_ID': '65656a64e702189c8dfacb53a85499d9812ac86f'
}

用户名或密码错误的情况下
{'ECS[visit_times]': '1', 'ECS_ID': 'e64fb781313753b0f99731e6d9dab8a70cf39885'}
"""
# 携带cookie访问网站 验证是否有效
res = requests.get('http://www.aa7a.cn/',
                   headers={
                       "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
                   },
                   cookies={
                       'ECS[password]': '4a5e6ce9d1aba9de9b31abdf303bbdc2',
                       'ECS[user_id]': '61399',
                       'ECS[username]': '616564099%40qq.com',
                       'ECS[visit_times]': '1',
                       'ECS_ID': '65656a64e702189c8dfacb53a85499d9812ac86f'
                   }
                   )
# 如何校验是否登录呢?
if '616564099@qq.com' in res.text:
    print("登录状态访问")
else:
    print("未登录状态访问")

防爬措施

1.referer  用来标记当前请求从何而来,既数据请求源来自哪的网址
	eg:
        图片防盗链
        当请求发送到服务端之后,服务端可以先校验请求头里面的referer鉴别当前请求是否是本网站发出的,如果是那么直接给相应的资源如果不是那么可以拒绝
        
Referer:http://www.aa7a.cn/user.php?&ref=http%3A%2F%2Fwww.aa7a.cn%2Fcategory-39-b0.html

获取大文件数据

当我们基于网络请求到的数据量特别大的情况下
如果我们直接使用res.text或者res.content可能会导致计算机内存的溢出(原地爆炸)

#stream参数:一点一点的取,比如下载视频时,如果视频100G,用response.content然后一下子写到文件中是不合理的

import requests

res=requests.get('https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo-transcode/1767502_56ec685f9c7ec542eeaf6eac93a65dc7_6fe25cd1347c_3.mp4',
                      stream=True)

with open(r'hhsj.txt','wb') as f:
    for line in res.iter_content():
        f.write(line)
print(type(res))

json格式

# 内置模块无需下载
json格式是用来实现不用语言之间的数据传输
最常用的就是python与JavaScript之间的前后端数据交互

json格式长的跟我们python里面的字典非常相似
只不过json格式的数据内部必须都是双引号

d = {"username": "jason", "password": "123"}


import json
# 将字典d转换成json格式的字符串
res = json.dumps(d)  # 序列化
# print(res,type(res))
# 将json格式的字符串转换成python中的字典
res1 = json.loads(res)  # 反序列
print(res1,type(res1))


"""
序列化:将python中的数据类型转换成json格式的字符串
反序列化:将json格式的字符串转换成python中的数据类型
"""
# 前后端数据交互一般都是采用json格式

代理池

1.IP代理池
	ip地址:每一台接入互联网的计算机都会有一个ip地址,ip地址相当于是身份证号,我们通过ip地址就可以明确的查找到互联网上面的某一台计算机
     防爬措施
    	服务端有时候也会校验IP地址
        	在规定的一个时间范围内,某一个ip地址访问网站的次数不能超过限定的次数,如果超过了直接封禁(2小时、半个月、终身)
        解决措施
        	采用IP代理池
            	免费
                收费
        	http://www.taiyanghttp.com/free/
   		代码实现
        	import requests
            proxies = {
                'http': '221.10.217.26:4261',
                'http': '110.88.31.173:4278',
                'http': '218.6.105.99:4206',
            }
            respone = requests.get('https://www.12306.cn',
                                   proxies=proxies)
            print(respone.status_code)
            
2.cookie代理池
	服务端有时候也会校验cookie数据
        	在规定的一个时间范围内,某一个cookie访问网站的次数不能超过限定的次数,如果超过了直接封禁账号(2小时、半个月、终身)
        解决方案:
            先提前使用N多个账号登录该网站获取对应的cookie数据并保存起来
            之后每一次访问的是都随机携带一个cookie数据     

beautiful soup模块

可以帮助我们去html文档中筛选出我们需要的数据内容

它是一个第三方模块,需要你自己手动下载
pip3 install beautifulsoup4

该模块在查找数据的时候有四种解析器(四种不同的查找策略)
html.parse
# lxml	重点这个	
lxml.xml
html5lib

pip3 install lxml

# 参考文档
https://www.cnblogs.com/xiaoyuanqujing/articles/11805757.html
    
# 模拟网络请求获取到的页面html数据
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><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> and
<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>
"""
# 导入模块
from bs4 import BeautifulSoup

# 将需要筛选的数据填入
soup = BeautifulSoup(html_doc, 'lxml')
# print(soup.prettify())  # 格式化美化展示

# 查找页面上所有的a标签  结果是一个列表
print(soup.find_all(name='a'))
# 查找第一个a标签里面的文本内容
print(soup.a.text)
# 查找第一个a标签里面的属性名与属性值
print(soup.find_all(name='a')[0].attrs)
# print(soup.a.attrs)  # 等价
# 查找第一个a标签里面的id值
print(soup.a.attrs.get('href'))
print(soup.a.attrs['href'])  # 等价
# 查找id是link1的标签
print(soup.find(attrs={'id': 'link1'}))
# 查找class是sister的标签
print(soup.find(attrs={'class': 'sister'}))
print(soup.find_all(attrs={'class': 'sister'}))

# 扩展
print(soup.find(id='link1'))
print(soup.find(class_='sister'))  
# 如果跟python中的关键字冲突 需要在末尾加下划线

"""
find
    结果是符合筛选条件的第一个标签
find_all
    结果是所有符合筛选条件的标签,列表的形式
"""

作业

1.今日笔记
2.整理防爬措施及相应的解决思路
3.尝试着用正则和bs4模块分别爬取红牛分公司数据
4.复习本周所有的内容

推荐阅读