XieJava's blog

记录最好的自己


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于

机器学习实现恶意URL检测实战一

发表于 2021-12-09 | 更新于: 2025-06-14 | 分类于 技术 , 开发 , 网络安全 | | 阅读次数:
字数统计: 1.1k | 阅读时长 ≈ 4

恶意URL检测的方法很多,这里介绍通过机器学习分析URL文本分词词频来检测恶意URL。训练的数据集为开源数据集,通过机器学习训练检测模型,然后做了部分工程化的应用,将模型持久化,在应用的时候加载进来直接应用,不用重新进行训练。通过接口调用实现恶意URL检测预测判断。

恶意URL检测,对应与机器学习是个分类问题,这里分别用逻辑回归和SVM支持向量机分类模型进行模型实现。

具体实现过程包括数据载入–>数据处理(分词、向量化处理)–>模型训练–>模型保存–>模型应用

项目组织结构如下:
项目组织结构

一、数据载入

从数据集中载入数据,读取数据,将URL和标签进行识别和区分。

1
2
3
4
5
6
7
8
9
10
#从文件中获取数据集
def getDataFromFile(filename='data/data.csv'):
input_url = filename
data_csv = pd.read_csv(input_url, ',', error_bad_lines=False)
data_df = pd.DataFrame(data_csv)
url_df = np.array(data_df)
random.shuffle(url_df)
y = [d[1] for d in url_df]
inputurls = [d[0] for d in url_df]
return inputurls,y

二、数据处理(分词、向量化处理)

数据处理实现对URL的分词及向量化处理
分词:分析URL根据,.-进行分词,由于com、cn等常用域名不是关键影响因素,所以分词的时候去掉了

分词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#分词
def getTokens(input):
web_url = input.lower()
urltoken = []
dot_slash = []
slash = str(web_url).split('/')
for i in slash:
r1 = str(i).split('-')
token_slash = []
for j in range(0, len(r1)):
r2 = str(r1[j]).split('.')
token_slash = token_slash + r2
dot_slash = dot_slash + r1 + token_slash
urltoken = list(set(dot_slash))
if 'com' in urltoken:
urltoken.remove('com')
if 'cn' in urltoken:
urltoken.remove('cn')
return urltoken

向量化处理

将分词以后的结果进行词频的向量化处理,形成可以用于模型训练的稀疏矩阵向量

1
2
3
all_urls,y=getDataFromFile(datapath)
url_vectorizer = TfidfVectorizer(tokenizer=getTokens)
x = url_vectorizer.fit_transform(all_urls)

三、模型训练

将经过处理后的训练数据用模型进行训练,将数据集分为两部分一部分用于训练,一部分用于测试评估。

1
2
3
4
5
6
7
8
9
10
11
#训练,通过逻辑回归模型训练
def trainLR(datapath):
all_urls,y=getDataFromFile(datapath)
url_vectorizer = TfidfVectorizer(tokenizer=getTokens)
x = url_vectorizer.fit_transform(all_urls)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
l_regress = LogisticRegression() # Logistic regression
l_regress.fit(x_train, y_train)
l_score = l_regress.score(x_test, y_test)
print("score: {0:.2f} %".format(100 * l_score))
return l_regress,url_vectorizer

用逻辑回归模型训练的结果是 score: 98.50 %

1
2
3
4
5
6
7
8
9
10
11
#训练,通过SVM支持向量机模型训练
def trainSVM(datapath):
all_urls, y = getDataFromFile(datapath)
url_vectorizer = TfidfVectorizer(tokenizer=getTokens)
x = url_vectorizer.fit_transform(all_urls)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
svmModel=svm.LinearSVC()
svmModel.fit(x_train, y_train)
svm_score=svmModel.score(x_test, y_test)
print("score: {0:.2f} %".format(100 * svm_score))
return svmModel,url_vectorizer

用SVM模型训练的结果是 score: 99.64 %

可以看出SVM模型训练的结果比逻辑回归模型训练的效果要稍好。

四、保存模型

将训练好的模型进行持久化保存,通过pickle.dump()的方式把训练好的模型参数及特征保存至模型文件,以便于应用的时候不要再进行训练,直接应用训练好的模型。

1
2
3
4
5
6
7
8
9
10
11
12
#保存模型及特征
def saveModel(model,vector):
#保存模型
file1 = modelfile_path
with open(file1, 'wb') as f:
pickle.dump(model, f)
f.close()
#保存特征
file2 = vectorfile_path
with open(file2, 'wb') as f2:
pickle.dump(vector, f2)
f2.close()

通过main方法执行训练模型及保存模型

1
2
3
4
if __name__ == '__main__':
#model,vector=trainLR('data/data.csv')
model, vector = trainSVM('data/data.csv')
saveModel(model,vector)

四、模型应用

通过pickle.load载入已经训练好的模型和特征,并用Flask暴露一个接口调用模型的预测方法进行预测。

载入已经训练好的模型

1
2
3
4
5
6
7
8
9
10
11
12
#载入已经训练好的模型
def loadModel():
file1 = modelfile_path
with open(file1, 'rb') as f1:
model = pickle.load(f1)
f1.close()

file2 = vectorfile_path
with open(file2, 'rb') as f2:
vector = pickle.load(f2)
f2.close()
return model,vector

通过接口进行调用

1
2
3
4
5
6
7
8
9
10
#通过接口进行调用
@app.route('/<path:path>')
def show_predict(path):
X_predict = []
X_predict.append(path)
model, vector = loadModel()
x = vector.transform(X_predict)
y_predict = model.predict(x)
print(y_predict[0])
return "url predict: "+str(y_predict[0])

五、应用效果

将需要检测的URL,输入到http://127.0.0.1:5000/后面,就可以根据输入的URL进行检测给出模型预测的结果。
http://127.0.0.1:5000/sohu.com/a/338823532_354899
检测效果1
http://127.0.0.1:5000/sohu.com/a/%3Cscript%3E/test
检测效果2

完整代码及数据集见:https://github.com/xiejava1018/urldetection.git


博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

解决Anaconda报The channel is not accessible源通道不可用问题

发表于 2021-11-26 | 更新于: 2024-06-13 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 675 | 阅读时长 ≈ 3

最近在通过pycharm开发python程序,引用anaconda环境建立虚拟环境时报错,报UnavailableInvalidChannel: The channel is not accessible or is invalid.应该是镜像源访问通道无法访问或无效。现将解决办法记录如下:

环境说明:

操作系统:win10
安装有anaconda 4.10.3
pycharm2021.2

报错现象:

在pycharm中新建python项目,引用anaconda建立虚拟环境时报错
报“UnavailableInvalidChannel: The channel is not accessible or is invalid.”
建立虚拟环境报错

解决办法:

1、找到anaconda的源配置文件

根据报错的建议提示:

You will need to ajust your conda configuration to proceed.
Use ‘cona config –show channels’ to view your configuration’s current state,
and use ‘conda config –show-sources’ to view config file location.

意思是建议你需要调整conda的配置来处理,可以通过cona config --show channels命令来查看你当前的配置状态,可以用conda config --show-sources看查看本地的配置文件。
根据这个建议,打开anaconda的命令行控制台。
Anaconda Powershell

敲入“conda config –show-sources”命令,显示当前的通道为https://pypi.tuna.tsinghua.edu.cn/simple 报错就是说这个通道无法访问或无效。

1
2
3
(base) PS C:\Users\xiejava> conda config --show channels
channels:
- https://pypi.tuna.tsinghua.edu.cn/simple

通过“conda config –show-sources” 查看配置文件的路径。配置文件为用户目录下的.condarc文件

1
2
3
4
5
(base) PS C:\Users\xiejava> conda config --show-sources
==> C:\Users\xiejava\.condarc <==
channels:
- https://pypi.tuna.tsinghua.edu.cn/simple
show_channel_urls: True

在这里插入图片描述

2、修改为清华的镜像源

将找到的.condarc文件打开。
拷贝以下清华的镜像源到该文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
channels:
- defaults
custom_channels:
conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
default_channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
show_channel_urls: True

然后再次运行conda config --show-sources,确认配置文件内容已经修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(base) PS C:\Users\xiejava> conda config --show-sources
==> C:\Users\xiejava\.condarc <==
channels:
- defaults
custom_channels:
conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
default_channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
show_channel_urls: True

3、验证

再打开pycharm引用Conda Enviroment新建新的虚拟环境。
新建新的虚拟环境
这时不报错可以正常创建Conda虚拟环境了。
创建Conda Environment

