【问题标题】:Python - parse IPv4 addresses from string (even when censored)Python - 从字符串中解析 IPv4 地址(即使被审查)
【发布时间】:2013-06-24 01:19:19
【问题描述】:

目标:编写 Python 2.7 代码以从字符串中提取 IPv4 地址。

字符串内容示例:


以下是 IP 地址:192.168.1.1、8.8.8.8、101.099.098.000。 这些也可以显示为 192.168.1[.]1 或 192.168.1(.)1 或 192.168.1[dot]1 或 192.168.1(dot)1 或 192 .168 .1 .1 或 192.168.1 . 1. 这些审查方法可以适用于任何一个点(例如:192[.]168[.]1[.]1)。


正如您从上面看到的,我正在努力寻找一种方法来解析一个 txt 文件,该文件可能包含以多种“审查”形式描述的 IP(以防止超链接)。

我认为正则表达式是要走的路。也许说一些类似的东西;由“分隔符列表”中的任何内容分隔的四个整数 0-255 或 000-255 的任何分组,其中包括句点、括号、括号或任何其他上述示例。这样,“分隔符列表”可以根据需要更新。

不确定这是否是正确的方法,甚至可能如此,非常感谢任何帮助。


更新: 感谢下面递归的回答,我现在有以下代码适用于上述示例。它会...

  • 查找 IP
  • 将它们放入列表中
  • 清除它们的空格/大括号/等
  • 并将未清理的列表条目替换为已清理的条目。

警告:以下代码不考虑不正确/无效的 IP,例如 192.168.0.256 或 192.168.1.2.3 目前,它将从上述内容中删除尾随的 6 和 3。如果它的第一个八位字节无效(例如:256.10.10.10),它将丢弃前导 2(导致 56.10.10.10)。

import re

def extractIPs(fileContent):
    pattern = r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)([ (\[]?(\.|dot)[ )\]]?(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3})"
    ips = [each[0] for each in re.findall(pattern, fileContent)]   
    for item in ips:
        location = ips.index(item)
        ip = re.sub("[ ()\[\]]", "", item)
        ip = re.sub("dot", ".", ip)
        ips.remove(item)
        ips.insert(location, ip) 
    return ips

myFile = open('***INSERT FILE PATH HERE***')
fileContent = myFile.read()

IPs = extractIPs(fileContent)
print "Original file content:\n{0}".format(fileContent)
print "--------------------------------"
print "Parsed results:\n{0}".format(IPs)

【问题讨论】:

  • 很高兴发布您到目前为止所尝试的内容以及您遇到的问题。这样我们可以改进您当前的解决方案,您可以从中学习(更多)
  • 起初我在空格上进行拆分,并且几乎所有东西都可以正常工作,但是在我意识到有时空格会在句点前面加上之后,我又回到了绘图板上。到目前为止,我已经尝试了 StackOverflow 中的许多不同示例,但只找到了获取“未经审查”IP 的方法。例如,我尝试拆分句点,然后验证每个元素 (re.match(r'^([01]?[0-9]?[0-9]|2[0-4][0-9] |25[0-5])$', part) 我以前从来没有玩过正则表达式,而且对 python 有点陌生,所以我对如何处理这个问题有点害怕。
  • recursive 提供了答案。我对help vampires 有点过敏,因此是我的反应。如果你早点回复我本可以回复你的:)
  • HamZa 不用担心。我很感激并理解“帮助吸血鬼”。我可能会遇到这种情况,因为我没有接受过正式的编程培训(阅读“完全菜鸟”),因此有时会遇到愚蠢的问题或需要指向正确方向的指针才能在我的脑海中形成它。递归非常有用,我现在几乎完成了我的代码。
  • @HamZa 很高兴知道。谢谢。

标签: python regex python-2.7 ipv4 data-extraction


【解决方案1】:

这是一个有效的正则表达式:

