python如何编写类似nmap的扫描工具


Posted in Python onNovember 06, 2020

本文主要是利用scapy包编写了一个简易扫描工具,支持ARP、ICMP、TCP、UDP发现扫描,支持TCP SYN、UDP端口扫描,如下:

usage: python scan.py <-p ping扫描类型> <-s 端口发现类型> [-t target] [--port ports]

简单扫描工具,可以进行存活扫描及端口扫描.
存活扫描包括:ARP扫描、ICMP扫描、TCP扫描、UDP扫描.
端口扫描包括:TCP SYN扫描、TCP ACK扫描、TCP FIN扫描.

optional arguments:
 -h, --help     show this help message and exit
 -v, --version   show program's version number and exit

target group:
 用于设置IP、PORT参数

 --target TARGET  target为IP或IP段,如192.168.1.1,192.168.1.x,或1
           92.168.1.1-254
 --port PORT    port为待扫描的端口,如21,80,...或21-80

ping group:
 用于开启存活扫描相关选项

 -p         开启存活扫描
 --ARP       启动ARP扫描
 --ICMP       启动ICMP扫描
 --TCP       启动TCP扫描
 --UDP       启动UDP扫描

port scan group:
 用于开启端口扫描相关选项

 -s         开启端口扫描
 --SYN       开启SYN扫描
 --ACK       开启ACK扫描
 --FIN       开启FIN扫描
 --UPORT      开启UDP端口扫描

utils group:
 用于开启扫描过程中的一些实用选项

 --timeout TIMEOUT 设置发包超时时间,默认0.5秒
 --retry RETRY   设置发包重试次数,默认不重试

以上做为说明,祝好运!

一、发现扫描

1.首先进行ARP扫描

python scan.py -p --target 192.168.1.1-254 --ARP
[+]IP: 192.168.1.1 => MAC: 14:75:90:xx:xx:xx
[+]IP: 192.168.1.111 => MAC: c6:36:55:xx:xx:xx
[+]总共耗时9.84091806412秒.

通过retry参数增加发包尝试次数,如下:

python scan.py -p --target 192.168.1.1-254 --ARP --retry 2
[+]IP: 192.168.1.1 => MAC: 14:75:90:xx:xx:xx
[+]IP: 192.168.1.111 => MAC: c6:36:55:xx:xx:xx
[+]IP: 192.168.1.102 => MAC: 58:1f:28:xx:xx:xx
[+]IP: 192.168.1.114 => MAC: 6c:8d:c1:xx:xx:xx
[+]IP: 192.168.1.103 => MAC: 84:38:38:xx:xx:xx
[+]总共耗时20.429942131秒.

2.使用ICMP扫描,若没有指定任何扫描类型参数,默认会启用ICMP扫描,如下:

python scan.py -p --target 192.168.1.1-254
[+]没有指定任何ping扫描方式,默认选择ICMP扫描
[+]IP:主机192.168.1.1 echo-reply.
[+]IP:主机192.168.1.111 echo-reply.
[+]总共耗时10.7177450657秒.

通过timeout参数,设置较长的超时,可以防止网络状况不好造成的丢包,如下:

python scan.py -p --target 192.168.1.1-254 --timeout 2
[+]没有指定任何ping扫描方式,默认选择ICMP扫描
[+]IP:主机192.168.1.1 echo-reply.
[+]IP:主机192.168.1.111 echo-reply.
[+]IP:主机192.168.1.114 echo-reply.
[+]总共耗时10.7566649914秒.

3.使用TCP扫描

