XieJava's blog

记录最好的自己


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于

穷忙与假努力

发表于 2021-12-28 | 更新于: 2025-07-11 | 分类于 人生 | | 阅读次数:
字数统计: 1.4k | 阅读时长 ≈ 4

穷忙与假努力

穷忙与假努力

时间过得真快,只有几天2021年即将过去。每次到了年底回想起来总是感觉时间过得真快,忙忙碌碌又过了一年,可自己各方面取得的成绩乏善可陈。自己并不是很懒惰的人,看上去每天都很忙,却没有忙出效果,反而是随着年龄的增大越来越焦虑。越焦虑就暗自下决心以后要更加努力,当努力没有达到效果时就更加的焦虑。陷入了越努力->越失望->越焦虑的怪圈。

没有目标、没有效果的忙就是穷忙,看上去努力却实际没有效果的努力是假努力,穷忙和假努力往往是一同出现的,假努力造成了穷忙,穷忙成就了假努力。相对于不努力,有时候“假努力”会更加可怕!因为它像安慰剂一样,让你感觉是在努力而不自知,会让你陷入深深的自我怀疑,对自己失望,最后越来越糟,失去对学习、工作、生活的兴趣。

到底什么样的表现是“假努力”呢?有老师针对孩子们在学习上的表现列举了一些“假努力”表现,给了我很大的启发。

“假努力”表现一:上课只顾抄笔记,老师讲的都不听。
有很多同学在上课的时候表现得特别忙,看上去特别努力的在学习,老师黑板上写的,还是口头上说的,他们都会事无巨细地写下来。然而,对于老师们讲的是什么?本节课的重难点又是什么?他们全然无所谓,只顾着把这堂课发生的所有一切都记录下来。这样的“假努力”注定会让课堂的效率低下,让自己的努力完全沦为无用的“假努力”。

“假努力”表现二:花很多时间做笔记,课后却从来不去理解。
有第一种“假努力”的同学,往往都存在着“假努力”的第二种表现,那就是笔记写得非常非常多,但是至于笔者写的内容和知识点,他们都从来不看,更不会花时间去理解和搞懂笔记上的内容。这样花大力气写下的笔记,当然最终沦为无用功。

“假努力”表现三:只顾刷题,从来都不花时间总结。
还有一部分“假努力”的同学,每天花大量的时间刷题,而且他们往往还有一个显著的特征,那就是只管做题多少,从来不过问题目对错!那些错题,反复出现问题的题目,他们从来都是不管不顾,只觉得刷了足够的题目,自己的成绩自然而然会上升!然而,殊不知他们把大量的时间花在了已经会的题目上,那些不会、易错的题目还是永远会错。

“假努力”表现四:每天熬夜学习,白天学习效率低下。
不知道各位老师和同学有没有发现,几乎每一个中学班级里,总会出现这么一两个“夜晚学习狂魔”,他么总喜欢晚上搞学习,并且熬非常的时间,导致第二天整个人的精神状态都不好,白天的学习效率极其低下!最后陷入一个“白天该学的时候状态差,晚上不该学的时候拼命学”的死循环当中。

“假努力”表现五:没有目标和计划的去学习。
这种“假努力”的表现有一个典型的例子,比如某个同学们英语很差,想通过自己的努力学好英语,然后就从英语单词开始入手,每天背课本上的单词,而且无论什么时候都是从单词表的第一个单词去背起!这样无计划、无目标的努力,只会耗费巨大的时间和精力在重复学习之上!进而导致学习成绩的速度异常的缓慢!

从这些表现上来看,其实我们成年人在平时学习、工作中同样存在这些类似的问题。个人认为造成穷忙和假努力最大的问题是没有目标和计划。东一榔头、西一棒子,不知道自己到底要学什么,要学到一个什么样的程度。就像小时候课本里的小猴子去掰玉米,看什么捡什么,最后捡了芝麻丢了西瓜。另外一个就是要有系统化、体系化的思维去学习。只有系统化、体系化的去学习某个东西,建立该领域的知识体系结构体系才能在有体系结构的基础上进行积累,才能学得好,学得牢。现在公众号、抖音、知乎上碎片化的知识很多,哪怕你是天天上知乎去关注学习这些碎片化的知识而没有建立一个知识体系去有意识的去理解吸收的话,那就类似于花了很多时间去做笔记,去关注去了解,课后从来不去理解。给人感觉是看上去在很努力的学习,其实啥也没有学到。


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


“fullbug”微信公众号

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

新场地,新征程!

发表于 2021-12-10 | 更新于: 2025-07-11 | 分类于 人生 | | 阅读次数:
字数统计: 144 | 阅读时长 ≈ 1

服务数字经济,护航美好生活!

2021年12月09日通服网安研发团队强势入驻岳麓上大学科技城国家网络安全产业园。

新场地,新征程,数网络安全研发,还看通服网安!

通服网安揭牌

通服网安

通服网安研发团队

通服网安研发团队

通服网安研发大楼

通服网安研发大楼

通服网安研发大楼外景

通服网安研发大楼外景

通服网安前台

通服网安前台

展厅入口

通服网安展厅入口

通服网安展厅

通服网安展厅

通服网安研发楼展厅安全运营中心展示

通服网安研发楼展厅安全运营中心展示

没有网络安全就没有国家安全

没有网络安全就没有国家安全

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

发表于 2021-12-09 | 更新于: 2025-07-11 | 分类于 技术 , 开发 , 网络安全 | | 阅读次数:
字数统计: 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 | 更新于: 2025-07-11 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 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 | 更新于: 2025-07-11 | 分类于 技术 , 开发 , 网络安全 | | 阅读次数:
字数统计: 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 | 更新于: 2025-07-11 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 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 | 更新于: 2025-07-11 | 分类于 人生 | | 阅读次数:
字数统计: 990 | 阅读时长 ≈ 3

目标

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

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

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

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

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

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


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

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

读书我们是认真的

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

发表于 2021-11-11 | 更新于: 2025-07-11 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 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 | 更新于: 2025-07-11 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 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 | 更新于: 2025-07-11 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 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”微信公众号

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

<1…161718…21>
XieJava

XieJava

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

主题 — NexT.Muse
0%