import re
pattern = r"((([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])[ (\[]?(\.|dot)[ )\]]?){3}([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]))"
text = "The following are IP addresses: 192.168.1.1, 8.8.8.8, 101.099.098.000. These can also appear as 192.168.1[.]1 or 192.168.1(.)1 or 192.168.1[dot]1 or 192.168.1(dot)1 or 192 .168 .1 .1 or 192. 168. 1. 1. "
ips = [match[0] for match in re.findall(pattern, text)]
print ips

# output: ['192.168.1.1', '8.8.8.8', '101.099.098.000', '192.168.1[.]1', '192.168.1(.)1', '192.168.1[dot]1', '192.168.1(dot)1', '192 .168 .1 .1', '192. 168. 1. 1']

正则表达式有几个主要部分,我将在这里解释:

  • ([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])
    这匹配 IP 地址的数字部分。 | 表示“或”。第一种情况处理从 0 到 199 的数字,带或不带前导零。后两个案例处理超过 199 的数字。
  • [ (\[]?(\.|dot)[ )\]]?
    这匹配“点”部分。有三个子组件:
    • [ (\[]? 点的“前缀”。可以是空格、开放括号或开放方括号。结尾的? 表示这部分是可选的。
    • (\.|dot)“点”或句号。
    • [ )\]]?“后缀”。与前缀相同的逻辑。
  • {3} 表示重复上一个组件 3 次。
  • 最后一个元素是另一个数字,与第一个相同,只是后面没有点。

【讨论】:

  • 我认为问题的最后两段足以说明 nephos 目前的进展情况。可能是没有代码,但很明显已经投入了一些想法,所以没关系。由于有足够的信息可以提供一个有希望的有用答案,我认为没有理由不这样做。
  • @recursive 你介意解释一下这个正则表达式是如何工作的吗?
  • @recursive:我一直在考虑买车,你会买给我吗?我对此表示怀疑。 思考解决方案和尝试是两件不同的事情。
  • @MadaraUchiha:我会告诉你如何买车。我实际上不会为此付出代价。同样,我会告诉你如何应用正则表达式,但我不会支持你的软件。
  • @BenjaminGruenbaum:我添加了解释。
【解决方案2】:

说明

这个正则表达式将匹配一个看起来像 IP 地址的四个八位字节中的每一个。每个八位字节都将被放入它自己的捕获组中以进行收集。

(2[0-4][0-9]|[01]?[0-9]?[0-9]|25[0-5])\D{1,5}(2[0-4][0-9]|[01]?[0-9]?[0-9]|25[0-5])\D{1,5}(2[0-4][0-9]|[01]?[0-9]?[0-9]|25[0-5])\D{1,5}(2[0-4][0-9]|[01]?[0-9]?[0-9]|25[0-5])

鉴于以下示例文本,此正则表达式将完整匹配所有 10 个嵌入式 IP 字符串,包括第一个。工作示例:http://www.rubular.com/r/1MbGZOhuj5

The following are IP addresses: 192.168.1.222, 8.8.8.8, 101.099.098.000. These can also appear as 192.168.1[.]1 or 192.168.1(.)1 or 192.168.1[dot]1 or 192.168.1(dot)1 or 192 .168 .1 .1 or 192. 168. 1. 1. and these censorship methods could apply to any of the dots (Ex: 192[.]168[.]1[.]1).

可以迭代生成的匹配项,并且可以通过用点连接 4 个捕获组来构造正确格式的 IP 字符串。

【讨论】:

  • 很棒的资源 Denomales!我一定会收藏rubular.com 并使用它来了解更多关于正则表达式如何工作的信息。谢谢!我喜欢你的方法,它绝对适用于我提供的示例。我有另一个更“混乱”的例子,它不起作用,但我会在周末再做一次,找到一个完整的解决方案,完成后在这里发布。再次感谢伟大的链接。如果您想知道我所说的“混乱”是什么意思...“(132) - 10.10.10.10 (2.31Mb)”被解析为 132.10.10.10