python scan.py -p --target 192.168.1.100-120 --TCP --timeout 1
[+]请稍等,时间较长!
[!]扫描... 192.168.1.100
[!]扫描... 192.168.1.101
[!]扫描... 192.168.1.102
[!]扫描... 192.168.1.103
[!]扫描... 192.168.1.104
[!]扫描... 192.168.1.105
[!]扫描... 192.168.1.106
[!]扫描... 192.168.1.107
[!]扫描... 192.168.1.108
[!]扫描... 192.168.1.109
[!]扫描... 192.168.1.110
[!]扫描... 192.168.1.111
[!]扫描... 192.168.1.112
[!]扫描... 192.168.1.113
[!]扫描... 192.168.1.114
[!]扫描... 192.168.1.115
[!]扫描... 192.168.1.116
[!]扫描... 192.168.1.117
[!]扫描... 192.168.1.118
[!]扫描... 192.168.1.119
[!]扫描... 192.168.1.120
[+]正在处理扫描信息.
====================
[+]主机 192.168.1.102 在线.
[+]主机 192.168.1.103 在线.
[+]主机 192.168.1.111 在线.
[+]主机 192.168.1.114 在线.
[+]总共耗时16.4359779358秒.

4.使用UDP扫描

python scan.py -p --target 192.168.1.100-120 --UDP --retry 3
[+]请稍等,时间较长!
[!]扫描... 192.168.1.100
[!]扫描... 192.168.1.101
[!]扫描... 192.168.1.102
[!]扫描... 192.168.1.103
[!]扫描... 192.168.1.104
[!]扫描... 192.168.1.105
[!]扫描... 192.168.1.106
[!]扫描... 192.168.1.107
[!]扫描... 192.168.1.108
[!]扫描... 192.168.1.109
[!]扫描... 192.168.1.110
[!]扫描... 192.168.1.111
[!]扫描... 192.168.1.112
[!]扫描... 192.168.1.113
[!]扫描... 192.168.1.114
[!]扫描... 192.168.1.115
[!]扫描... 192.168.1.116
[!]扫描... 192.168.1.117
[!]扫描... 192.168.1.118
[!]扫描... 192.168.1.119
[!]扫描... 192.168.1.120
[+]正在处理扫描信息.


====================
[+]主机 192.168.1.102 在线.
[+]主机 192.168.1.103 在线.
[+]主机 192.168.1.111 在线.
[+]主机 192.168.1.114 在线.
[+]总共耗时33.5198891163秒.

二、端口扫描

1、TCP SYN端口扫描,不设置端口参数,则默认扫描1-1024端口

python scan.py --target 192.168.1.110-115 -s --SYN
[+]没有指定任何扫描端口,默认扫描1-1024
[!]扫描... 192.168.1.110
[!]扫描... 192.168.1.111
[!]扫描... 192.168.1.112
[!]扫描... 192.168.1.113
[!]扫描... 192.168.1.114
[!]扫描... 192.168.1.115
[+]正在处理扫描信息.


====================
[+]主机 192.168.1.111 开放的TCP端口有:[80]
[+]总共耗时165.125555992秒.

扫描指定端口:

python scan.py --target 192.168.1.1-254 -s --SYN --port 80 --timeout 1
[!]扫描... 192.168.1.1
[!]扫描... 192.168.1.2
[!]扫描... 192.168.1.3
[!]扫描... 192.168.1.4
...
[!]扫描... 192.168.1.253
[!]扫描... 192.168.1.254
[+]正在处理扫描信息.


====================
[+]主机 192.168.1.111 开放的TCP端口有:[80]
[+]主机 192.168.1.1 开放的TCP端口有:[80]
[+]总共耗时9.72222185135秒.

2、扫描UDP端口

python scan.py --target 192.168.1.1 -s --UPORT --timeout 1
[+]没有指定任何扫描端口,默认扫描1-1024
[!]扫描... 192.168.1.1
[+]正在处理扫描信息.
====================
[+]主机 192.168.1.1 开放的UDP端口有:[520]
[+]总共耗时27.4742250443秒.

也可同时进行发现扫描与端口扫描,如下:

