【问题标题】:Extract all urls in a string with python3使用python3提取字符串中的所有url
【发布时间】:2017-06-20 05:27:59
【问题描述】:

我正在尝试找到一种干净的方法来提取文本字符串中的所有 url。

经过广泛的搜索,我发现许多帖子建议使用正则表达式来完成任务,并且他们给出了假设这样做的正则表达式。每个 RegEx 都有一些优点和一些缺点。此外,编辑它们以改变它们的行为也不是直截了当的。无论如何,在这一点上,我对任何可以正确检测此文本中的 url 的 RegEx 感到满意:

输入:

Lorem ipsum dolor sit amet https://www.lorem.com/ipsum.php?q=suas, nusquam tincidunt ex per, ius modus integre no, quando utroque placerat qui no. Mea 结论 vituperatoribus et, omnes malorum est id, pri omnes atomorum expetenda ex。 Elit pertinacia no eos, noumy comprehensam id mei。 Ei eum maiestatis quaerendum https://www.lorem.org????。 Pri posse constituam in, 坐在http://news.bbc.co.ukomnium assentior definitionem ei。 Cu duo equidem meliore qualisque。

输出:

['https://www.lorem.com/ipsum.php?q=suas', 'https://www.lorem.org', 'http://news.bbc.co.uk']

但如果有一个 python3 类/函数/库,它会在给定文本中查找所有 url 并将参数传递给:

  1. 选择要检测的协议
  2. 选择允许的顶级域名
  3. 选择允许的域

我很高兴知道这件事。

【问题讨论】:

  • 我认为你在写问题标题时睡着了..
  • 也许吧。所以,我已经编辑了问题标题...

标签: python regex python-3.x url


【解决方案1】:

除了其他人提到的,既然你要求的东西已经存在,你可能想试试URLExtract

显然它试图在给定的文本中找到任何出现的 TLD。如果找到 TLD,它会从该位置开始向两边扩展边界,搜索“停止字符”(通常是空格、逗号、单引号或双引号)。

你有几个例子here

from urlextract import URLExtract

extractor = URLExtract()
urls = extractor.find_urls("Let's have URL youfellasleepwhilewritingyourtitle.com as an example.")
print(urls) # prints: ['youfellasleepwhilewritingyourtitle.cz']

这个模块似乎还有一个update() 方法可以让你更新TLD列表缓存文件

但是,如果这不符合您的特定要求,您可以在使用上述模块(或任何其他解析 URL 的方式)处理 url 后手动进行一些检查。例如,假设您获得了一个 URL 列表:

result = ['https://www.lorem.com/ipsum.php?q=suas', 'https://www.lorem.org', 'http://news.bbc.co.uk'] 

然后您可以构建另一个包含排除域/顶级域/等的列表:

allowed_protocols = ['protocol_1', 'protocol_2']
allowed_tlds = ['tld_1', 'tld_2', 'tld_3']
allowed_domains = ['domain_1']

for each_url in results:
    # here, check each url against your rules

