本篇文章记录的是Python内置模块和requests模块知识。
一、模块的介绍
1、模块是什么
模块 就是一系列功能 ( 函数 ) 的集合体
模块的分类
- 内置模块 c语言写的模块/python中自带的
- 第三方模块 别人写好的模块/从网上下载
- 自定义模块 自己自定义的
一个python文件本身就是一个模块 , 文件名m.py , 模块名叫m
2、 为什么要用模块
- 内置与第三方的模块拿来就可以用,无需定义,这种拿来主义,可以极大的提升自己的开发效率
- 可以将程序的各部分功能提取出来放到一模块中为大家共享使用
- 减少了代码冗余,程序组织结构更加清晰
3、 模块怎么使用
import 导入
[创建模块]
# m.py
print('======我是m模块中的print代码=====')
x1 = 100
def get(arg):
print("get ========%s" % arg)
[导入模块]
# 第一种方式
# import m
# 模块导入的时候,里面的代码会执行
# 模块里面内容的访问
# 语法
# 模块名.属性名
# print(m.x1)
# print(m.get(200))
有点类似于 php 中的 inclde 包含 , 包含进来的文件 , 你是不是可以使用该文件里面定义好的功能
from ... import .... 导入
# foo.py
print('======foo=====')
x = 0
def get(arg):
print("get ========%s" % arg)
# 第二种方式
# from ... import .... 导入
# from foo import x # from 模块 import 名字
# print(x)
from foo import get
get(100) # 100
简单了解的导入方式 , 我们来学习一下常见的内置模块
补充 : 为什么你在别人的poc也好还是exp也好 , 总是有这样一个身影 , 就是
def main():
pass
if __name__ == '__main__':
main()
# main还好 , 是个函数 , 大家都知道 , 但是为什么要写在if __name__ == '__main__': , 我想调用他直接main()
# 不就好了吗 , 这是因为什么呢 ? 当py脚本当成模块导入的时候我们知道 , 代码会被执行 , 假如有人一不小心把你的这个py脚本当成模块导入了 , 那不就自动执行了吗? 这个判断就是为了防止这件事情的发生的
# __name__ 就是一个特殊的变量而已
# 当py脚本当成模块导入 __name__ 是不等于 '__main__' 的 , 只有执行运行改脚本才是 __name__ == '__main__'
包和模块的不同
模块是一个单独的文件
包是一个文件夹 , 并且该文件夹下必须有一个 __init__.py这样的文件
导入包时 , 会自动运行 __init__.py 里面的代码
其他的导入形式
import numpy as np # as简单理解就是起别名 , 然后可以通过 别名.名字 调用属性
__import__('base64') # 以字符串形式导入 base64
二、内置模块
无需下载直接导入即可使用 , 是安装python就已经在你的电脑上安装好了的
1、os模块
os系列
import os
os.getcwd() # 获取当前工作目录(pwd),即当前python脚本工作的目录路径
os.chdir("dirname") # 改变当前脚本工作目录;相当于shell下cd
os.curdir # 返回当前目录:('.')
os.pardir # 获取当前目录的父目录字符串名:( '..')
os.mkdir('dirname') # 生成单级目录;相当于shell中mkdir dirname
os.makedirs('dirname1/dirname2') # 可生成多层递归目录
os.rmdir('dirname') # 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') # 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove("filename") # 删除一个文件
os.removedirs('dirname1') # 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,并递归倒上一层
os.rename("oldname", "newname") # 重命名文件/目录
os.name # 输出字符串指示当前使用平台。win-> 'nt '; Linux->'posix'
os.system("bash command") # 运行shell命令,直接显示
os.path系列
os.path.abspath('path') # 返回path规范化(符合平台的路径分隔符)的绝对路径
os.path.split('path') # 将path(path的分隔符必须是/)分割成目录和文件名二元组返回
os.path.dirname(path) # 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) # 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) # 如果path存在,返回True;如果path不存在,返回Falseos.path.isabs (path)如果path是绝对路径,返回True
os.path.isfile(path) # 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) # 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[,...]]) # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
常用 :
os.remove("filename") # 删除一个文件
os.rename("oldname", "newname") # 重命名文件/目录
os.name # 输出字符串指示当前使用平台。win-> 'nt '; Linux->'posix'
os.system("bash command") # 运行shell命令,直接显示
os.path.isfile(path) # 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) # 如果path是一个存在的目录,则返回True。否则返回False
os.path.abspath('path') # 返回path规范化(符合平台的路径分隔符)的绝对路径
os.path.exists(path) # 如果path存在,返回True;如果path不存在,返回Falseos.path.isabs (path)如果path是绝对路径,返回True
os.path.join(path1[, path2[,...]]) # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
2、time模块
# 时间分为三种格式
# 1.时间戳:从1970年到现在经过的秒数
# 作用:用于时间间隔的计算
import time
print(time.time()) # 1630411655.8108306
print(type(time.time())) # <class 'float'>
# 2.按照某种格式显示的时间:2021-08-31 11:11:11
# 作用:用于展示时间
# %Y-%m-%d %H:%M:%S
# 年 月 日 时 分 秒
# %H:%M:%S == %X , %p代表上下午
print(time.strftime("%Y-%m-%d %H:%M:%S")) # 2021-08-31 20:08:42
print(time.strftime("%Y-%m-%d %H:%M:%S %p")) # 2021-08-31 20:08:42 PM
print(time.strftime("%Y-%m-%d %X")) # 2021-08-31 20:08:42
print(type(time.strftime("%Y-%m-%d %X"))) # <class 'str'>
# 3.延时
time.sleep(3) # 程序运行到这行代码的时候会延时3秒
3、random模块
import random
print(random.random())#(0,1)----float 大于0且小于1之间的小数
print(random.randint(1,3)) #[1,3] 大于等于1且小于等于3之间的整数
print(random.randrange(1,3)) #[1,3) 大于等于1且小于3之间的整数
print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5]
print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合
print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716
item=[1,3,5,7,9]
random.shuffle(item) #打乱item的顺序,相当于"洗牌"
print(item)
示例 : 随机的6位数验证码
import random
def make_code(n):
res = ''
for i in range(n):
s1 = str(random.randint(0, 9))
res += s1
return res
print(make_code(6))
4、json模块
准备知识 : 了解什么是序列化 , 什么是反序列化 ?
序列化指的是把内存中的数据类型转换成一个特定的格式的内容
反序列化指的是把一个特定的格式的内容转化成当前平台在内存中的一个数据类型
对于我们后面写python代码 , 就是 json格式的字符串-->python对象(字典) 反序列化
python对象(字典) --> json格式的字符串 序列化 (用到的不多)
为什么要进行序列化和反序列化呢?
这就要从他的特点来说了,也是他的用途 :
1.用于存储==>用于存档
大家玩过存档游戏吗?存档对于玩家说是装备等级,对程序员来说实际上这些就是数据,代码而已,
所以所谓的存档就是把程序的运行状态保存下来了(内存中的数据)
2.传输给其他平台使用==>跨平台数据交互
python java
列表 特定格式 数组
强调:
针对用途1 可以是一种专用的格式==>pickle
针对用途2 应该是通用, 能够被所有语言识别的格式==>json
json模块示例代码
import json
dic = {"status": 200, "msg": "success"}
# 序列化
res = json.dumps(dic)
print(res, type(res)) # {"status": 200, "msg": "success"} <class 'str'>
# 反序列化
l = json.loads(res)
print(l, type(l)) # {'status': 200, 'msg': 'success'} <class 'dict'>
# 补充:
# 将序列化的结果写入文件
res = json.dumps(dic)
with open('test.json', mode='w', encoding='utf-8') as f:
json.dump(dic, f)
#
# # 将文件读取的json格式的字符串反序列化出来
with open('test.json', mode='r', encoding='utf-8') as f:
res = json.load(f)
print(res, type(res)) # {"status": 200, "msg": "success"} <class 'str'>
# json验证: json格式兼容的是所有语言通用的数据类型 ,不能支持单一语言所有类型
# 不支持python的集合和元祖
我们用到的场景是 , 当后面我们使用python代码发送网络请求 , 得到服务器的响应是json格式的字符串的时候 , 可以通过反序列化 , 把字符串转成字典对象, 然后通过字典的方法 , 获取其中我们想要的数据
5、base64模块
实现对字符串的base64编码和解码
import base64
# base64编码
s1 = "admin"
res1 = base64.b64encode(s1.encode("utf-8")) # 参数必须是字节,返回值是字节
print(res1) # b'YWRtaW4='
print(res1.decode("utf-8")) # YWRtaW4=
# 简单封装成一个函数
def my_b64encode(s):
res = base64.b64encode(s.encode("utf-8")) # 参数必须是字节,返回值是字节
return res.decode("utf-8")
b64 = my_b64encode("123456")
print(b64)
# base64解码
b64_str = "YWRtaW4="
res = base64.b64decode(b64_str)
res = res.decode("utf-8")
print(res) # admin
# 封装成一个函数
6、url模块
通过python对url进行编码和解码
import urllib.parse
# url编码
keyword = "后台"
keyword_byte = keyword.encode('utf-8')
url_keyword = urllib.parse.quote(keyword_byte)
print(url_keyword) # %E5%90%8E%E5%8F%B0
# url解码
url_keyword = "%E5%90%8E%E5%8F%B0"
url = urllib.parse.unquote(url_keyword)
print(url) # 后台
三、requests初体验
1、requests是什么
requests 是一个在python中用来发送请求的模块 , 同时他是一个第三方模块 , 我们可以通过pip3安装
我们平时使用浏览器上网本质上是不是就是通过浏览器这个工具对对方的网站发送请求 , 那么我换个工具 , 不再使用浏览器 , 使用其他的我不管你是什么工具 , 只要能满足我们发送请求的需求即可 , requests这个模块就是发送请求的一个模块。
2、安装
pip3 install requests
这种是在线安装 , 还有一种本地安装的方式 , 需要先下载对应的模块安装包 , 一般用到的比较少 , 可能python2环境下的一些依赖无法在线自动安装会采用这种方式安装
https://pypi.org/project/requests/#files
pip3 install requests-2.28.0-py3-none-any.whl
四、requests基本使用
1、发送get请求
import requests
url = "http://www.baidu.com"
response = requests.get(url)
# 1.打印服务器返回的响应状态码
print(response.status_code)
# 2.打印服务器返回的响应内容 , 全部
# print(response.text)
# # 3.保存到一个html文件
# with open("./1.html",mode="w",encoding="utf-8") as f:
# f.write(response.text)
# 4.返回编码格式
print(response.encoding) # ISO-8859-1
# response.text 之时,Requests 会使用其推测的文本编码。你可以找出 Requests 使用了什么编码,并且能够使用 r.encoding 属性来改变它:
# 如果你改变了编码,每当你访问 response.text ,Request 都将会使用 r.encoding 的新值
# 5.设置编码格式
response.encoding = 'utf-8'
# 6.设置编码后再保存到一个html文件
with open("./2.html",mode="w",encoding="utf-8") as f:
f.write(response.text)
2、发送post请求
环境:
http://XX.XX.XX.XXX:8092/toLogin
通过浏览器查看post请求提交的数据
url = "http://XX.XX.XX.XXX:8092/login"
data = {
"userName": "admin",
"password": "123456",
}
response = requests.post(url, data=data)
d = json.loads(response.text)
if d.get("code") == 200 and d.get("msg") == None:
print(f"[+]{url}存在弱口令")
else:
print(f"[-]{url}不存在弱口令")
3、参数解释
# 请求方法
requests.方法名()
# 常见参数
url # 请求的url
data # post请求携带的请求体
headers # 请求头
cookies # cookies
timeout # 等待时间
allow_redirects # 是否运行重定向 , 默认是允许 true
proxies # 代理 , 参数是字典类型 , 示例 :
proxies = { "http": "http://127.0.0.1:7890", "https": "http://10.10.1.10:1080", }
协议 url
verify # ssl证书校验 , 默认是true
4、响应获取
# 1.获取响应状态码
response.status_code # int
# 2.获取响应头
response.headers # dict
# 3.获取响应体
# 3.1 文本内容
response.text # str
# 3.2 字节内容 (图片,音频,视频)
response.content # byte
# 3.3 json格式字符串
response.json() # str
5、bp插件
在bp的扩展插件中搜索 Copy As Python-Requests
我们都知道BP可以抓包,当我们相对某个请求包,使用python编写相应代码发送时可以,先使用BP抓包,然后右键选择:
此时该插件就会生成python对应的请求代码,并赋值到你当前的剪切板
import requests
burp0_url = "https://www.baidu.com:443/"
burp0_cookies = {"PSTM": "1655964694", "BAIDUID": "65B9408A169710530C1F05C8AEDD650B:FG=1", "BD_HOME": "1", "H_PS_PSSID": "36552_36460_36673_36455_34813_36165_36570_36073_26350_36469_36314", "BAIDUID_BFESS": "65B9408A169710533F70359FCA98D582:FG=1", "BIDUPSID": "725DA321C78DF0F6CD65584E4FE8839C", "BD_UPN": "12314753", "BA_HECTOR": "a90480048h050lah8g1hb810m14", "ZFY": "8bxEX:A:B9HSmxIFaHW7pmuR9joCr8iyaLT:B0pkYG6GYM:C"}
burp0_headers = {"Cache-Control": "max-age=0", "Sec-Ch-Ua": "\"(Not(A:Brand\";v=\"8\", \"Chromium\";v=\"100\"", "Sec-Ch-Ua-Mobile": "?0", "Sec-Ch-Ua-Platform": "\"Windows\"", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Sec-Fetch-Site": "none", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}
requests.get(burp0_url, headers=burp0_headers, cookies=burp0_cookies)
五、尝试看源码分析
一步一步点击去看就ok了 , 这个时候你就会发现为什么 url 是位置传参 , 而其他的参数是关键字传参了。
六、小模版
针对bp生成的代码模板实际上是有一些不足的 , 比如有的站点 ssl证书过期了 , 你直接用浏览器访问都需要我们二次确认 , 对于requests模块也是 , 它也会检测 , 默认 verify 参数是true , 所以需要我们手动设置为 false , 不检测还有一些其他的参数也是 , 比如超时参数 , 最好也设置一下 , 你会发现每次都要设置这些参数 , 所以我们可以保留一个模板 , 防止自己忘记 , 而且我们都知道 请求有可能会失败 , 在我们代码中的体现是请求失败后 , 拿到的响应是None , 如果你再对响应做处理 , 比如 r.text
就会报错 , 所以最好加上 try ... except
# 语法
try:
# 可能会出错的代码
except:
# 报错之后,会执行的代码
报错捕捉需要指定报错类型 , 指定了类型只会捕捉这类的报错 , 比如 IndentationError , SyntaxError等 , 如果你不确定报错的类型 , 那么可以使用 Exception , 它可以捕捉任意类型的报错 , 示例
try:
# 可能会出错的代码
except Exception as e:
print(e)
import requests
requests.packages.urllib3.disable_warnings()
url = "http://xxxx.com/signin"
cookies = {"NG_TRANSLATE_LANG_KEY": "zh-CN", "JSESSIONID": "7D7571D40E4C16EC46C0C84FB3340E80"}
headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1",
"Origin": "http://xxxx.com", "Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Referer": "http://xxxx.com/signin", "Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,ja;q=0.8", "Connection": "close"}
data = {"username": "apollo", "password": "admin", "login-submit": "\xe7\x99\xbb\xe5\xbd\x95"}
try:
response = requests.post(url, headers=headers, cookies=cookies,data=data, allow_redirects=False, verify=False, timeout=5 )
print(response.text)
except Exception as e:
print(e)
# 退出代码,如果是循环,就跳过本次
"""
其他的代码逻辑,比如响应中的数据提取等
"""
然后我只需要每次把BP插件生成的代码替换到里面即可 , 或者你可以自己手动编写一个BP插件 , 按照你想要的格式生成python代码