python scan.py --target 192.168.1.1-254 -p --ARP -s --SYN --port 80 --timeout 1 --retry 2
[+]IP: 192.168.1.1 => MAC: 14:75:90:xx:xx:xx
[+]IP: 192.168.1.102 => MAC: 58:1f:28:xx:xx:xx
[+]IP: 192.168.1.114 => MAC: 6c:8d:c1:xx:xx:xx
[+]IP: 192.168.1.103 => MAC: 84:38:38:xx:xx:xx
[+]IP: 192.168.1.101 => MAC: 5c:f7:e6:xx:xx:xx
[!]扫描... 192.168.1.1
[!]扫描... 192.168.1.2
...
[!]扫描... 192.168.1.253
[!]扫描... 192.168.1.254
[+]正在处理扫描信息.


====================
[+]主机 192.168.1.1 开放的TCP端口有:[80]
[+]主机 192.168.1.111 开放的TCP端口有:[80]
[+]总共耗时45.2775988579秒.

OK,最后附上源码:

import argparse
import re
import time
import threading
from scapy.all import *

import logging
logging.getLogger('scapy.runtime').setLevel(logging.ERROR)


class Discovery_Scan(object):
  '''
  说明:用于发现扫描
  '''

  def __init__(self,args,timeout=0.5,retry=0):
    self.targets = parse_target(args)
    self.timeout = timeout
    self.retry = retry

  def arp_scan(self,pdst):
    #ARP发现扫描
    ans = sr1(ARP(pdst=pdst),timeout=self.timeout,retry=self.retry,verbose=False)
    if ans:
      if ans[ARP].op == 2:  #操作码为2是is-at,是ARP响应
        print '[+]IP: %s => MAC: %s' % (pdst,ans[ARP].hwsrc)

  def icmp_scan(self,dst):
    #ICMP发现扫描
    ans = sr1(IP(dst=dst)/ICMP(),timeout=self.timeout,retry=self.retry,verbose=False)
    if ans:
      if ans[ICMP].type == 0: #ICMP type为0表示是ICMP echo-reply
        print '[+]IP:主机%s echo-reply.' % dst

  tcp_info = {}
  def tcp_scan(self,dst,port):
    #TCP SYN,发送TCP SYN包,有响应表示端口开放
    ans,unans = sr(IP(dst=dst)/TCP(sport=RandShort(),dport=port,flags='S'),
            timeout=self.timeout,retry=self.retry,verbose=False)
    if ans.res:
      if ans.res[0][0][IP].dst not in Discovery_Scan.tcp_info:
        Discovery_Scan.tcp_info[ans.res[0][0][IP].dst] = True

  udp_info = {}
  def udp_scan(self,dst,port):
    #UDP,发送UDP包,有响应表示端口开放
    ans,uans = sr(IP(dst=dst)/UDP(sport=RandShort(),dport=port),
           timeout=self.timeout,retry=self.retry,verbose=False)
    if ans.res:
      if ans.res[0][0][IP].dst not in Discovery_Scan.udp_info:
        Discovery_Scan.udp_info[ans.res[0][0][IP].dst] = True