至此,修改成清华镜像源解决了Anaconda报The channel is not accessible源通道不可用的问题。


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

Python快速实现一个域名、IP信息聚合网站

发表于 2021-11-21 | 更新于: 2024-06-13 | 分类于 技术 , 开发 , 网络安全 | | 阅读次数:
字数统计: 2.3k | 阅读时长 ≈ 11

域名和IP地址信息是非常基础的情报信息,目前网上有很多网站都提供了域名信息的查询、IP地址及归属地的查询。本文通过Python Flask实现域名及IP情报信息的聚合网站。

因为域名和IP地址信息会有变化,为了减少接口压力,做了本地数据库的存储,新鲜度保存一周,每次查询先从本地数据库获取信息,如果本地库信息有并且没有超过一个星期就从本地库取,没有就从其他网站获取,并更新到本地库。

一、获取域名WHOIS信息

网上提供域名WHOIS信息查询的网站有很多,这里以http://whois.chinafu.com 为例实现WHOIS信息的查询和解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}

def getwhoisinfobychinafu(domain):
ret_result = {}
result=getWhoisInfoFromDB(domain)
if len(result)==0:
whois_service_url = 'http://whois.chinafu.com/whois.php'
post_data={"domain":domain}

try:
post_result=requests.post(whois_service_url,post_data)
if post_result.status_code == 200:
ret_str = post_result.content.decode('utf-8')
soup = BeautifulSoup(ret_str, 'lxml')
items_tr =soup.find(name='table',attrs={'class':'listtable'}).find_all(name='tr')
for item_tr in items_tr:
td_item=item_tr.find(name='td')
if 'colspan' in td_item.attrs:
key_name='详情'
key_value=td_item.find(name='div',id='tab1').text
else:
key_name=item_tr.find(name='th').text
key_value=item_tr.find(name='td').text
ret_result[key_name]=key_value
addchinafuWhoisInfo2DB(ret_result)
except Exception as r:
print('未知错误 %s' % (r))
#ret_result = json.dumps(ret_result, ensure_ascii=False)
else:
ret_result=result[0]
return ret_result

def getWhoisInfoFromDB(domainname):
whoisInfos=db.session.execute('select * from whoisinfo where domain_name="%s" and updated_time > DATE_SUB(CURDATE(), INTERVAL 1 WEEK)' % domainname).fetchall()
whoisInfo_dics=[]
for whoisInfo in whoisInfos:
chinafuwhoisinfo_dic=chinafuwhoisinfo2dic(whoisInfo)
whoisInfo_dics.append(chinafuwhoisinfo_dic)
return whoisInfo_dics

def addchinafuWhoisInfo2DB(chinafuWhoisInfo_dic):
chinafuWhois=WhoisInfo()
chinafuWhois.domain_name=chinafuWhoisInfo_dic.get('域名DomainName')
chinafuWhois.domain_status=chinafuWhoisInfo_dic.get('域名状态Domain Status','')
chinafuWhois.registrar=chinafuWhoisInfo_dic.get('注册商Sponsoring Registrar','')
chinafuWhois.name_server=chinafuWhoisInfo_dic.get('DNS 服务器Name Server','')
chinafuWhois.registrar_creation_date=chinafuWhoisInfo_dic.get('注册日期Registration Date','')
chinafuWhois.registrar_updated_date = chinafuWhoisInfo_dic.get('更新日期Update Date', '')
chinafuWhois.registrar_expiry_date = chinafuWhoisInfo_dic.get('到期日期Expiration Date', '')
chinafuWhois.detail=chinafuWhoisInfo_dic.get('详情', '')[0:10000]
chinafuWhois.source = '中国福网'
db.session.execute('delete from whoisinfo where domain_name="%s" and source="%s"' % (chinafuWhoisInfo_dic.get('域名DomainName'), chinafuWhois.source))
db.session.add(chinafuWhois)
db.session.commit()

这里为了减少直接从其他网站获取WHOIS信息的压力,做了本地数据库的存储,每次先从本地数据库取WHOIS的信息,如果本地库信息有并且没有超过一个星期就从本地库取,没有就从其他网站获取,并更新到本地库。这里getWhoisInfoFromDB实现了取新鲜度为1周的数据,addchinafuWhoisInfo2DB实现将获取的信息保存到本地数据库。

二、根据域名解析出IP

根据域名解析出IP代码:

1
2
3
4
5
6
7
8
def getIPbyDomain(domain):
addr=''
try:
myaddr = socket.getaddrinfo(domain, 'http')
addr=myaddr[0][4][0]
except Exception as e:
print(e)
return addr

三、获取IP信息

获取IP信息的API接口也有很多,有淘宝的 https://ip.taobao.com/outGetIpInfo 、IPINFO http://ipinfo.io/、IPAPI http://ip-api.com/ 以及GeoLite2离线库等。

从淘宝IP获取IP信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def getipinfobytaobao(ip):
taobaoIp_url = 'https://ip.taobao.com/outGetIpInfo'
post_data={"ip":ip,"accessKey":"alibaba-inc"}
ret_ipinfo= {}
try:
return_data=requests.post(taobaoIp_url,post_data)
#其中返回数据中code的值的含义为,0:成功,1:服务器异常,2:请求参数异常,3:服务器繁忙,4:个人qps超出
return_json=json.loads(return_data.text)
if return_json['code']==0:
ret_ipinfo['ip']=return_json['data']['ip']
ret_ipinfo['country']=return_json['data']['country']
ret_ipinfo['region']=return_json['data']['region']
ret_ipinfo['org']=''
ret_ipinfo['city'] = return_json['data']['city']
ret_ipinfo['isp']=return_json['data']['isp']
ret_ipinfo['loc'] = ''
ret_ipinfo['timezone'] = ''
ret_ipinfo['source']='淘宝IP'
addIPInfo2DB(ret_ipinfo)
except Exception as e:
print('未知错误 %s' % (e))
return ret_ipinfo

从ipinfo.io获取IP信息

1
2
3
4
5
6
7
8
9
10
11
12
def getipinfobyipinfo(ip):
api_url='http://ipinfo.io/'+ip
ipinfo = {}
try:
req_return = requests.get(api_url)
if req_return.status_code == 200:
ipinfo = json.loads(req_return.text)
ipinfo['source']='ipinfo.io'
addIPInfo2DB(ipinfo)
except Exception as e:
print('未知错误 %s' % (e))
return ipinfo

从ip-api.com获取IP信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def getipinfobyipapi(ip):
api_url='http://ip-api.com/json/'+ip
ipinfo={}
try:
req_return=requests.get(api_url)
if req_return.status_code==200:
ipinfo=json.loads(req_return.text)
ipinfo['ip'] = ip
ipinfo['source'] = 'ip-api.com'
ipinfo['loc'] = str(ipinfo['lat'])+','+str(ipinfo['lon'])
addIPInfo2DB(ipinfo)
except Exception as e:
print('未知错误 %s' % (e))
return ipinfo

从GeoLite离线库获取IP信息

如何获取GeoLite离线库及如何读取,详见:http://xiejava.ishareread.com/posts/2c5697c0/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def getipinfobygeoip2(ip):
ipinfo={}
dbdir=Config.geoLiteDBdir
with geoip2.database.Reader(dbdir) as reader:
response = reader.city(ip)
ipinfo['ip'] =ip
ipinfo['country'] = response.country.names['zh-CN']
ipinfo['region'] =''
ipinfo['city']=response.city.name
ipinfo['org'] =''
ipinfo['loc'] = str(response.location.latitude)+','+str(response.location.longitude)
ipinfo['timezone'] = response.location.time_zone
ipinfo['source'] = 'GeoIP'
addIPInfo2DB(ipinfo)
return ipinfo

四、搭建一个FLASK Web应用来查询聚合的域名、IP情报信息

1、FLASK Web应用的工程组织

工程组织

2、配置数据及读取配置数据

1)配置数据

配置数据分别放在.env及.flaskenv中,其中.env放的是工程中用到的数据库链接等比较私密的配置信息。.flaskenv放的是Flask运行环境的信息
.env的配置信息参考如下:

1
2
3
4
5
6
DEV_DATABASE_URI = 'mysql+pymysql://dbuser:yourpassword@127.0.0.1:3306/infocol_db_dev?charset=utf8'
TEST_DATABASE_URI = 'mysql+pymysql://dbuser:yourpassword@127.0.0.1:3306/infocol_db_test?charset=utf8'
PROD_DATABASE_URI = 'mysql+pymysql://dbuser:yourpassword@127.0.0.1:3306/infocol_db?charset=utf8'