【解决方案3】:

下面的代码将...

  • 即使经过审查也能在字符串中找到 IP(例如:192.168.1[dot]20 或 10.10.10 .21)
  • 将它们放入列表中
  • 清除它们的审查(空格/大括号/括号)
  • 并将未清理的列表条目替换为已清理的条目。

警告: 下面的代码不考虑不正确/无效的 IP,例如 192.168.0.256 或 192.168.1.2.3 目前,它会删除尾随数字(6 和 3 从上述)。如果它的第一个八位字节无效(例如:256.10.10.10),它将丢弃前导数字(导致 56.10.10.10)。


import re

def extractIPs(fileContent):
    pattern = r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)([ (\[]?(\.|dot)[ )\]]?(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3})"
    ips = [each[0] for each in re.findall(pattern, fileContent)]   
    for item in ips:
        location = ips.index(item)
        ip = re.sub("[ ()\[\]]", "", item)
        ip = re.sub("dot", ".", ip)
        ips.remove(item)
        ips.insert(location, ip) 
    return ips


myFile = open('***INSERT FILE PATH HERE***')
fileContent = myFile.read()

IPs = extractIPs(fileContent)
print "Original file content:\n{0}".format(fileContent)
print "--------------------------------"
print "Parsed results:\n{0}".format(IPs)