class Port_Scan(object):
  '''
  说明:用于进行端口扫描,判断端口是否开放
  '''
  def __init__(self,args,timeout=0.5,retry=0):
    self.targets = parse_target(args)
    self.timeout = timeout
    self.retry = retry

  syn_port_dict = {}
  def syn_port_scan(self,dst,port):
    #TCP SYN端口扫描,若SYN包返回携带SYN、ACK(即TCP.flags=18)标志的包,则表明此端口打开。
    ans,uans = sr(IP(dst=dst)/TCP(sport=RandShort(),dport=port,flags='S'),
           timeout=self.timeout,retry=self.retry,verbose=False)
    if ans:
      first_respons_pkt = ans.res[0][1]
      if first_respons_pkt[TCP] and first_respons_pkt[TCP].flags == 18:
        if first_respons_pkt[IP].src not in Port_Scan.syn_port_dict:
          Port_Scan.syn_port_dict[first_respons_pkt[IP].src] = [first_respons_pkt[TCP].sport]
        else:
          Port_Scan.syn_port_dict[first_respons_pkt[IP].src].append(first_respons_pkt[TCP].sport)

  udp_port_dict = {}
  def udp_port_scan(self,dst,port):
    #UDP端口扫描,若UDP端口返回ICMP port-unreachable,则表示端口打开。(排除某些主机对任何UDP端口的探测都响应为ICMP port-unrechable)
    ans,uans = sr(IP(dst=dst)/UDP(sport=RandShort(),dport=port),
           timeout=self.timeout, retry=self.retry, verbose=False)
    if ans.res and ans.res[0][1].haslayer(UDPerror):
      first_respons_pkt = ans.res[0][1]
      if first_respons_pkt[IP].src not in Port_Scan.udp_port_dict:
        Port_Scan.udp_port_dict[first_respons_pkt[IP].src] = [first_respons_pkt[UDPerror].dport]
      else:
        Port_Scan.udp_port_dict[first_respons_pkt[IP].src].append(first_respons_pkt[UDPerror].dport)

def parse_opt():
  '''
  @说明:通过argparse模块解析程序传入的参数
  @return:args
  '''
  usage = 'python %(prog)s <-p ping扫描类型> <-s 端口发现类型> [-t target] [--port ports]'
  description = '简单扫描工具,可以进行存活扫描及端口扫描.\n' \
         '存活扫描包括:ARP扫描、ICMP扫描、TCP扫描、UDP扫描.\n' \
         '端口扫描包括:TCP SYN扫描、TCP ACK扫描、TCP FIN扫描.'
  epilog = '以上做为说明,祝好运!'
  parser = argparse.ArgumentParser(usage=usage,description=description,epilog=epilog,version='v1.0')

  target_group = parser.add_argument_group('target group',description='用于设置IP、PORT参数')
  target_group.add_argument('--target',dest='target',action='store',
               help='target为IP或IP段,如192.168.1.1,192.168.1.x,或192.168.1.1-254')
  target_group.add_argument('--port',dest='port',action='store',
               help='port为待扫描的端口,如21,80,...或21-80')

  ping_group = parser.add_argument_group('ping group',description='用于开启存活扫描相关选项')
  ping_group.add_argument('-p',dest='ping',action='store_true',help='开启存活扫描')
  ping_group.add_argument('--ARP',dest='ARP',action='store_true',help='启动ARP扫描')
  ping_group.add_argument('--ICMP',dest='ICMP',action='store_true',help='启动ICMP扫描')
  ping_group.add_argument('--TCP',dest='TCP',action='store_true',help='启动TCP扫描')
  ping_group.add_argument('--UDP',dest='UDP',action='store_true',help='启动UDP扫描')

  port_scan_group = parser.add_argument_group('port scan group',description='用于开启端口扫描相关选项')
  port_scan_group.add_argument('-s',dest='scan',action='store_true',help='开启端口扫描')
  port_scan_group.add_argument('--SYN',dest='SYN',action='store_true',help='开启SYN扫描')
  port_scan_group.add_argument('--ACK',dest='ACK',action='store_true',help='开启ACK扫描')
  port_scan_group.add_argument('--FIN',dest='FIN',action='store_true',help='开启FIN扫描')
  port_scan_group.add_argument('--UPORT', dest='UPORT', action='store_true', help='开启UDP端口扫描')

  utils_group = parser.add_argument_group('utils group',description='用于开启扫描过程中的一些实用选项')
  utils_group.add_argument('--timeout',dest='timeout',action='store',type=float,help='设置发包超时时间,默认0.5秒')
  utils_group.add_argument('--retry',dest='retry',action='store',type=int,help='设置发包重试次数,默认不重试')

  args = parser.parse_args()
  if not args.ping and not args.scan:
    print '[-]必须通过-p/-s选项开启一种扫描'
    print '\n'
    parser.print_help()
    exit(1)
  elif not args.target:
    print '[-]必须通过--target选项指定扫描的对象'
    print '\n'
    parser.print_help()
    exit(1)
  if args.ping:
    if not args.ARP and not args.ICMP and not args.TCP and not args.UDP:
      args.ICMP = True #若没有指定任何ping扫描方式,则默认选择ICMP扫描
      print '[+]没有指定任何ping扫描方式,默认选择ICMP扫描'
  if args.scan:
    if not args.SYN and not args.ACK and not args.FIN and not args.UPORT:
      args.SYN = True  #若没有指定任何端口扫描方式,则默认选择SYN扫描
      print '[+]没有指定任何端口扫描方式,默认选择SYN扫描'
    if not args.port:
      args.port = '1-1024'  #若没有指定任何扫描端口,则默认扫描1-1024
      print '[+]没有指定任何扫描端口,默认扫描1-1024'

  return args