SQLALCHEMY_TRACK_MODIFICATIONS = True
SECRET_KEY=your secret key

.falskenv配置信息参考如下:

1
FLASK_ENV=development

2)实现读取配置数据

通过config.py实现配置数据的读取及管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import os
from dotenv import load_dotenv
basedir=os.path.abspath(os.path.dirname(__file__))
flaskenv_path=os.path.join(basedir,'.flaskenv')
env_path=os.path.join(basedir,'.env')
if os.path.exists(flaskenv_path):
load_dotenv(flaskenv_path)
if os.path.exists(env_path):
load_dotenv(env_path)

class Config:
geoLiteDBdir=os.path.join(basedir,'GeoLite2\GeoLite2-City.mmdb')
flaskenv = os.getenv('FLASK_ENV','development')
SECRET_KEY=os.getenv('SECRET_KEY','123!@#')
SQLALCHEMY_TRACK_MODIFICATIONS=os.getenv('SQLALCHEMY_TRACK_MODIFICATIONS')
SQLALCHEMY_DATABASE_URI = os.getenv('DEV_DATABASE_URI')
@staticmethod
def init_app(app):
pass

class DevelopmentConfig(Config):
DEBUG=True
SQLALCHEMY_DATABASE_URI = os.getenv('DEV_DATABASE_URI')

class TestingConfig(Config):
TESTING=True
SQLALCHEMY_DATABASE_URI = os.getenv('TEST_DATABASE_URI')

class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = os.getenv('PROD_DATABASE_URI')

config={
'development':DevelopmentConfig,
'testing':TestingConfig,
'production':ProductionConfig,
'default':DevelopmentConfig
}

3、界面及路由

界面很简单就一个域名/IP的输入框,输入域名或IP后去查询相应的域名信息或IP信息显示到界面上。
index界面

