day96 爬虫 requests
爬虫
1 爬虫介绍
1.1 爬取流程
爬取的都是http/https的数据,移动端的数据,发送请求获取数据,但并不是只有python能做爬虫(任何语言都可以做爬虫),python比较便捷,上手快,爬虫框架scrapy
发送http请求(request模块)----》服务器返回数据(咱们要爬取的网站)-----》拿到数据解析(re,bs4)(json/html)-----》入库保存(文件,mysql,redis)----》后续可以做分析
发送http请求:浏览器,浏览器会自动组装数据包(http的请求包),向服务端发送请求
自己基于socket来封装,比较复杂,原生python提供了urllib模块,有个人基于urllib模块继续封装,做了requests模块
使用requests模块模拟http请求,有的时候爬不到数据,被禁止了,一定是你模拟的不够像
可见即可爬
爬虫协议:规定了什么东西我让你你爬,什么东西不让你爬:https://www.baidu.com/robots.txt
面试题:301和302的区别:
301是永久重定向(permanent),而302是临时重定向(redirect)
302重定向只是暂时的重定向,搜索引擎会抓取新的内容而保留旧的地址,因为服务器返回302,所以,搜索搜索引擎认为新的网址是暂时的。
而301重定向是永久的重定向,搜索引擎在抓取新的内容的同时也将旧的网址替换为了重定向之后的网址。
requests模块
小猿取经:https://www.cnblogs.com/xiaoyuanqujing/articles/11805698.html
django的request对象有个META字典,请求头中的所有东西,都在这个字典中
监听127.0.0.1:8080和0.0.0.0.8080的区别,前者只允许本机访问,后者允许任意机器访问ALLOWED_HOSTS=['*']程序层面允许任意IP地址访问
请求头的数据从request.META中取,只不过前面加了个HTTP,把请求头的key值变成了大写
问题:POST请求在请求地址中可以不带参数 ,连接地址的参数从GET 请求体中从POST
三种编码格式:urlencoded,json,form-data
django request.POST中之所以能取得数据,是因为Django框架从请求体中取得数据,放在POST中,编码格式必须是urlencoded
如果编码格式是json格式,django不干,request.POST取不出来,request.body取出来自行处理
http请求体:
urlencoded:name=lqz&age=19
json:{"name":"刘清政","":""}
form-data:很复杂
1 ret就是响应对象,response对象
# pip3 install requests
# 模拟发送http请求
# 导入
import requests
# 用的最多的就是get和post
# requests.request('get','地址') get和post请求本质就是它
ret = requests.get('https://www.baidu.com/')
# ret就是响应对象,response对象
print(ret.text) # 响应体的内容
with open('baidu.html', 'w', encoding="utf-8") as f:
f.write(ret.text)
2 有的地址发送请求 需要携带头部
#有的地址发送请求 需要携带头部
ret = requests.get('https://www.baidu.com/',
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
})
print(ret.text) # 响应体的内容
with open('baidu.html', 'w', encoding="utf-8") as f:
f.write(ret.text)
3 通过自己服务器模拟requests的使用
# 通过自己服务器模拟requests的使用
ret = requests.get('http://127.0.0.1:8000/',
headers={
'aaa':'xxx'
})
print(ret.text) # 响应体的内容
4 get请求携带参数
# 4 get请求携带参数
#第一种方式
# ret=requests.get('http://127.0.0.1:8000/?name=zqf&age=18')
#第二种方式(推荐使用)
ret=requests.get('http://127.0.0.1:8000/',params={'name':'绽放','age':19})
#区别
#第二种方式,如果有中文会自动转码,第二种不行
# https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3
# 补充:
from urllib.parse import urlencode
print(urlencode({'name':'许大虎'},encoding='utf-8'))#name=%E8%AE%B8%E5%A4%A7%E8%99%8E
print(ret.text)
5 get请求携带headers
# 5 get请求携带header
#Referer,一般网站通过这个做反扒、图片防盗链 上一个地址时什么 大型网站通常会根据该参数判断请求的来源
#User-Agent 客户端
#Cookie Cookie信息虽然包含在请求头中,但requests模块有单独的参数来处理它,headers就不放它了
ret = requests.get('https://www.baidu.com/',
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
})
6 携带cookie的两种方式
# 6 携带cookie的两种方式
#第一种方式
ret = requests.get('https://www.baidu.com/',
headers={
'cookie':'key:value;key2:value2'
})
#第二种方式(推荐)本质还是放在headers
ret=requests.get('https://www.baidu.com/',
cookies={"key":'value','key2':'value2'})
7 发送post请求,携带数据,两个位置,一个是请求地址中,一个是请求体中
#7 发送post请求,携带数据,两个位置,一个是请求地址中,一个是请求体中
#params:放在地址中的参数
#data:请求体中的参数
ret=requests.post('http://127.0.0.1:8001/',params={'name':'lqz','age':18},data={'name':'egon','age':17})
print(ret)
8 响应对象
# 8 响应对象
ret=requests.post('http://127.0.0.1:8001/',params={'name':'lqz','age':18},data={'name':'egon','age':17})
print(ret.text)
print(ret.content) # 响应体的二进制格式,一旦请求的是图片。。。,
print(ret.status_code) #响应的状态码
print(ret.cookies) #对象,requests模块自己封装的对象
print(ret.cookies.get_dict()) #这个是字典
print(ret.url)
print(ret.history[0].url)#列表,放的是重定向之前的response对象
print(ret.encoding) #服务端的编码方式
#重点补充
session=requests.session()#再发送各种请求,不需要手动加cookie了 它会自动处理了
9 解析json
# 9 解析json
ret=requests.post('http://127.0.0.1:8000/')
print(ret.text)#str类型
print(ret.json())# 字典类型
#python3.5和3.6以后 json有些改动 3.5以前 json.loads(字符串) 3.6以后json.loads(字符串/bytes格式)
10 高级用法
# 10 高级用法
# ssl 检查证书
# 代理(重点) 代理池(正向代理和反向代理
'''
一、正向代理
所谓正向代理就是顺着请求的方向进行的代理,即代理服务器他是由你配置为你服务,去请求目标服务器地址。
比如我们要去访问谷歌网站,我们直接访问不通,那么我们就可以找一个代理服务器为我们服务,我们通过代理服务器请求到谷歌网站。对于谷歌而言他只知道有一个服务器访问了自己,并不知道这件事你是访问不了他,找了一个代理服务器访问自己。
在举一个通俗的例子。你需要钱,C正好有钱,但是你C不直接借给你。你和B关系比较好,B可以找C借到钱。你和B沟通后,由B来找C借到钱后在给你。
二、反向代理
所谓反向代理正好与正向代理相反,代理服务器是为目标服务器服务的,虽然整体的请求返回路线都是一样的都是Client到Proxy到Server。
比如 我们访问百度网站,百度的代理服务器对外的域名为 https://www.baidu.com 。具体内部的服务器节点我们不知道。现实中我们通过访问百度的代理服务器后,代理服务器给我们转发请求到他们N多的服务器节点中的一个给我们进行搜索后将结果返回。
再举例:我们同样需要钱,但是我们又不知道谁有钱,所以我们找了一家网贷平台,你提交资料后,网贷平台直接将钱打给你。但是你不知道,也不用关注网贷平台的钱从哪里来。网贷平台内部他们可能从哪一个财主哪里融的钱。对你而言网贷平台和他们的金主是一起的
'''
#使用代理,防止服务端封自己的IP (免费的:不稳定 收费的:稳定)
# 代理匿名度:高匿 透明
# requests发送请求如何使用代理
ret=requests.get('http://101.133.225.166:8088/',
proxies={'http':'222.95.241.88:3000'}
)
print(ret.text)
# django如何取得客户端的IP地址(request.META.get('REMOTE_ATTR'),取得的是代理的IP
# 真正的项目中,一般会使用代理池,自己搭建代理池,自己去爬免费代理
# https://github.com/jhao104/proxy_pool 网上开源的代理池
#django中如何取到哪个IP地址使用了代理
#百度的
'''
通常访问者的IP就在其中,所以我们可以用下列方法获取用户的真实IP:
#X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。
def get_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]#所以这里是真实的ip
else:
ip = request.META.get('REMOTE_ADDR')#这里获得代理ip
return ip
'''
11 超时设置
# 11 超时设置
ret=requests.get('http://www.baidu.com',timeout=0.01)
12 异常(了解)
# 12 异常(了解)
#异常处理
import requests
from requests.exceptions import * #可以查看requests.exceptions获取异常类型
try:
r=requests.get('http://www.baidu.com',timeout=0.00001)
except ReadTimeout:
print('===:')
# except ConnectionError: #网络不通
# print('-----')
# except Timeout:
# print('aaaaa')
except RequestException:
print('Error')
13 上传文件
# 13 上传文件
file={'myfile':open('baidu.html')}
ret=requests.post('http://127.0.0.1:8000/',files=file)
print(ret.text)
后台服务端
from django.shortcuts import render
# Create your views here.
from django.shortcuts import render,HttpResponse,redirect
from django.http import JsonResponse
def index(request):
# print(request)
# print(request.META.get('HTTP_AAA'))
# print(request.GET)
# print(request.POST)
from django.http.request import QueryDict
#QueryDict不允许修改 request.GET
# 但是 aa=request.GET.dict()可以修改了
# 肯定继承了HTTPRESONSE,封装了json
# JsonResponse 转列表转不了
# import json
# json.dumps(ensure_ascii=False)
file=request.FILES.get('myfile')
with open('baidu.html','wb') as f:
for line in file:
f.write(line)
return HttpResponse('ok')
总结:
1 requests模块就是模拟http请求,请求有什么,requests模块就可以放什么headers(user-agent,referer),cookies,data/json,
2 如果不做爬虫 requests模块可以单独使用,以后涉及到两个服务(两个项目)至今做数据交互
案例一
模拟登陆到某网站,获取cookie,携带cookie再进入到首页,会有我的用户名
dic={
'username': '616564099@qq.com',
'password': 'lqz123',
'captcha': 'mjk6',
'remember': '1',
'ref': 'http://www.aa7a.cn',
'act': 'act_login',
}
ret=requests.post('http://www.aa7a.cn/user.php',data=dic)
print(ret)
print(ret.text)
cookie=ret.cookies.get_dict()
ret1=requests.get('http://www.aa7a.cn/',cookies=cookie)
print('616564099@qq.com' in ret1.text)
案例二
爬取梨视频短视频
import re
ret=requests.get('https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=5&start=0')
print(ret.text)
re_com='<a href="(.*?)" class="vervideo-lilink actplay">'
req=re.findall(re_com,ret.text)
print(req)
for url in req:
ret1=requests.get('https://www.pearvideo.com/'+url)
print(ret1.text)
re_com2 = 'ldUrl="",srcUrl="(.*?)",'
url_mp4=re.findall(re_com2,ret1.text)[0]
print(url_mp4)
ret3=requests.get(url_mp4)
name=url_mp4.rsplit('/',1)[-1]
with open(name,'wb') as f:
for line in ret3.iter_content():#一行一行写入
f.write(line)