def parse_target(args):
  '''
  @说明:用于解析如'192.168.1.1,192.168.1.x,...或192.168.1.1-254'格式的IP为单独的IP,用于解析如'21,80,...或21-80'格式的端口为单独的端口
  @param: args,一个namespace对象
  @return: (ip_list,port_list)
  '''
  pattern1 = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'
  pattern2 = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}-\d{1,3}$'
  pattern3 = r'\d{1,5}$'
  pattern4 = r'\d{1,5}-\d{1,5}$'
  ip_list,port_list = None,None
  if args.target:
    if re.search(pattern1,args.target):
      ip_list = args.target.split(',')
    elif re.match(pattern2,args.target):
      _split = args.target.split('-')
      first_ip = _split[0]
      ip_split = first_ip.split('.')
      ipdot4 = range(int(ip_split[3]), int(_split[1]) + 1)
      ip_list = [ip_split[0] + '.' + ip_split[1] + '.' + ip_split[2] + '.' + str(p) for p in ipdot4]
    else:
      print '[-]target格式输入有误,请查看帮助!'
      exit(1)
  if args.port:
    if re.match(pattern4,args.port):
      _split = args.port.split('-')
      port_list = range(int(_split[0]),int(_split[1])+1)
    elif re.search(pattern3,args.port):
      port_list = args.port.split(',')
    else:
      print '[-]port格式输入有误,请查看帮助!'
      exit(1)
  return ip_list,port_list