界面用jinjia2的模板
index.html代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
{% extends "bootstrap/base.html" %}
{% block title %}InfoCol{% endblock %}
{% block head %}
{{ super() }}
<style></style>
{% endblock %}
{% block body %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">InfoCol</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
<div class="page-header " >
<form method="post" class="center-block">
<div class="center-block" style="text-align:center">
{{ form.hidden_tag() }}
{{ form.name.label }}{{ form.name() }}
{{ form.submit() }}
</div>
</form>
</div>
<div>
{% if whois_info %}
<table class="table table-bordered">
<tr><th colspan="2">{{ name }}的Whois信息</th></tr>
{% for item in whois_info %}
{% if item!='详情' %}
<tr><td style="width: 20%">{{ item }}</td><td style="width: 80%">{{ whois_info[item] }}</td></tr>
{% else %}
<tr>
<td style="width: 20%">
<a role="button" data-toggle="collapse" href="#collapseExample" aria-expanded="false" aria-controls="collapseExample">
{{ item }}
</a>
</td>
<td style="width: 80%">
<div class="collapse" id="collapseExample">
<div class="well">
{{ whois_info[item] }}
</div>
</div>
</td>
</tr>
{% endif %}
{% endfor %}
</table>
{% endif %}
{% if ipinfos|length>0 %}
<table class="table table-bordered">
<tr><th>IP</th><th>国家/地区</th><th>省份</th><th>城市</th><th>机构</th><th>ISP</th><th>经纬度</th><th>来源</th></tr>
{% for ipinfo in ipinfos %}
<tr>
<td>{{ ipinfo['ip'] }}</td>
<td>{{ ipinfo['country'] }}</td>
<td>{{ ipinfo['region'] }}</td>
<td>{{ ipinfo['city'] }}</td>
<td>{{ ipinfo['org'] }}</td>
<td>{{ ipinfo['isp'] }}</td>
<td>{{ ipinfo['loc'] }}</td>
<td>
{% if ipinfo['source']=='ipinfo.io' %}
<a href="http://ipinfo.io/{{ ipinfo['ip'] }}" target="_blank">{{ ipinfo['source'] }}</a>
{% elif ipinfo['source']=='ip-api.com'%}
<a href="http://ip-api.com/json/{{ ipinfo['ip'] }}" target="_blank">{{ ipinfo['source'] }}</a>
{% else %}
{{ ipinfo['source'] }}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
</div>
{% endblock %}
{% endblock %}

路由配置处理中实现了获取表单中的信息,并判断是域名还是IP如果是域名者获取whois信息,并根据域名获取IP信息。如果输入的是IP则获取IP信息,并反馈到页面上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@index_bp.route('/',methods=['GET','POST'])
def index():
name = ''
ipinfos = []
whois_info = ''
form = InputForm()
if form.validate_on_submit():
name = form.name.data
if checkip(name):
ipinfos = getipinfo(name)
else:
whois_info = getwhoisinfo(name)
whois_ip = getIPbyDomain(name)
if checkip(whois_ip):
ipinfos = getipinfo(whois_ip)
form.name.data = ''
return render_template('index.html',form=form, name=name, ipinfos=ipinfos, whois_info=whois_info)

4、最终实现效果

界面查询效果

至此通过Python快速实现了一个简单的域名、IP信息聚合网站


全部源代码:https://github.com/xiejava1018/infocollect

演示地址:http://test.ishareread.com/

博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

Python爬虫获取电子书资源实战

发表于 2021-11-20 | 更新于: 2024-06-13 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 1.6k | 阅读时长 ≈ 7

最近在学习Python,相对java来说python简单易学、语法简单,工具丰富,开箱即用,适用面广做全栈开发那是极好的,对于小型应用的开发,虽然运行效率慢点,但开发效率极高。大大提高了咱们的生产力。为什么python能够在这几年火起来,自然有他的道理,当然也受益于这几年大数据和AI的火。

据说网络上80%的爬虫都是用python写的,不得不说python写爬虫真的是so easy。基本上一个不太复杂的网站可以通过python用100多行代码就能实现你所需要的爬取。
现在就以一个电子书的网站为例来实现python爬虫获取电子书资源。爬取整站的电子书资源,按目录保存到本地,并形成索引文件方便查找。

爬取的目标网站:苦瓜书盘

步骤:爬取->分析、解析->保存

对于一个不需要登录验证的资源分享类的网站,爬取最大的工作量应该是在对目标页面的分析、解析、识别,这里用的到是Python的BeautifulSoup库。

一、获取目录

二、获取书籍列表页

三、获取书籍详情页

四、分析书籍详情页的资源地址

五、下载并保存

准备

引入相应的包,设置 headerd, 和资源保存路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests
import os
import re
from bs4 import BeautifulSoup
import time
import json
from Book import Book

savepath="J://kgbook//books//" #保存地址
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
main_url='https://kgbook.com/'
bookcount=0

一、获取目录

获取目录
通过浏览器的调试工具可以看到目录在id=catagory的div标签下,下面还有ul和li标签,那我们可以迭代li可以获得目录及目录页的地址。
可以通过soup.find_all(attrs={‘id’: ‘category’})[0].ul 获取 到ul标签,然后获取ul的li标签,进行迭代获取。
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
'''
获取目录
'''
def getcategory():
req_result=requests.get(main_url,headers=headers)
if req_result.status_code==200:
htmlstr=req_result.content.decode('utf-8')
soup = BeautifulSoup(htmlstr, 'lxml')
categorys=soup.find_all(attrs={'id': 'category'})[0].ul
for li in categorys.find_all(name='li'):
print('开始抓取'+li.a.attrs['href']+"--"+li.string)
getcategroydetail(main_url+li.a.attrs['href'],li.string)
time.sleep(1)

二、获取书籍列表页

在书籍列表页,我们要获取两个信息,分别是书籍列表的信息及翻页下一页书籍列表的URL地址。
通过浏览器的调试工具分别对列表的信息及翻页下一页的html进行分析。
获取书籍列表页
列表中的书籍详情页信息在class=”channel-item”的div标签下,通过class=”list-title”的h3标签循环迭代
翻页
下一页,我们可以直接通过next_pag=soup.find(name=’a’,text=re.compile(‘下一页’))来获取。
然后我们可以通过递归来不断的调用获取下一页书籍列表页的代码,知道没有下一页为止。就可以把怎个目录都可以爬取完。
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'''
获取书籍列表
'''
def getbookslist(bookurlstr,categroy_path):
book_result=requests.get(bookurlstr,headers=headers)
bookhtmlstr=book_result.content.decode('utf-8')
soup = BeautifulSoup(bookhtmlstr, 'lxml')
booklists=soup.select('.channel-item')
for bookinfo_div in booklists:
booktitle_div=bookinfo_div.select('.list-title')[0]
bookurl=booktitle_div.a.attrs['href']
getbookdetail(bookurl,categroy_path)
next_pag=soup.find(name='a',text=re.compile('下一页'))
if next_pag is not None:
next_url=next_pag.attrs['href']
print('爬取下一页:'+next_url)
getbookslist(next_url,categroy_path)

三、获取书籍详情页

我们要在书籍详情页需要获得书籍详情信息包括书名、作者等信息
书籍详情
关于书名和作者可以分别通过提取class=”news_title”的h1标签和id=”news_details”的div下的ul下的li再通过正则表达式对作者信息进行提取。

1
2
3
4
booktitle=bookdetailsoup.select('.news_title')[0].text.strip()
bookauthor=bookdetailsoup.select('#news_details')[0].ul.li.find(text=re.compile('作者:(.*?)')).strip()
bookauthor=bookauthor.replace('作者:','')
booktitleinfo="《"+booktitle+'》-'+bookauthor

四、分析书籍详情页的资源地址

在书籍详情页,我们还要分析书籍详情页的资源地址
资源地址
电子书的资源下载地址可以通过提取a标签的信息来获取。通过正则表达式分别匹配azw3、mobi、epub分别提取不同的电子书资源。
book_url_item=bookdetailsoup.find(name=’a’,text=re.compile(booktype,re.I))
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
'''
根据书籍资源类型下载资源
'''
def getbookfortype(bookurl,categroy_path,bookdetailsoup,booktype):
booktitle=bookdetailsoup.select('.news_title')[0].text.strip()
bookauthor=bookdetailsoup.select('#news_details')[0].ul.li.find(text=re.compile('作者:(.*?)')).strip()
bookauthor=bookauthor.replace('作者:','')
booktitleinfo="《"+booktitle+'》-'+bookauthor
print('书籍详情:---'+booktitleinfo)
book_url_item=bookdetailsoup.find(name='a',text=re.compile(booktype,re.I))
if book_url_item is not None:
downloadurl=book_url_item.attrs['href']
print('下载地址:'+downloadurl)
if checkIfNoExistBookByUrl(downloadurl):
r = requests.get(downloadurl)
if r.status_code==200:
savepath=createdir(categroy_path,booktitleinfo)
filename=booktitle+"."+booktype
savebook(r.content,savepath,filename)
p,f=os.path.split(categroy_path)
bookcategory=f
book=Book(bookcategory,booktitle,bookauthor,bookurl,downloadurl,savepath,"苦瓜书盘",booktype)
print(book.toString())
savebooktojson(book)
else:
print('下载失败:status_code='+str(r.status_code))
else:
print('没有'+booktype+'格式的书')

五、下载并保存
有了资源的下载资源后下载就变得很简单了,主要用python的os库,对文件进行操作,包括建目录及保存资源文件。也可以通过连接数据库将爬取的数据保存到数据库。
定义书籍类Book用于组织和保存数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Book(object):

def __init__(self,bookcategory,bookname,bookauthor,bookurl,bookdownloadurl,booksavepath,booksource,booktype):
self.bookcategory=bookcategory
self.bookname=bookname
self.bookauthor=bookauthor
self.bookurl=bookurl
self.bookdownloadurl=bookdownloadurl
self.booksavepath=booksavepath
self.booksource=booksource
self.booktype=booktype

def toString(self):
return {"bookcategory":self.bookcategory,"bookname":self.bookname,"bookauthor":self.bookauthor,"bookurl":self.bookurl,"bookdownloadurl":self.bookdownloadurl,"booksavepath":self.booksavepath,"booksource":self.booksource,"booktype":self.booktype}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'''
将获取的信息保存至文件
'''
def savebooktojson(book):
bookdata={
'booksource':book.booksource,
'booktype':book.booktype,
'bookcategory':book.bookcategory,
'bookname':book.bookname,
'bookauthor':book.bookauthor,
'bookurl':book.bookurl,
'bookdownloadurl':book.bookdownloadurl,
'booksavepath':book.booksavepath
}
bookjson=json.dumps(bookdata,ensure_ascii=False) #ensure_ascii=False 就不会用 ASCII 编码,中文就可以正常显示了
print(bookjson)
with open('data.json', 'a',encoding='gbk') as file:
file.write(bookjson+'\n')
1
2
3
4
5
6
7
8
9
10
11
12
'''
根据目录创建文件夹
'''
def createdir(savepath,dir):
path=os.path.join(savepath,dir)
isExists=os.path.exists(path)
if isExists:
print('已经存在'+dir)
else:
print('创建目录'+dir)
os.mkdir(path)
return path
1
2
3
4
5
6
7
'''
下载书籍资源
'''
def savebook(content,savepath,savefilename):
savefile=os.path.join(savepath,savefilename)
with open(savefile, "wb") as code:
code.write(content)

运行效果如下:

1、爬取过程
爬取过程
2、爬取记录的json信息
data.json的信息如下:
爬取记录
3、爬取获取的资源
按目录都已经整理好了,够你看的了。
获取的资源

​
Python爬虫获取电子书资源实战的全部代码,包括爬取->分析、解析->保存至本地及数据库。下载

​github: https://github.com/xiejava1018/getbooks


博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

你有了一个目标,于是你有了一堆技能,而不是反过来!

发表于 2021-11-17 | 更新于: 2024-08-17 | 分类于 人生 | | 阅读次数:
字数统计: 990 | 阅读时长 ≈ 3

目标

你有了一个目标,于是你有了一堆技能。而不是反过来!
这应该是这段时间我领悟最深刻的一句话,是从白帽汇-赵武的微信文章中看到的。
我的体会是,没有一个清晰的为之努力奋斗的目标而去学东西,很难获得效果。

老实说,我并不是个懒惰的人,知道要不断的去学习、看书,来努力提升自己,但是几年下来自己的个人成长确是非常的有限,原因就是目标不明确。尤其是随着年龄的增大,面对越来越大的压力,越来越焦虑。焦虑是因为面对残酷的社会竞争压力以及对自身能力的不自信。所以很多东西都想学,机器学习、网络安全、英语、写作等等。没有明确的目标和整体的规划,只知道要学,桌上摆了很多书,今天看几页这本书,明天翻几页那本书,看上去天天在看书,实际上一本书都没有看进去。看英语的时候在想应该多花点时间看看专业书,看专业书的时候在想英语也很重要,要不看会英语。实际就是有限的时间精力和无限的需要学习的知识之间的矛盾。还有一个突出的问题就是没有明确的目标就会没有成就感,尤其是专业领域,看了很多书,不能学以致用,看了就忘,感觉就是学了个寂寞。

学习,目标非常重要,没有明确目标的学习到头来都是浪费时间。学习效果好、状态好的往往是带着明确的目标去学的。记得我才参加工作的时候做网页开发那时候啥都不懂,我的目标就是想成为一名真正的程序员。那时候BBS和聊天室很火,就想自己能够写一个BBS和聊天室,于是自己学Java、 jsp、HTML、javascript、数据库等。那时候上外网还比较奢侈,自己写了一个聊天室放到公司内网,公司几十百把号人玩得不亦乐乎。大家玩聊天室的时候还不断的给我提建议提需求,我白天上班,晚上改我的聊天室代码。看着自己的成果被别人用心里挺开心的。那段时间感觉自己成长很快,学到了很多东西。很快成为了公司主力程序员。还有个例子就是有段时间想学英语,给自己定的目标就是看完全套的《书虫》,有了目标后每天坚持看几十页,花了几个月的时间把全套的149本书虫给看完了。自己感觉还是非常的好,英语阅读能力有了一定的提升。但是这个目标实现了以后,没有重新给自己制定新的目标,所以自己的英语水平一直没有达到自己理想的状态。应该规划好终极目标、长期目标、阶段性目标,通过实现一个个小目标最终达到自己理想的终极目标。

懂得了很多大道理依旧无法过好这一生,其实就是没有一个明确的人生目标,没有一个让自己为之奋斗的目标,目标感强的人往往都会比较成功。可以说项目管理也好,个人管理也好,归根到底都是目标管理。为了实现目标、投入时间、金钱、精力等各种已有的资源,用各种手段,思考各种方法来达到目标。

定方向、定目标非常重要!

作者博客:http://xiejava.ishareread.com/


关注:“爱分享读书”微信公众号

“爱分享读书”微信公众号

读书我们是认真的

CentOS7下配置Supervisor自启动的两种方法

发表于 2021-11-11 | 更新于: 2024-06-13 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 529 | 阅读时长 ≈ 2

很多网友留言问如何配置Supervisor 自启动,现将如何在CentOS7下配置Supervisor自启动的两种方法整理如下:

一、方法一

直接将启动命令加入到/etc/rc.d/rc.local中(简单但不推荐)

1
vi /etc/rc.d/rc.local

在现有的内容后面加入supervisor的启动命令
supervisord -c /etc/supervisord.conf
/etc/rc.d/rc.local
注意:一定要执行 chmod +x /etc/rc.d/rc.local

chmod +x /etc/rc.d/rc.local

给文件加入可执行权限
根据官方的提示,该方式是不被建议的,强烈建议创建自己的systemd services或udev规则来启动自已的应用,也就是方法二。

二、方法二

通过创建systemd services来实现自启动 (推荐)
进入到/usr/lib/systemd/system/目录

1
[root@localhost ~]# cd /usr/lib/systemd/system/

找到supervisord及supervisorctl命令的路径

1
2
3
4
[root@localhost system]# which supervisord
/usr/local/bin/supervisord
[root@localhost system]# which supervisorctl
/usr/local/bin/supervisorctl

创建文件supervisord.service

1
vi supervisord.service

复制以下代码。注意:supervisord及supervisorctl命令的路径根据实际情况进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#supervisord.service

[Unit]
Description=Supervisor daemon

[Service]
Type=forking
ExecStart=/usr/local/bin/supervisord -c /etc/supervisord.conf
ExecStop=/usr/local/bin/supervisorctl shutdown
ExecReload=/usr/local/bin/supervisorctl reload
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

启用服务

1
2
[root@localhost system]# systemctl enable supervisord
Created symlink from /etc/systemd/system/multi-user.target.wants/supervisord.service to /usr/lib/systemd/system/supervisord.service

启动服务

1
[root@localhost ~]# systemctl start supervisord

查看服务状态

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# systemctl status supervisord
● supervisord.service - Supervisor daemon
Loaded: loaded (/usr/lib/systemd/system/supervisord.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2021-11-11 11:11:36 CST; 12s ago
Process: 3822 ExecStart=/usr/local/bin/supervisord -c /etc/supervisord.conf (code=exited, status=0/SUCCESS)
Main PID: 3850 (supervisord)
CGroup: /system.slice/supervisord.service
├─3850 /usr/local/bin/python3.8 /usr/local/bin/supervisord -c /etc/supervisord.conf
├─3916 uwsgi --ini /home/flask_web/uwsgi.ini
├─3918 uwsgi --ini /home/flask_web/uwsgi.ini
└─3919 uwsgi --ini /home/flask_web/uwsgi.ini

验证一下是否为开机启动

1
2
[root@localhost system]# systemctl is-enabled supervisord
enabled

reboot重启服务器后,可以发现supervisor随服务器启动后自动启动了。

至此,本文介绍了CentOS7下配置Supervisor自启动的两种方法,推荐使用第二种方式。


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注微信公众号,一起学习、成长!

Python通过GeoIP获取IP信息(国家、城市、经纬度等)

发表于 2021-11-10 | 更新于: 2024-06-13 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 1.1k | 阅读时长 ≈ 4

IP地址信息是非常重要的情报信息,通过IP可以定位到该IP所在的国家、城市、经纬度等。
获取IP信息的方式有很多,很多服务商都提供了相应的地址库或API接口服务。
如国内的ipip.net,国外的ip-api.com、maxmind.com等。
很多公司都是使用Maxmind网站的IP信息库,里面包含着IP的详细信息,有付费的也有免费的,收费与免费的区别就是精准度和覆盖率。

本文介绍下载及定时更新Maxmind的离线库用python通过GeoIP来获取IP信息

一、下载GeoLite2离线地址库

1、注册及申请License Key

下载地址库之前先要在Maxmind网站注册同意相应的协议并登陆。

1)注册

访问 https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
Maxmiand注册导航
点击”Sign Up for GeoLite2” 根据输入框进行注册
Maxmiand注册表单
注意邮箱一定要正确,注册后会发邮件进行确认及修改密码。
根据注册的用户名和修改后的密码登陆就可以直接下载离线包了。
Maxmind账号信息
点击”Download Databases”进入到下载页面,可以看到提供了CSV及mmdb两种格式的离线库包,最近的更新时间为2021年11月02日。
MaxmiandGeoLite2地址库下载
由于IP地址信息是经常有变化的,Maxmind提供了geoipupdate工具来更新离线地址包。该工具使用需要申请账号和License Key

2)申请License Key

