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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 域名和IP地址信息是非常基础的情报信息,目前网上有很多网站都提供了域名信息的查询、IP地址及归属地的查询。本文通过Python Flask实现域名及IP情报信息的聚合网站。因为域名和IP地址信息会有变化,为了减少接口压力,做了本地数据库的存储,新鲜度保存一周,每次查询先从本地数据库获取信息,如果本地库信息有并且没有超过一个星期就从本地库取,没有就从其他网站获取,并更新到本地库。

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

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

一、获取域名WHOIS信息

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

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代码:

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信息

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信息

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信息

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/

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的配置信息参考如下:

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配置信息参考如下:

FLASK_ENV=development

2)实现读取配置数据

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

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代码如下:

{% 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信息,并反馈到页面上。

@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/

目录
相关文章
|
21天前
|
缓存 算法 API
查询域名WHOIS信息免费API接口教程
该API用于查询顶级域名的WHOIS信息,不支持国别域名和中文域名。通过POST或GET请求,需提供用户ID、KEY及待查询域名。返回信息包括域名状态、注册商、时间等详细数据。示例与文档见官网。
|
1月前
|
缓存 监控 Linux
Python 实时获取Linux服务器信息
Python 实时获取Linux服务器信息
|
1月前
|
存储 数据采集 数据库
用 Python 爬取淘宝商品价格信息时需要注意什么?
使用 Python 爬取淘宝商品价格信息时,需注意法律和道德规范,遵守法律法规和平台规定,避免非法用途。技术上,可选择 Selenium 和 Requests 库,处理反爬措施如 IP 限制、验证码识别和请求频率控制。解析页面数据时,确定数据位置并清洗格式。数据存储可选择 CSV、Excel、JSON 或数据库,定期更新并去重。还需进行错误处理和日志记录,确保爬虫稳定运行。
|
1月前
|
数据采集 Web App开发 iOS开发
如何利用 Python 的爬虫技术获取淘宝天猫商品的价格信息?
本文介绍了使用 Python 爬虫技术获取淘宝天猫商品价格信息的两种方法。方法一使用 Selenium 模拟浏览器操作,通过定位页面元素获取价格;方法二使用 Requests 和正则表达式直接请求页面内容并提取价格。每种方法都有详细步骤和代码示例,但需注意反爬措施和法律法规。
|
24天前
|
数据采集 API 定位技术
Python技术进阶:动态代理IP的跨境电商解决方案
Python技术进阶:动态代理IP的跨境电商解决方案
|
2月前
|
小程序 Python
利用Python编程提取身份证的信息
利用Python编程提取身份证的信息
34 2
|
2月前
|
iOS开发 MacOS Python
Python编程小案例—利用flask查询本机IP归属并输出网页图片
Python编程小案例—利用flask查询本机IP归属并输出网页图片
28 1
|
2月前
|
IDE 开发工具 数据安全/隐私保护
Python编程--实现用户注册信息写入excel文件
Python编程--实现用户注册信息写入excel文件
23 1
|
2月前
|
Python
Python实现系统基础信息
Python实现系统基础信息
36 0
|
2月前
|
运维 安全 网络协议
Python 网络编程:端口检测与IP解析
本文介绍了使用Python进行网络编程的两个重要技能:检查端口状态和根据IP地址解析主机名。通过`socket`库实现端口扫描和主机名解析的功能,并提供了详细的示例代码。文章最后还展示了如何整合这两部分代码,实现一个简单的命令行端口扫描器,适用于网络故障排查和安全审计。
54 0