def main():
  '''
  @说明:扫描的主程序,首先根据条件创建Ping扫描或端口扫描对象,然后调用相关的扫描方法进行扫描。
  '''
  args = parse_opt()
  if args.ping: #是否启动Ping扫描
    if not args.timeout and not args.retry:
      obj_ping = Discovery_Scan(args)
    elif args.timeout and not args.retry:
      obj_ping = Discovery_Scan(args,timeout=args.timeout)
    elif not args.timeout and args.retry:
      obj_ping = Discovery_Scan(args,retry=args.retry)
    else:
      obj_ping = Discovery_Scan(args,args.timeout,args.retry)
    ip_list = obj_ping.targets[0]
    if ip_list:
      #ARP扫描
      if args.ARP:
        for pdst in ip_list:
          t = threading.Thread(target=obj_ping.arp_scan,args=(pdst,))
          t.start()
        while threading.activeCount() != 1:   #避免线程还没有运行完就提前输出不全的结果
          time.sleep(1)
      #ICMP扫描
      elif args.ICMP:
        for dst in ip_list:
          t = threading.Thread(target=obj_ping.icmp_scan,args=(dst,))
          t.start()
        while threading.activeCount() != 1:   #避免线程还没有运行完就提前输出不全的结果
          time.sleep(1)
      #TCP扫描
      elif args.TCP:
        port_list = [80,443,21,22,23,25,53,135,139,137,445,1158,1433,1521,3306,3389,7001,8000,8080,9090]
        print '[+]请稍等,时间较长!'
        for dst in ip_list:
          print '[!]扫描...',dst
          for port in port_list:
            t = threading.Thread(target=obj_ping.tcp_scan,args=(dst,port))
            t.start()

        print '[+]正在处理扫描信息.'
        while threading.activeCount() != 1:   #避免线程还没有运行完就提前输出不全的结果
          time.sleep(1)

        if not obj_ping.tcp_info:
          print '\n'
          print '=' * 20
          print '[+]未发现在线主机.'
        else:
          print '\n'
          print '=' * 20
          for ip_a in sorted(obj_ping.tcp_info.keys()):
            print '[+]主机 %s 在线.' % ip_a
      #UDP扫描
      elif args.UDP:
        port_list = [7,9.13,15,37,53,67,68,69,135,137,138,139,445,520]
        print '[+]请稍等,时间较长!'
        for dst in ip_list:
          print '[!]扫描...',dst
          for port in port_list:
            t = threading.Thread(target=obj_ping.udp_scan,args=(dst,port))
            t.start()

        print '[+]正在处理扫描信息.'
        while threading.activeCount() != 1:   #避免线程还没有运行完就提前输出不全的结果
          time.sleep(1)

        if not obj_ping.udp_info:
          print '\n'
          print '=' * 20
          print '[+]未发现在线主机.'
        else:
          print '\n'
          print '=' * 20
          for ip_a in sorted(obj_ping.udp_info.keys()):
            print '[+]主机 %s 在线.' % ip_a
  if args.scan:  #是否启动端口扫描
    if not args.timeout and not args.retry:
      obj_port = Port_Scan(args)
    elif args.timeout and not args.retry:
      obj_port = Port_Scan(args,timeout=args.timeout)
    elif not args.timeout and args.retry:
      obj_port = Port_Scan(args,retry=args.retry)
    else:
      obj_port = Port_Scan(args,args.timeout,args.retry)

    ip_list,port_list = obj_port.targets
    if ip_list and port_list:
      if args.SYN:
        for dst in ip_list:
          print '[!]扫描...',dst
          for port in port_list:
            t = threading.Thread(target=obj_port.syn_port_scan,args=(dst,int(port)))
            t.start()

        print '[+]正在处理扫描信息.'
        while threading.activeCount() != 1:   #避免线程还没有运行完就提前输出不全的结果
          time.sleep(1)

        if not obj_port.syn_port_dict:
          print '\n'
          print '=' * 20
          print '[+]未发现开放TCP端口.'
        else:
          print '\n'
          print '=' * 20
          for k,v in obj_port.syn_port_dict.items():
            print '[+]主机 %s 开放的TCP端口有:%s' % (k,str(v))
      elif args.ACK:
        pass  #基本不能使用
      elif args.FIN:
        pass  #基本不能使用
      elif args.UPORT:
        for dst in ip_list:
          print '[!]扫描...',dst
          for port in port_list:
            t = threading.Thread(target=obj_port.udp_port_scan,args=(dst,int(port)))
            t.start()

        print '[+]正在处理扫描信息.'
        while threading.activeCount() != 1:   #避免线程还没有运行完就提前输出不全的结果
          time.sleep(1)

        if not obj_port.udp_port_dict:
          print '\n'
          print '=' * 20
          print '[+]未发现开放UDP端口.'
        else:
          print '\n'
          print '=' * 20
          for k,v in obj_port.udp_port_dict.items():
            print '[+]主机 %s 开放的UDP端口有:%s' % (k,str(v))