【讨论】:

    【解决方案4】:

    提取和分类 IPv4 地址(即使经过审查)

    注意:这只是我为提取 IPv4 地址而编写的一个类的实现。将来我可能会使用此功能的方法更新我的课程。你可以在my GitHub page找到它。


    我在下面演示的内容如下:

    1. 清理您的字符串内容示例

    2. 将字符串数据放入列表中

    3. 使用 ExtractIPs() 类解析和分类 IPv4 地址

      • 这个类返回一个包含 4 个列表的字典:

        • 有效的 IPv4 地址

        • 公共 IPv4 地址

        • 私有 IPv4 地址

        • 无效的 IPv4 地址


    • ExtractIPs 类

      #!/usr/bin/env python
      
      """Extract and Classify IP Addresses."""
      
      import re  # Use Regular Expressions.
      
      
      __program__ = "IPAddresses.py"
      __author__ = "Johnny C. Wachter"
      __copyright__ = "Copyright (C) 2014 Johnny C. Wachter"
      __license__ = "MIT"
      __version__ = "0.0.1"
      __maintainer__ = "Johnny C. Wachter"
      __contact__ = "wachter.johnny@gmail.com"
      __status__ = "Development"
      
      
      class ExtractIPs(object):
      
          """Extract and Classify IP Addresses From Input Data."""
      
          def __init__(self, input_data):
              """Instantiate the Class."""
      
              self.input_data = input_data
      
              self.ipv4_results = {
                  'valid_ips': [],  # Store all valid IP Addresses.
                  'invalid_ips': [],  # Store all invalid IP Addresses.
                  'private_ips': [],  # Store all Private IP Addresses.
                  'public_ips': []  # Store all Public IP Addresses.
              }
      
          def extract_ipv4_like(self):
              """Extract IP-like strings from input data.
              :rtype : list
              """
      
              ipv4_like_list = []
      
              ip_like_pattern = re.compile(r'([0-9]{1,3}\.){3}([0-9]{1,3})')
      
              for entry in self.input_data:
      
                  if re.match(ip_like_pattern, entry):
      
                      if len(entry.split('.')) == 4:
      
                          ipv4_like_list.append(entry)
      
              return ipv4_like_list
      
          def validate_ipv4_like(self):
              """Validate that IP-like entries fall within the appropriate range."""
      
              if self.extract_ipv4_like():
      
                  # We're gonna want to ignore the below two addresses.
                  ignore_list = ['0.0.0.0', '255.255.255.255']
      
                  # Separate the Valid from Invalid IP Addresses.
                  for ipv4_like in self.extract_ipv4_like():
      
                      # Split the 'IP' into parts so each part can be validated.
                      parts = ipv4_like.split('.')
      
                      # All part values should be between 0 and 255.
                      if all(0 <= int(part) < 256 for part in parts):
      
                          if not ipv4_like in ignore_list:
      
                              self.ipv4_results['valid_ips'].append(ipv4_like)
      
                      else:
      
                          self.ipv4_results['invalid_ips'].append(ipv4_like)
      
              else:
                  pass
      
          def classify_ipv4_addresses(self):
              """Classify Valid IP Addresses."""
      
              if self.ipv4_results['valid_ips']:
      
                  # Now we will classify the Valid IP Addresses.
                  for valid_ip in self.ipv4_results['valid_ips']:
      
                      private_ip_pattern = re.findall(
      
                          r"""^10\.(\d{1,3}\.){2}\d{1,3}
      
                          (^127\.0\.0\.1)|  # Loopback
      
                          (^10\.(\d{1,3}\.){2}\d{1,3})|  # 10/8 Range
      
                          # Matching the 172.16/12 Range takes several matches
                          (^172\.1[6-9]\.\d{1,3}\.\d{1,3})|
                          (^172\.2[0-9]\.\d{1,3}\.\d{1,3})|
                          (^172\.3[0-1]\.\d{1,3}\.\d{1,3})|
      
                          (^192\.168\.\d{1,3}\.\d{1,3})|  # 192.168/16 Range
      
                          # Match APIPA Range.
                          (^169\.254\.\d{1,3}\.\d{1,3})
      
                          # VERBOSE for a clean look of this RegEx.
                          """, valid_ip, re.VERBOSE
                      )
      
                      if private_ip_pattern:
      
                          self.ipv4_results['private_ips'].append(valid_ip)
      
                      else:
                          self.ipv4_results['public_ips'].append(valid_ip)
      
              else:
                  pass
      
          def get_ipv4_results(self):
              """Extract and classify all valid and invalid IP-like strings.
              :returns : dict
              """
      
              self.extract_ipv4_like()
              self.validate_ipv4_like()
              self.classify_ipv4_addresses()
      
              return self.ipv4_results
      
    • 审查提取示例

      censored = re.compile(
          r"""
      
          \(\.\)|
          \(dot\)|
          \[\.\]|
          \[dot\]|
          ( \.)
      
          """, re.VERBOSE | re.IGNORECASE
      )
      
      data_list = input_string.split()  # Bring your input string to a list.
      
      clean_list = []  # List to store the cleaned up input.
      
      for entry in data_list:
      
          # Remove undesired leading and trailing characters.
          clean_entry = entry.strip(' .,<>?/[]\\{}"\'|`~!@#$%^&*()_+-=')
      
          clean_list.append(clean_entry)  # Add the entry to the clean list.
      
      clean_unique_list = list(set(clean_list))  # Remove duplicates in list.
      
      # Now we can go ahead and extract IPv4 Addresses. Note that this will be a dict.
      results = ExtractIPs(clean_list).get_ipv4_results()
      
      for k, v in results.iteritems():
      
          # After all that work, make sure the results are nicely presented!
          print("\n%s: %s" % (k, v))
      
      • 结果:

        public_ips: ['8.8.8.8', '101.099.098.000']
        
        valid_ips: ['192.168.1.1', '8.8.8.8', '101.099.098.000']
        
        invalid_ips: []
        
        private_ips: ['192.168.1.1']
        

    【讨论】:

      猜你喜欢
      • 2012-12-25
      • 1970-01-01
      • 2023-04-02
      • 2021-09-02
      • 2016-04-22
      • 2016-01-16
      • 1970-01-01
      • 2015-10-19
      • 2012-12-11
      相关资源
      最近更新 更多