使用 Python 从 Markdown 中提取 URL 和锚文本

Extracting URL and anchor text from Markdown using Python

我正在尝试从 Markdown 中提取锚文本和关联的 URL。我看过 this question. Unfortunately, the answer 似乎没有完全回答我想要的。

在Markdown中,有两种插入link的方法:

示例 1:

[anchor text](http://my.url)

示例 2:

[anchor text][2]

   [1]: http://my.url

我的脚本看起来像这样(注意我使用的是 regex,不是 re):

import regex
body_markdown = "This is an [inline link](http://google.com). This is a [non inline link][4]\r\n\r\n  [1]: http://yahoo.com"

rex = """(?|(?<txt>(?<url>(?:ht|f)tps?://\S+(?<=\P{P})))|\(([^)]+)\)\[(\g<url>)\])"""
pattern = regex.compile(rex)
matches = regex.findall(pattern, body_markdown, overlapped=True)
for m in matches:
    print m

这会产生输出:

('http://google.com', 'http://google.com')
('http://yahoo.com', 'http://yahoo.com')

我的预期输出是:

('inline link', 'http://google.com')
('non inline link', 'http://yahoo.com')

如何从 Markdown 中正确捕获锚文本?

How can I properly capture the anchor text from Markdown?

将其解析为结构化格式(例如,html),然后使用适当的工具提取 link 个标签和地址。

import markdown
from lxml import etree

body_markdown = "This is an [inline link](http://google.com). This is a [non inline link][1]\r\n\r\n  [1]: http://yahoo.com"

doc = etree.fromstring(markdown.markdown(body_markdown))
for link in doc.xpath('//a'):
  print link.text, link.get('href')

这让我:

inline link http://google.com
non inline link http://yahoo.com

另一种方法是编写您自己的 Markdown 解析器,这似乎是您不应该集中精力的地方。

您可以使用几个简单的 re 模式来完成:

import re

INLINE_LINK_RE = re.compile(r'\[([^\]]+)\]\(([^)]+)\)')
FOOTNOTE_LINK_TEXT_RE = re.compile(r'\[([^\]]+)\]\[(\d+)\]')
FOOTNOTE_LINK_URL_RE = re.compile(r'\[(\d+)\]:\s+(\S+)')


def find_md_links(md):
    """ Return dict of links in markdown """

    links = dict(INLINE_LINK_RE.findall(md))
    footnote_links = dict(FOOTNOTE_LINK_TEXT_RE.findall(md))
    footnote_urls = dict(FOOTNOTE_LINK_URL_RE.findall(md))

    for key, value in footnote_links.iteritems():
        footnote_links[key] = footnote_urls[value]
    links.update(footnote_links)

    return links

然后你可以像这样使用它:

>>> body_markdown = """
... This is an [inline link](http://google.com).
... This is a [footnote link][1].
...
... [1]: http://yahoo.com
... """
>>> links = find_md_links(body_markdown)
>>> links
{'footnote link': 'http://yahoo.com', 'inline link': 'http://google.com'}
>>> links.values()
['http://yahoo.com', 'http://google.com']

将@mreinhardt 解决方案修改为 return 所有对的列表(而不是字典)(text, link):

import re
    
INLINE_LINK_RE = re.compile(r'\[([^\]]+)\]\(([^)]+)\)')
FOOTNOTE_LINK_TEXT_RE = re.compile(r'\[([^\]]+)\]\[(\d+)\]')
FOOTNOTE_LINK_URL_RE = re.compile(r'\[(\d+)\]:\s+(\S+)')


def find_md_links(md):
    """ Return dict of links in markdown """

    links = list(INLINE_LINK_RE.findall(md))
    footnote_links = dict(FOOTNOTE_LINK_TEXT_RE.findall(md))
    footnote_urls = dict(FOOTNOTE_LINK_URL_RE.findall(md))

    for key in footnote_links.keys():
        links.append((footnote_links[key], footnote_urls[footnote_links[key]]))

    return links
    

我在 python3 中测试 链接为:

[h](http://google.com) and [h](https://goog.e.com)