【讨论】:

    【解决方案2】:

    如果你想要一个正则表达式,你可以使用这个:

    import re
    
    
    string = "Lorem ipsum dolor sit amet https://www.lorem.com/ipsum.php?q=suas, nusquam tincidunt ex per, ius modus integre no, quando utroque placerat qui no. Mea conclusionemque vituperatoribus et, omnes malorum est id, pri omnes atomorum expetenda ex. Elit pertinacia no eos, nonumy comprehensam id mei. Ei eum maiestatis quaerendum https://www.lorem.org?. Pri posse constituam in, sit http://news.bbc.co.uk omnium assentior definitionem ei. Cu duo equidem meliore qualisque."
    
    result = re.findall(r"\w+://\w+\.\w+\.\w+/?[\w\.\?=#]*", string)
    print(result)
    

    输出:

    ['https://www.lorem.com/ipsum.php?q=suas', 
     'https://www.lorem.org', 
     'http://news.bbc.co.uk']
    

    【讨论】:

    • 再次检查你的结果不是你写的它是['https://www.lorem.com/', 'https://www.lorem.org.', 'http://news.bbc.co.']
    • 哦,对不起,我在复制和粘贴代码时打错字了,小姐写了 \w 到 \d @Gahan 感谢您发现
    【解决方案3】:
    import re
    import string
    text = """
    Lorem ipsum dolor sit amet https://www.lore-m.com/ipsum.php?q=suas, 
    nusquam tincidunt ex per, ftp://link.com ius modus integre no, quando utroque placerat qui no. 
    Mea conclusionemque vituperatoribus et, omnes malorum est id, pri omnes atomorum expetenda ex. 
    Elit ftp://link.work.in pertinacia no eos, nonumy comprehensam id mei. Ei eum maiestatis quaerendum https://www.lorem.org?. 
    Pri posse constituam in, sit http://news.bbc.co.uk omnium assentior definitionem ei. Cu duo equidem meliore 
    qualisque.
    """
    
    URL_REGEX = r"""((?:(?:https|ftp|http)?:(?:/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?:com|org|uk)/)(?:[^\s()<>{}\[\]]+|\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\))+(?:\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?:com|uk|ac)\b/?(?!@)))"""
    
    urls = re.findall(URL_REGEX, text)
    print([''.join(x for x in url if x in string.printable) for url in urls])
    

    现在,如果您只想保留具有有效域的 url,您可以编写如下:

    VALID_DOMAINS = ['lorem.org', 'bbc.co.uk', 'sample.com', 'link.net']
    valid_urls = []
    for url in result_url:
        for val_domain in VALID_DOMAINS:
            if val_domain in url:
                valid_urls.append(url)
    print(valid_urls)
    

    【讨论】:

      【解决方案4】:
      output = [x for x in input().split() if x.startswith('http://') or x.startswith('https://') or x.startswith('ftp://')]
      print(output)
      

      你的例子: http://ideone.com/wys57x

      毕竟,如果列表元素中的最后一个字符不是字母,你也可以剪切它。

      编辑:

      output = [x for x in input().split() if x.startswith('http://') or x.startswith('https://') or x.startswith('ftp://')]
      newOutput = []
      for link in output:
          copy = link
          while not copy[-1].isalpha():
              copy = copy[:-1]
          newOutput.append(copy)
      print(newOutput)
      

      你的例子:http://ideone.com/gHRQ8w

      【讨论】:

      • 感谢您的回复。您的方法无法排除“lorem.org?”中的笑脸
      • 不。只是“如果它不是字母,则剪切列表元素中的最后一个字符。”
      • @Ouss 现在检查我的答案。
      • 也可以试试这个: content = input.split(' ') newOutput = [] for val in content: if val.startswith('http://') or val.startswith('https ://'): newOutput.append(val)
      • @AnubhavSingh 我认为理解列表在这里更好。还有content = input().split(' ') :)
      【解决方案5】:

      使用现有的库可能是最好的解决方案。

      但这对于我的小脚本来说太多了,而且——受@piotr-wasilewiczs 回答的启发——我想出了:

      from string import ascii_letters
      links = [x for x in line.split() if x.strip(str(set(x) - set(ascii_letters))).startswith(('http', 'https', 'www'))]
      
      • 对于该行中的每个单词,
      • 去除(从开头和结尾)在单词本身中找到的非 ASCII 字母)
      • 并按以 https、http、www 之一开头的单词进行过滤。

      对我的口味来说有点太密集了,我不知道它有多快,但它应该可以检测到字符串中大多数“正常”的 url。

      【讨论】:

        猜你喜欢
        • 2011-01-29
        • 2011-01-18
        • 1970-01-01
        • 2012-07-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-20
        • 1970-01-01
        相关资源
        最近更新 更多