还是通过刚注册的引导页面,点击“Generate a License Key”
Maxmind生成License导航页
进如到页面后,点击“Generate new license key”
Generate new license key
License Key生成确定页
点击确定以后就会生成账号及License key
License key生成

2、下载并配置geoipupdate

https://github.com/maxmind/geoipupdate
这里有详细的安安装及配置说明

发行版本下载地址 https://github.com/maxmind/geoipupdate/releases
在这里插入图片描述

可以看到提供了各种平台的版本的下载链接,这里我们下载安装的是linux版本,点击下载“geoipupdate_4.8.0_linux_amd64.tar.gz”
在home目录下执行

1
wget https://github.com/maxmind/geoipupdate/releases/download/v4.8.0/geoipupdate_4.8.0_linux_amd64.tar.gz

下载至home目录

tar -zxvf geoipupdate_4.8.0_linux_amd64.tar.gz 进行解压
cd geoipupdate_4.8.0_linux_amd64 目录执行ls -alh查看目录内容,发现有两个关键文件,一个是getipupdate命令执行文件,一个是GeoIP.conf配置文件
geoipupdate目录

将执行命令拷贝到命令文件夹

1
cp geoipupdate /usr/local/bin/

geoipupdate命令读配置文件默认为/usr/local/etc/GeoIP.conf将配置文件拷贝到/usr/local/etc/下

1
cp GeoIP.conf /usr/local/etc/
1
vi /usr/local/etc/GeoIP.conf

修改GeoIP.conf
如上图修改离线库文件目录及账号、LicenseKey,AccountID和LicenseKey就是开始在Maxmind网站上申请的。

3、运行geoipupdate命令并加入定时任务

执行geoipupdate命令,在目录下面产生了GeoLite2-City.mmdb、GeoLite2-Country.mmdb两个离线库文件。
GeoLite2离线库文件
创建Linux定时任务,每周自动更新一下离线库文件

1
2
crontab -e
0 0 * * 0 /usr/local/bin/geoipupdate

二、通过Python调用GeoIP获取IP信息

默认已经安装好了Flask环境,并激活了python虚拟环境。激活python虚拟环境安装Flask教程见http://xiejava.ishareread.com/posts/7f405b25/

1、安装geoip2

1
pip install geoip2

2、编写hello.py调用geoip2

1
vi hello.py

复制以下代码到hello.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from flask import Flask
import geoip2.database

app = Flask(__name__)
reader=geoip2.database.Reader('/home/geoipupdate_4.8.0_linux_amd64/GeoLite2-City.mmdb')
@app.route("/")
def hello():
return "Hello World!"

@app.route("/getip/<ip>")
def getip(ip):
ipinfo=reader.city(ip)
ipinfo_json={'country':ipinfo.country.name,'city':ipinfo.city.name,'location':[ipinfo.location.longitude,ipinfo.location.latitude]}
return ipinfo_json

if __name__ == "__main__":
app.run(host='0.0.0.0',port=8080)

3、运行hello.py

1
2
3
4
5
6
7
8
9
(flask_web) [root@localhost flask_web]# python hello.py
* Serving Flask app 'hello' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on all addresses.
WARNING: This is a development server. Do not use it in a production deployment.
* Running on http://192.168.1.18:8080/ (Press CTRL+C to quit)

注意:如果linux开启了防火墙请关闭防火墙,或放开192.168.1.18

4、验证

通过浏览器访问 http://192.168.1.18:8080/getip/128.101.101.101
验证IP信息
可以看到返回IP的国家、城市、经纬度等信息。

至此,本文介绍了如何注册并下载GeoIP离线数据包,并通过官方提供的geoipupdate进行定期更新数据。还介绍了如何通过Python调用GeoIP获取IP信息。


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

CentOS7下python3+Flask+uWSGI+Nginx+Supervisor环境搭建

发表于 2021-11-05 | 更新于: 2024-06-13 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 1.9k | 阅读时长 ≈ 8