if __name__ == '__main__':
  try:
    start_time = time.time()
    main()
    stop_time = time.time()
    print '[+]总共耗时'+str(stop_time-start_time)+'秒.'
  except Exception,e:
    print '[-]执行出错,具体错误见下面信息.'
    print e

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python(Tornado)模拟登录小米抢手机
Nov 12 Python
python3使用tkinter实现ui界面简单实例
Jan 10 Python
Python入门教程之运算符与控制流
Aug 17 Python
浅谈python中的__init__、__new__和__call__方法
Jul 18 Python
python 读取鼠标点击坐标的实例
Dec 29 Python
python接口自动化(十七)--Json 数据处理---一次爬坑记(详解)
Apr 18 Python
Python+Selenium使用Page Object实现页面自动化测试
Jul 14 Python
python使用pyecharts库画地图数据可视化的实现
Mar 25 Python
python中urllib.request和requests的使用及区别详解
May 05 Python
Python绘制动态水球图过程详解
Jun 03 Python
python中操作文件的模块的方法总结
Feb 04 Python
Python机器学习之基础概述
May 19 Python
Python常用base64 md5 aes des crc32加密解密方法汇总
Nov 06 #Python
基于Python模拟浏览器发送http请求
Nov 06 #Python
python如何写个俄罗斯方块
Nov 06 #Python
基于Python实现全自动下载抖音视频
Nov 06 #Python
Python3读写ini配置文件的示例
Nov 06 #Python
Python Serial串口基本操作(收发数据)
Nov 06 #Python
python基于exchange函数发送邮件过程详解
Nov 06 #Python
You might like
比较全面的PHP数组的使用方法小结
2010/09/23 PHP
codeigniter显示所有脚本执行时间的方法
2015/03/21 PHP
简单了解将WordPress中的工具栏移到底部的小技巧
2015/12/31 PHP
PHP缓冲区用法总结
2016/02/14 PHP
php解析mht文件转换成html的实例
2017/03/13 PHP
php中字符串和整数比较的操作方法
2019/06/06 PHP
php生成微信红包数组的方法
2019/09/05 PHP
javascript 树控件 比较好用
2009/06/11 Javascript
SOSO地图JS画出标注和中心点以html形式运行
2013/08/09 Javascript
javascript静态页面传值的三种方法分享
2013/11/12 Javascript
js 数值转换为3位逗号分隔的示例代码
2014/02/19 Javascript
js截取中英文字符串、标点符号无乱码示例解读
2014/04/17 Javascript
Jquery仿IGoogle实现可拖动窗口示例代码
2014/08/22 Javascript
jQuery实现进度条效果代码
2015/12/17 Javascript
原生JS实现左右箭头选择日期实例代码
2017/03/14 Javascript
angularjs指令之绑定策略(@、=、&amp;)
2017/04/13 Javascript
简单实现js点击展开二级菜单功能
2017/05/16 Javascript
在 Node.js 中使用 async 函数的方法
2017/11/17 Javascript
vue 指定组件缓存实例详解
2018/04/01 Javascript
微信小程序中进行地图导航功能的实现方法
2018/06/29 Javascript
JavaScript实现鼠标经过表格某行时此行变色
2020/11/20 Javascript
Python如何优雅获取本机IP方法
2019/11/10 Python
dpn网络的pytorch实现方式
2020/01/14 Python
基于python模拟bfs和dfs代码实例
2020/11/19 Python
pyx文件 生成pyd 文件用于 cython调用的实现
2021/03/04 Python
IE下实现类似CSS3 text-shadow文字阴影的几种方法
2011/05/11 HTML / CSS
Yahoo-PHP面试题3
2012/01/14 面试题
连锁经营管理专业大学生求职信
2013/10/30 职场文书
大学军训自我鉴定
2013/12/15 职场文书
环保建议书300字
2014/05/14 职场文书
幼儿园辞职信范文
2015/02/27 职场文书
2015年控辍保学工作总结
2015/05/18 职场文书
少先大队干部竞选稿
2015/11/20 职场文书
解决mysql模糊查询索引失效问题的几种方法
2021/06/18 MySQL
PYTHON使用Matplotlib去实现各种条形图的绘制
2022/03/22 Python
Python编写车票订购系统 Python实现快递收费系统
2022/08/14 Python