接口
1、什么是接口?
接口一般来讲分为两种:
(1)程序内部的接口:方法与方法、模块与模块之间的交互,程序内部抛出的接口,如登录发帖,发帖就必须要登录,如果不登录不能发帖,发帖和登录这两个模块之间就要有交互,就会抛出一个接口,进行内部系统调用。
(2)系统对外的接口:从别人的网站或服务器上获取资源或信息,对方不会提供数据库共享,只能提供一个写好的方法来获取数据,如购物网站和第三方支付之间,购物网站支付时可选择第三方支付方法,但第三方不会提供自己的数据库给购物网站,只会提供一个接口,供购物网站进行调用。
2、接口的分类?
接口分类一般分为两种:
(1)webService接口:走soap协议通过http传输,请求报文和返回报文都是xml格式的。测试时需要通过工具才能进行调用、测试。少数公司还在使用这种接口,如医院等行业。
(2)http api接口:走http协议,通过路径来区分调用的方法,请求和报文都是key-value形式的,返回报文一般都是json串,有get和post等方法。目前来讲,是最常用的。
3、接口返回数据
接口返回的数据一般都是json串,json是一种通用的数据类型,格式为key-value。
Requests库
requests.get()
get一般用于获取,查询数据,不会修改服务器数据。由于它是读取的,故可对读取数据进行缓存。
r = requests.get(url, params)
- 返回值为response对象。
- url为查询对象所在服务器地址,params即查询的限制条件,为字典形式。若params为空则不添加限制。
- 由于字典中键值一一对应,有时会出现url有多个参数的情况,此时可以将值写成列表的形式。
- 在浏览器中,get的url长度一般都有限制,因为其缓存的特性,过长的url容易导致内存爆炸。
requests.post()
post将某些数据发送到服务器时使用,可以向服务器发送修改请求,进行数据的修改,但是不可进行缓存。
requests.post(url, data)
- 返回值为response对象
- 浏览器中,post请求分为请求头(header)和请求体(body)
- data为请求的内容,一般是字典,元组列表,字节或要发送到指定URL的文件对象;如果是json的格式,最好使用json.dumps,反序列化一下,避免格式错误,如果是其他格式,就都是字符串了
response
-
r.content:返回网页的HTML内容,直接从网络上面抓取的数据,没有经过任何解码,是编码后的byte类型(str数据类型)。
-
r.text:返回网页的HTML内容,是unicode类型(二进制)。是 requests将 response.content进行解码的字符串,解码需要指定一个编码方式,requests会根据自己的猜测来判断编码的方式,有时候可能会猜测错误,导致解码产生乱码。
-
r.json:返回网页的HTML内容,但是把返回响应的json字符串转换成字典。 response.json() 等同于 json.loads(response.text);返回信息的格式是json对象;若r不是json格式则会导致返回报错,从而可判断是开发的接口出错了。
-
r.status_code:返回 http 的状态码,200是成功,404是未找到接口路径,500是服务器错误等等
-
r.url:返回请求时的url地址
-
r.headers:返回服务器给你的响应header
-
r.cookies:返回服务器给你的cookies
-
r.encoding:可以用来定义编码(如utf-8),如果编码不对,网页就会乱码的。
请求头和请求体
1. 请求行
请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1
* 请求方式:
* HTTP协议有7中请求方式,常用的有2种
* GET:
1. 请求参数在请求行中,在url后。
2. 请求的url长度有限制的
3. 不太安全,因为所发送的数据是 URL 的一部分,在发送密码或其他敏感信息时绝不要使用 GET
* POST:
1. 请求参数在请求体中
2. 请求的url长度没有限制的
3. 相对安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。
2. 请求头:客户端浏览器告诉服务器一些信息
请求头名称: 请求头值
* 常见的请求头:
1. User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
* 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
2. Referer:http://localhost/login.html
* 告诉服务器,我(当前请求)从哪里来?
* 作用:
1. 防盗链
2. 统计工作
3. 请求空行
空行,就是用于分割POST请求的请求头,和请求体的。
4. 请求体(正文):
* 封装POST请求消息的请求参数的,GET没有请求体
在请求网页爬取的时候,输出的text信息中会出现抱歉,无法访问等字眼,这就是禁止爬取,需要通过反爬机制去解决这个问题。
headers是解决requests请求反爬的方法之一,相当于我们进去这个网页的服务器本身,假装自己本身在爬取数据。对反爬虫网页,可以设置一些headers信息,模拟成浏览器取访问网站 。
JSON
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。通常用于在 Web 客户端(浏览器)与 Web 服务器端之间传递数据。
JSON 的语法规则
- 数组(Array)用方括号[ ]表示。
- 对象(Object)用大括号{ }表示。
名称/值对(name/value)组合成数组和对象。名称(name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组,并列的数据之间用逗号分隔。
requests其它方法
- requests.put(url):从客户端向服务器传送的数据取代指定的文档的内容。
- requests.delete(url): 请求服务器删除指定的页面。
- requests.head(url): 只请求页面的头信息。
Flask
https://blog.csdn.net/qq_44864833/article/details/122423539
装饰器
- @ 符号就是装饰器的语法糖。它放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上,和这个函数绑定在一起。在我们调用这个函数的时候,第一件事并不是执行这个函数,而是将这个函数做为参数传入它头顶上这顶帽子,这顶帽子我们称之为装饰函数 或 装饰器。
- 装饰器通过闭包实现,装饰器作为外函数传入目标函数,内函数执行具体操作。
- 不带参数的装饰器:
def decorate(func): # 这里的参数是函数
print("装饰器执行了") # 可以看出,这里的装饰器就是外函数有了参数的闭包
def inner():
print("执行函数了")
func()
print("函数执行结束了")
return inner;
@decorate # @decorate 值得是装饰器语法糖,它的执行意义是 comment = decorate(comment) comment()
def comment():
print("评论开始了")
comment()
- 带参数的装饰器:
def decorate (func):
def inner(a,b): # 这里的inner函数有参数,则也需要func也需要有参数
print("努力计算中!!!")
func(a,b)
return inner
@decorate # 这里本质是 f = decorate(add1), f(a,b) 所以inner函数也需要和add1函数有相同的形参列表
def add1(a,b):
print("%d + %d = %d"%(a,b,a+b))
add1(2,3)
# 输出: 努力计算中!!!
# 2 + 3 = 5
@app.route()
- @app.route(‘URL’)的功能,就是程序运行起来,然后输入这里的URL,页面上显示函数的return值。
- 注意:@app.route只指定内部路由寻址方向,即’/test1/'前面的内容它不会涉及。其中127.0.0.1是服务器IP,如果不指定就是本机IP,冒号后面的5000是端口号。服务器IP和端口号决定函数在哪里运行。
- 建议: 尽量保持route()内的URL和被修饰的函数名相同,这样就可以大大避免在同一文件中因函数名字相同而导致程序报错。(这里URL和被修饰的函数名无本质联系,这里的建议只是一种编码习惯)
- @app.route()可传输参数:https://blog.csdn.net/qq_33962481/article/details/113522479
app.run()
-
指定访问的网站地址的方法: (加入host的参数指定当前机器的ip)
app.run(host=“192.168.1.109”,debug=True) -
如果机器存在多个网卡或代码放到另外一台机器,让他智能识别(直接输入当前及其的ip即可)
app.run(host=“0.0.0.0”,debug=True) -
修改访问的端口号的方法:(加入port的参数指定端口)
app.run(host=“192.168.1.109”,debug=True, port=81)
request模块——都是用来获取提交的内容
- request.method():返回请求方法
- request.Form:获取以POST方式 提交的数据(接收Form提交来的数据);
- request.args:获取地址栏参数(不分提交方式,一般默认GET);当浏览器以post方式请求时,若请求地址栏也有参数也可以通过request.args.get(键) 方式获取
- request:包含以上两种方式(优先获取GET方式提交的数据)
- request.json:只能够接受方法为POST、Body为raw,header 内容为 application/json类型的数据。执行步骤是首先判断Content-Type是不是application/json,如果是,做json.load;如果不是,直接返回None。
- json.loads(request.data) 能够同时接受方法为POST、Body为 raw类型的 Text 或者 application/json类型的值
理解发送数据和接受数据
- 使用requests库的post方法,就是在把data推进url对应的服务器中(先传再收)
- 使用@app.route,request模块就是在接收传进来的数据,后面可以根据相应的内容,提供对应的返回数据(先收再传)
例子
接收:
app = Flask(__name__)
#获取状态数据接口,http://192.168.1.109:80/getState
@app.route("/getState",methods=['POST'])
def getState():
msg = []
try:
if request.method == 'POST':
msg = [{'tag': 'M1', 'state': '1'},
{'tag': 'M2', 'state': '0'}]
#0 正常,1 异常
except:
msg = []
return json.dumps(msg,ensure_ascii=False)
if __name__ == '__main__':
app.run(host = '0.0.0.0', port = 80)
发送:
url = 'http://192.168.1.109:80/getState'
#无需输入
data = {}
r = requests.post(url,data = data)
print(r.json())
- 这里的例子中,post时无需输入数据;
- 如果有特定需求,比如想获得某个指标的状态,可以在第一段中添加
paras = request.form.to_dict()
# 或paras = request.get_json(), 根据不同的信息格式而定
然后读取paras中的信息,根据信息要求返回相应的内容;
- 第二段中也要给data添加相应的内容,如指标的名字之类的信息,要注意data的格式需和第一段代码的要求保持一致。
实践报错整理
OSError: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试。
解决方法:
- 命令提示符中查看哪个进程占用了端口号
netstat -ano|findstr 3306
findstr 3948
(查看详细信息,5272为上一步查出来的pid结果) - kill进程(注意用管理员权限打开,要不然关不了)
taskkill /pid 3948 /F
- WARNING: This is a development server. Do not use it in a production deployment.
分析与解决:
方法一:
from gevent import pywsgi
if name == ‘main’:
server = pywsgi.WSGIServer((‘0.0.0.0’, 5000), app)
server.serve_forever()
方法二:
from wsgiref.simple_server import make_server
if name == ‘main’:
server = make_server(‘’, 5000, app)
server.serve_forever()
from flask_script import Manager
方法三:
from flask_script import Manager
manager=Manager(app)
if name == “main”:
db.create_all()
app.run(debug=False) #开发者模式
manager.run() #非开发者模式
ValueError: too many values to unpack (expected 2)
使用requests.post时出现,data格式是列表,元素为字典
- 第一步:data = json.dumps(data)
原因:数据是json格式,需要json.dumps()反格式化 - 报错:TypeError: Object of type date is not JSON serializable
第二步:
class DateEncoder(json.JSONEncoder):
def default(self, obj):
# 处理返回数据中有date类型的数据
if isinstance(obj, datetime.date):
return obj.strftime("%Y-%m-%d")
# 处理返回数据中有datetime类型的数据
elif isinstance(obj, datetime.datetime):
return obj.strftime("%Y-%m-%d %H:%M:%S")
# 处理返回数据中有decimal类型的数据
elif isinstance(obj, decimal.Decimal):
return float(obj)
else:
return json.JSONEncoder.default(self, obj)
data = json.dumps(data, ensure_ascii=False, cls=DateEncoder).encode("utf-8")
原因:日期类型的数据存在,json.dups()无法处理,要转成字符串
3. 报错:“requests.exceptions.InvalidSchema: No connection adapters were found for…
第三步:url的地址没加http://,地址不完整导致访问出错
requests.exceptions.ConnectionError: HTTPConnectionPool(host=‘****, port=80): Max retries exceeded
连接次数太多了,所以避免使用延时连接(也有可能url之类的写错了,记得检查)
解决方法(两种):
- 在headers里面加:{‘connection’: ‘close’}
- requests.adapters.DEFAULT_RETRIES = 8
跳板机
跳板机(Jump Server),也称堡垒机,是一类可作为跳板批量操作远程设备的网络设备,是系统管理员或运维人员常用的操作平台之一。
跳板机是网络中容易受到侵害的主机,所以跳板机也必须是自身保护完善的主机。通常至少配备两块网卡设备,分别具备不同的网络连接。 一个连接外网,用以对目标服务器的远程登录及维护;另一个则连接内网,便于内部网络的管理、控制和保护,通过网关服务提供从私网到公网,或从公网到私网的特殊协议路由服务。
当需要用本地电脑远程连接服务器(或其它电脑)时,很有可能出现两个设备存在网络限制,彼此无法互联,所以可以通过跳板机这个中介,分别连接到两个设备,从而实现远程连接的目的。