在生产环境中通常用uwsgi作为Flask的web服务网关,通过nginx反向代理进行负载均衡,通过supervior进行服务进行的管理。这一套搭下来还是有一些坑要踩,本文通过一个简单的Flask web应用记录了CentOS7下python3+Flask+uWSGI+Nginx+Supervisor环境搭建的全过程,以及一些注意事项,以免遗忘。

一、Python3环境安装

CentOS7下Python3环境安装参考 http://xiejava.ishareread.com/posts/57cef505/

查看python版本

1
2
[root@localhost ~]# python -V
Python 3.8.12

二、安装Flask

1、创建Python虚拟环境

在home目录下创建flask_web目录(目录根据具体实际环境创建,本教程是/home/flask_web)
通过venv创建虚拟环境
[root@localhost flask_web]# python -m venv /home/flask_web
创建成功后可以看到在目录下自动建了一些文件夹,包括python命令及依赖库等,激活以后是个独立的python虚拟运行环境。
python虚拟运行环境

在目录下运行source bin/activate 激活虚拟环境

1
2
[root@localhost flask_web]# source bin/activate
(flask_web) [root@localhost flask_web]#

2、安装Flask

通过pip install flask安装flask

1
(flask_web) [root@localhost flask_web]# pip install flask

安装的时候有可能报ModuleNotFoundError: No module named ‘_ctypes’的错误,原因是缺少libffi-devel包,具体可参考 https://blog.csdn.net/qq_36416904/article/details/79316972
安装Flask报错

运行yum install libffi-devel -y 并且要重新编译执行安装python
解决包依赖的问题
(flask_web) [root@localhost flask_web]# yum install libffi-devel -y
进入到python源码包目录 执行使用make&make install 命令重新编译并安装python(这里比较坑)
然后再pip install flask 进行安装
安装完成后可以尝试运行flask run,提示没有Flask应用程序,说明flask已经安装成功并且可以运行了。

1
2
3
4
5
6
7
8
9
(flask_web) [root@localhost flask_web]# flask run
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
Usage: flask run [OPTIONS]
Try 'flask run --help' for help.

Error: Could not locate a Flask application. You did not provide the "FLASK_APP" environment variable, and a "wsgi.py" or "app.py" module was not found in the current directory.

3、建立测试应用
vi hello.py创建一个hello.py的文件,copy下面的内容到文件中:wq保存退出

1
2
3
4
5
6
7
8
9
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World!"

if __name__ == "__main__":
app.run()

通过python hello.py运行测试程序

1
2
3
4
5
6
7
(flask_web) [root@localhost flask_web]# python hello.py
* Serving Flask app 'hello' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

新开一个shell窗口执行curl http://127.0.0.1:5000/ 可以看到有Hello World返回说明应用在flask框架下运行没有问题。

1
2
[root@localhost ~]# curl http://127.0.0.1:5000/
Hello World!

三、安装及配置uwsgi

uWSGI是一个Web Server,并且独占uwsgi协议,但是同时支持WSGI协议、HTTP协议等,它的功能是把HTTP协议转化成语言支持的网络协议供python使用。有点类似于Java的web服务容器中间件tomcat

1、安装uwsgi

通过pip命令安装

1
(flask_web) [root@localhost flask_web]# pip install uwsgi

如果顺利的话会显示Successfully installed uwsgi-2.0.20,表示安装成功了。

2、配置uwsgi

新建一个uwsgi.ini配置文件,并将配置信息复制到配置文件
vi uwsgi.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[uwsgi]
#http=127.0.0.1:3366 #如果是http,通过proxy_pass http链接
socket=127.0.0.1:3366 #如果是socket,通过nginx配置uwsgi_pass socket链接
wsgi-file=/home/flask_web/hello.py
callable=app
touch-reload=/home/flask_web/
#最大请求数,最多请求5000次就重启进程,以防止内存泄漏
max-requests=5000
#请求超时时间,超过60秒关闭请求
harakiri=60
#进程的数量
processes=1
#线程数
threads = 2
#记录pid的文件
pidfile=/home/flask_web/uwsgi.pid
buffer-size = 32768
#日志最大50M
log-maxsize=50000000
#配置虚拟环境路径,如果是在虚拟环境下启动,这个一定要配,不配会有些包找不到,应用会报错。可以在uwsgi.log文件中看报错信息
virtualenv =/home/flask_web
#uwsgi日志文件,如果是通过supervisor托管,daemonize配置需要屏蔽
#daemonize=/home/flask_web/uwsgi.log
#项目更新后,自动加载
python-autoreload=1
#状态检测地址
stats = 127.0.0.1:9191

3、运行uwsgi

1
(flask_web) [root@localhost flask_web]# uwsgi --ini /home/flask_web/uwsgi.ini

启动以后通过访问curl http://127.0.0.1:3366 有Hello World!的返回信息表示uwsgi已经成功启动,并且应用程序正常。

1
2
[root@localhost flask_web]# curl http://127.0.0.1:3366
Hello World!

四、配置Nginx反向代理

ps -ef|grep nginx 找到nginx的配置文件
nginx配置文件
如果uwsgi配置的是socket连接
[uwsgi]
socket=127.0.0.1:3366 #如果是socket,通过nginx配置uwsgi_pass socket链接
nginx的server配置如下:

1
2
3
4
5
6
7
8
9
10
11
server {
listen 808;
server_name localhost;

location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:3366;
}
access_log /home/flask_web/access.log;
error_log /home/flask_web/error.log;
}

如果uwsgi配置的是http
[uwsgi]
http=127.0.0.1:3366 #如果是http,通过proxy_pass http链接
nginx的server配置如下:

1
2
3
4
5
6
7
8
9
10
server {
listen 808;
server_name localhost;

location / {
proxy_pass http://127.0.0.1:3366;
}
access_log /home/flask_web/access.log;
error_log /home/flask_web/error.log;
}

重新加载nginx配置后,通过浏览器访问可以正常显示访问结果

五、通过Supervisor进行进程托管

生产环境中,可以通过supervisor来进行uwsgi和nginx进程的托管,界面化的方式管理uwsgi和nginx,包括进程的监控、启停等。

1、安装supervisor

通过pip安装

1
pip install supervisor

离线安装请参考:http://xiejava.ishareread.com/posts/d670c9b8/

2、配置supervisor

找到supervisord的安装目录在/usr/local/bin下

1
2
[root@localhost bin]# which supervisord
/usr/local/bin/supervisord

cd到/usr/local/bin目录下
通过echo_supervisord_conf > supervisord.conf

1
[root@localhost bin]# echo_supervisord_conf > supervisord.conf

可以看到生成了一个supervisord.conf的配置文件。
将生成的supervisord.conf配置文件放到/etc/目录下

1
mv supervisord.conf /etc/

修改supervisord.conf的配置文件,主要是将子配置文件路径开启并指定配置文件路径,按照惯例将配置文件放到/etc目录下

1
2
[include]
files = /etc/supervisord.d/*.ini

supervisord.conf配置文件

我们在/etc目录下建个supervisord.d目录用来保存supervisor托管进程的配置文件

1
2
[root@localhost ~]# cd /etc/
[root@localhost etc]# mkdir supervisord.d

建立并配置子配置文件

1
2
[root@localhost etc]# cd supervisord.d/
[root@localhost supervisord.d]# vi uwsgi.ini

复制以下内容至uwsgi.ini文件中

1
2
3
4
5
6
7
8
9
10
11
12
[program:uwsgi]
command =uwsgi --ini /home/flask_web/uwsgi.ini
directory=/home/flask_web
startsecs=10
startretries=5
autostart=true
autorestart=true
stdout_logfile=/home/flask_web/uwsgi_sup_log.log
stdout_logfile_maxbytes=10MB
user=root
stopasgroup=true
killasgroup=true

3、启动supervisor

在启动supervisor拉起uwsgi前两个注意事项

1) uwsgi的配置文件中daemonize一定要屏蔽掉,否则守护进程一直会重启,导致端口每次都被占用,Supervisor托管不了。
uwsgi.ini
2) 在启动之前先将已经启动的uwsgi进程停掉,否则通过supervisor拉起uwsgi进程时端口冲突
kill uwsgi进程

启动supervisord进程

1
[root@localhost bin]# supervisord -c /etc/supervisord.conf

修改配置文件后重新加载可以通过 supervisorctl reload 命令重新加载
查看supervisor托管状态

1
2
[root@localhost supervisord.d]# supervisorctl status
uwsgi STARTING

可以看到uwsgi被supervisor托管并已经启动。如果需要通过supervisor的web控制界面进行进程的管理。需要修改/etc/supervisord.conf的配置文件将访问的IP地址限制放开,设置用户名、口令

1
2
3
4
[inet_http_server]         ; inet (TCP) server disabled by default
port=*:9001 ; ip_address:port specifier, *:port for all iface
username=user ; default is no username (open server)
password=user@123 ; default is no password (open server)

重新启动supervisor,重启时会报需要验证的错误

1
2
3
[root@localhost supervisord.d]# supervisorctl shutdown
Server requires authentication
error: <class 'xmlrpc.client.ProtocolError'>, <ProtocolError for 127.0.0.1/RPC2: 401 Unauthorized>: file: /usr/local/lib/python3.8/site-packages/supervisor/xmlrpc.py line: 542

可以直接kill -9杀掉supervisor的进程再启动,也可以通过supervisorctl 输入用户名、口令通过shutdown然后再重启。
启动命令:supervisord -c /etc/supervisord.conf

这时就可以通过supervisor的web控制界面进行进程的管理了。
Supervisor
至此,CentOS7下python3+Flask+uWSGI+Nginx+Supervisor环境全部搭建好了。


作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

CentOS7下安装python3.8

发表于 2021-11-04 | 更新于: 2024-06-13 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 927 | 阅读时长 ≈ 4

环境的搭建是进行开发的第一步,python因为存在python2和python3两个版本,让在建立python环境时造成不便,并且由于在Linux环境下不像Window环境安装那么友好,存在一些小坑。本教程记录了CentOS7下安装python3.8的过程和注意事项。

一、查看系统版本

1
2
[root@localhost ~]# cat /etc/centos-release
CentOS Linux release 7.2.1511 (Core)
1
2
[root@localhost ~]# uname -a
Linux localhost.localdomain 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

查看python版本

1
2
[root@localhost ~]# python -V
Python 2.7.5

系统默认安装了Python 2.7.5

二、安装依赖

1
yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make

如果有提示一路选择Y就可以

三、下载python源码包

python官网https://www.python.org/ 目前python最新版本是python3.10
下载Python源码包

下载稳定版本3.8版

1
wget https://www.python.org/ftp/python/3.8.12/Python-3.8.12.tgz

四、解压安装python源码包

1、解压

1
tar -zxvf Python-3.8.12.tgz

2、安装

进入解压后的目录进行编译和安装

1
2
cd Python-3.8.12/
[root@localhost Python-3.8.12]#
1
[root@localhost Python-3.8.12]# ./configure
1
[root@localhost Python-3.8.12]# make&&make install

执行完后显示安装成功
pyhont安装成功

3、建立命令软链接

虽然python3.8.12安装成功了,但默认输入python还是显示是2.7版本的。如果要用python3.8.12需要输入python3即可,有时候不太方便。可以通过修改软链接的方式将默认的python指向python3.8.12。
先看一下默认的python及新安装的python3都安装在哪里

1
2
[root@localhost Python-3.8.12]# which python
/usr/bin/python
1
2
[root@localhost Python-3.8.12]# which python3
/usr/local/bin/python3

可以看到默认的python路径为/usr/bin/python,python3的路径为/usr/local/bin/python3
将python3的软链接加到python上

1
2
[root@localhost Python-3.8.12]# mv /usr/bin/python /usr/bin/python.bak
[root@localhost Python-3.8.12]# ln -s /usr/local/bin/python3 /usr/bin/python

通过python -V命令查看python版号,这时python的版本已经是3.8.12了。

1
2
[root@localhost Python-3.8.12]# python -V
Python 3.8.12

pip命令也可以修改,python3.8.12默认的pip是pip3,CentOS7的python2.7默认没有安装pip.
输入pip命令的时候提示命令没有找到

1
2
[root@localhost Python-3.8.12]# pip
bash: pip: command not found...

这时也可以通过建立软链接的方式将pip命令链接到pip3上。首先看pip3命令在哪?

1
2
[root@localhost Python-3.8.12]# which pip3
/usr/local/bin/pip3

然后建立pip到pip3的软链接

1
[root@localhost Python-3.8.12]# ln -s /usr/local/bin/pip3 /usr/bin/pip
1
2
[root@localhost Python-3.8.12]# pip -V
pip 21.1.1 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)

五、配置yum

安装python3改完软链接以后发现yum命令报错了,yum是依赖python2.7的,你把python改成了3.8了,所以报错了。

1
2
3
4
5
[root@localhost Python-3.8.12]# yum
File "/usr/bin/yum", line 30
except KeyboardInterrupt, e:
^
SyntaxError: invalid syntax

可以修改yum里对python2的依赖即可。虽然安装了python3但是系统里python2依旧还在系统里,可以通过python2来指定用python2.7的命令,首先来看下python2的命令在哪里

1
2
[root@localhost ~]# which python2
/usr/bin/python2

可以cd到/usr/bin目录下 通过ls -alh|grep python查看python命令的详细情况。

1
[root@localhost bin]# ls -alh|grep python

python命令软链接
可以看到python软连接是执行的python3命令,python2是执行的python2.7的命令

1
vi /usr/libexec/urlgrabber-ext-down

修改对python的依赖,修改成python2或python2.7都可以。
修改依赖

1
vi /usr/bin/yum

修改依赖

修改完这两个文件后,再敲yum命令就不会报错了。

至此CentOS7环境下python3.8.12已经成功安装!

作者博客:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

认识SOAR-安全事件编排自动化响应

发表于 2021-11-01 | 更新于: 2024-06-13 | 分类于 技术 , 网络安全 | | 阅读次数:
字数统计: 3.5k | 阅读时长 ≈ 11

SOAR是最近几年安全市场上最火热的词汇之一。SOAR究竟是什么,发展历程是什么,能够起什么作用,带着这些问题我们来认识一下SOAR。

一、SOAR是什么

SOAR 一词来自分析机构 Gartner,SOAR-Security Orchestration, Automation and Response 安全编排和自动化响应。在Gartner的报告里,SOAR平台的核心组件为,编排与自动化、工作流引擎、案例与工单管理、威胁情报管理。而SOAR体系则是三个概念的交叉重叠:SOAR=SOA+SIRP+TIP
1)精密编排的联动安全解决方案(SOA);
2)事件应急响应平台(SIRP);
3)威胁情报平台(TIP)。
SOAR

二、SOAR的发展历程

2015年,可以定义为SOAR的1.0时代。Gartner将SOAR(当时被认为是“安全运维分析和报告”)描述成为安全运维团队提供机器可读的安全数据报告和分析管理功能的产品。2017年,SOAR进入2.0时代。Gartner提出了“安全编排、自动化及响应”(SOAR)这个术语,用以描述脱胎于事件响应、安全自动化、场景管理和其他安全工具的一系列新兴平台。Gartner观察到三种以前截然不同的技术:安全编排和自动化(SOA)、安全事件响应平台(SIRPs)和威胁情报平台(TIPs),正在逐步融合到一起。
根据Gartner2019年最新定义,SOAR是指能使企业组织从SIEM等监控系统中收集报警信息,或通过与其它技术的集成和自动化协调,提供包括安全事件响应和威胁情报等功能。SOAR技术市场最终目标是将安全编排和自动化(SOA)、安全事件响应(SIR)和威胁情报平台(TIP)功能融合到单个解决方案中。
SOAR的演进

根据Gartner预测,到2022年,有30%大型企业组织(安全团队超过5人)将在安全和运维的工作中使用SOAR,这一比例远超当下5%。当下SOAR技术的早期拥护者是那些已经拥有成熟安全运维中心,并且能够理解SOAR带来好处的那些成熟的安全组织。

三、SOAR主要解决什么问题

随着网络安全攻防对抗的日趋激烈,网络安全单纯指望防范和阻止的策略已经失效,必须更加注重检测与响应。企业和组织要在网络已经遭受攻击的假定前提下构建集阻止、检测、响应和预防于一体的全新安全防护体系。在国际上,检测和响应类产品受到了极大的关注。放眼国内,更多的注意力集中到了新型检测产品,尤其是未知威胁检测领域。借助这些产品和技术,用户获得了更低的 MTTD(平均检测时间),能够更快更准确地检测出攻击和入侵。但是,这些产品和技术大都没有帮助用户降低 MTTR(平均响应时间)。事实上,对于用户而言,更快地检测出问题仅仅是第一步,如何快速地对问题进行响应更加重要。而在提升安全响应效率的时候,不能仅仅从单点(譬如单纯从端点或者网络)去考虑,还需要从全网整体安全运维的角度去考虑,要将分散的检测与响应机制整合起来。而这,正是 SOAR 要解决的问题。
Gartner指出,SOAR可供公司企业收集不同来源的安全威胁数据和警报,运用人机结合的方法进行事件分析与分类,根据标准流程辅助定义、排序和驱动标准化事件响应行为。SOAR主要为安全团队提供定制化的流程和控制,弥合并加速有效网络威胁的调查与缓解。安全运营团队的大量日常事务性工作也可以借助SOAR加以自动化。而且,案例战术手册还可以帮助分析师在单一平台上响应和缓解威胁,节约事件响应的每一分每一秒宝贵时间。
Gartner 用 OODA 模型,来描绘一个典型的安全运营流程。OODA 即 Observe(观察)、Orient(定位)、Decide(决策)、Act(行动)。

  • 观察:观察事件并确定发生了什么,即通过各种检测、分析工具,比如 SIEM 类工具,找到威胁线索,如告警。
  • 定位:确定观察的方向,并添加上下文来确定观察的含义,即对产生的告警的内容做调查、丰富化。比如查找外网域名的威胁情报,查找此 IP 的历史行为协助研判等等。
  • 决策:根据业务的风险容忍度和能力决定适当的响应行动,即判定是否需要对此告警采取行动,比如是否需要封禁,是否影响业务,是否需要进一步观察。
  • 行动:根据决定采取行动,并应用到观察过程中,然后重复,即执行确定的安全策略,并验证。每一步都对下一步提供了指导,周而复始,构成了一个良性促进的进化循环,不断优化企业的安全运营流程以应对不断变化的安全威胁。
    OODA 模型

OODA 环看起来逻辑清晰,易于操作。但事实上, OODA 环里的丰富化、调查取证、验证、执行安全策略变更等等,都是耗时耗力的工作。加上安全设备一直以来的误报问题产生的噪音,以及安全人员工作负荷重,资深从业人员短缺等原因,难以真正有效的推进 OODA 循环。更不用提在 HW 时段高强度的工作压力下,如何能够有条不紊的保持一贯的处置流程来处理每一个安全线索。SOAR 正是在这个背景下被提出,并被寄予厚望。SOAR 的核心,就是将安全流程或预案,即 OODA 循环的每一个实例,比如蠕虫爆发处理流程、挖矿病毒告警处理流程、疑似钓鱼邮件处理流程等等,数字化管理起来形成 Playbook。用自动化完成其中所有可能自动化的动作,无法自动的仍然交由人来处理,通过可视化编排工具将人、技术和流程有机的结合起来,形成标准统一的、可重复的、更高效的安全运营流程。

四、SOAR的核心功能

从SOAR安全编排自动化响应的字面定义来看SOAR应该具备三大核心能力,编排、自动化、响应

编排

SOAR中的关键词是编排,这是在使用自动化和响应之前必须构建的关键组件。SOAR的编排体现的是一种协调和决策的能力,针对复杂性的安全事件,通过编排将分析过程中各种复杂性分析流程和处理平台进行组合。分析涉及多种数据或平台,如SIEM分析平台、漏洞管理平台、情报数据、资产数据等。处置响应的编排也涉及到很多平台或设备,如EDR管理平台、运维管理平台、工单管理平台、WAF设备、防火墙等。仅仅以技术为中心的安全保障已不再能满足现状,将人员和流程的编排才能保证安全流程真正高效的运行。SOAR的终极目标就是实现技术、流程、人员的无缝编排。

自动化

SOAR的自动化体现在三个方面,面对需要处理的安全事件能够根据策略自动选择编排的剧本、自动执行剧本的操作流程、根据决策结果自动联动设备进行防护阻断等行动策略。它允许剧本(常称为Playbooks)在安全流程的部分或全部内容上执行多个任务,将线性剧本串联起来。虽然线性剧本可能更容易创建,但只适用于处理决策需求较少的工作流。编排和自动化比线性剧本的最大优势就是其灵活性,为支持全自动化和半自动化的决策,需要更加灵活的工作流和执行剧本。SOAR能够识别这些决策模式,并基于以往事件中的执行操作,自动推荐新事件的剧本、执行剧本操作流程,自动化分析决策,根据决策结果自动下发防护阻断的行动策略。

响应

安全事件响应包括告警管理、工单管理、案件管理等功能。告警管理的核心不仅是对告警安全事件的收集、展示和响应,更强调告警分诊和告警调查。只有通过告警分诊和告警调查才能提升告警的质量,减少告警的数量。工单管理适用于中大型的安全运维团队协同化、流程化地进行告警处置与响应,并且确保响应过程可记录、可度量、可考核。案件管理是现代安全事件响应管理的核心能力。案件管理帮助用户对一组相关的告警进行流程化、持续化的调查分析与响应处置,并不断积累该案件相关的痕迹物证 (IOC) 和攻击者的战技过程指标信息 (TTP)。多个案件并行执行,从而持续化地对一系列安全事件进行追踪处置。
SOAR事件响应

事件响应是SOC操作中非常复杂的部分,理想状态下,它将是一个有效的动态过程,涉及数十种相互关联的技术、IT、业务流程和整个组织的人员,将是持续性适应风险和信任评估(Continuous Adaptive Risk and Trust Assessment, CARTA)策略用于在持续监测和可视性方面时,SOC团队可使用SOAR技术执行连续活动,利用SOAR技术通过智能化编排与响应最大程度的将已有安全技术进行整合,提高整个安全事件的解决能力和效率。基于编排和自动化前期对事件的分析,SOAR所提供的响应技术是完善整个事件生命周期,提高解决安全威胁效率的关键一环。本质上,SOAR的最终目标是促进安全团队对事件有全面的、端到端的理解,完成更好、更明智响应。

五、SOAR的价值

1、缩短响应时间
通过自动化技术,尽可能多的自动完成一个安全事件处置流程中相关步骤,从而缩短响应时间即 MTTR。
2、释放人力
让安全专家从繁重的重复劳动中释放出来,将时间放在更有价值的安全分析、威胁猎捕、流程建立等工作上。
3、安全运营流程标准化
将公司的安全运营流程数字化管理起来,每一次安全事件的对应处置过程都在统一标准,统一步骤下执行,有迹可循。避免人员能力的差距导致的处置实际效果不可控。
4、避免能力断层
将安全专家的经验固化成处置预案Playbook,让不同的人都可以遵循同样的方法来完成特定安全事件的处置流程,避免因为个人的离职导致某个领域的安全能力缺失。
5、运营流程指标可度量
因为运营流程都通过 Playbook 数字化管理且每一次的执行过程都记录在案,因此流程的 KPI 如 MTTD、MTTR、TTQ、TTI 等全部可评估、可度量、可追踪。
6、安全运营决策支撑
通过对公司的所有运营流程数字化管理、数字化执行、数字化KPI评估后,管理者可以有效的评估什么流程基本无用,什么流程执行效率不高,什么流程发挥了最大的作用,甚至什么安全设备在所有流程中被使用的价值最大。从而为以后的安全投资决策,安全团队建设决策提供有价值的数值化支撑。

六、SOAR与其他安全产品的关系

SOAR与其他安全产品的关系

SOAR定位于安全运营操作平台,它收集不同来源的安全威胁数据和警报,事件来源于其他的态势感知平台、SIEM、日志分析系统或安全人员人工录入需要处理的事件。通过调用安全设备的能力如:情报平台、资产管理平台、漏洞扫描平台、EDR管理平台、运维管理平台、工单管理平台、WAF设备、防火墙来实现对安全事件的分析、溯源、取证、处置、通知等。一端接安全事件源,一端对接安全设备能力。通过SOAR本身的编排能力将人员、设备、资源、流程协同起来。每个企业部署流程和技术并不相同,SOAR在实际落地应用过程中并不能“即插即用”,需要对接事件源、对接各类联动处置设备,根据企业具体的实际情况定制剧本流程。对接的实际安全设备能力数量以及剧本的积累,是SOAR平台能够很好的支持运营的关键。

作者博客:http://xiejava.ishareread.com/

<1…161718…21>
XieJava

XieJava

201 日志
11 分类
26 标签
RSS
GitHub
友情链接
  • 爱分享读书
  • CSDN
  • 豆瓣
© 2025 XieJava | Site words total count: 416.3k

主题 — NexT.Muse
0%