【问题标题】:How to use Python to parse a SVG document from URL (get points of a polyline)如何使用 Python 从 URL 解析 SVG 文档(获取折线的点)
【发布时间】:2023-03-09 17:45:01
【问题描述】:

我正在寻找一个 Python 扩展来解析来自 <polyline> 元素的 SVG 的“点”值并打印它们?可能从 URL 解析它?或者我可以保存 SVG 并在本地进行。

我只需要它来解析points 值并为每个polyline 元素分别打印它们。因此,它将为当前 <polyline> 元素的每个 points 值打印类似的内容。

[[239,274],[239,274],[239,274],[239,275],[239,275],[238,276],[238,276],[237,276],[237,276],[236,276],[236,276],[236,277] [236,277],[235,277],[235,277],[234,278],[234,278],[233,279],[233,279],[232,280] [232,280],[231,280],[231,280],[230,280],[230,280],[230,280],[229,280],[229,280]]

因此,在第一个 polyline 元素被解析和打印后,它会解析下一个 polyline 元素并获取 points 的值并像第一个元素一样打印它,直到不再打印。

SVG 的 URL:http://colorillo.com/bx0l.inline.svg

这是来自 SVG 的折线元素的 HTML 示例

<polyline points="239,274 239,274 239,274 239,275 239,275 238,276 238,276 237,276 237,276 236,276 236,276 236,277 236,277 235,277 235,277 234,278 234,278 233,279 233,279 232,280 232,280 231,280 231,280 230,280 230,280 230,280 229,280 229,280" style="fill: none; stroke: #000000; stroke-width: 1; stroke-linejoin: round; stroke-linecap: round; stroke-antialiasing: false; stroke-antialias: 0; opacity: 0.8"/>

我只是在寻找一些快速帮助和一个例子。如果你能帮助我,那就太好了。

【问题讨论】:

    标签: python xml python-3.x svg


    【解决方案1】:

    我相信某处有一个 HTML 提取包,但这是我将使用核心 python 和正则表达式模块执行的任务。让txt 成为您呈现的文本&lt;polyline...,所以:

    导入正则表达式模块

    In [22]: import re
    

    执行搜索:

    In [24]: g = re.search('polyline points="(.*?)"', txt)
    

    在上面的正则表达式中,我使用polyline points=" 作为锚点(我省略了&lt;,因为它在正则表达式中具有含义)并捕获所有其余部分,直到下一个引号。

    你想要的文字是通过以下方式实现的:

    In [25]: g.group(1)
    Out[25]: '239,274 239,274 239,274 239,275 239,275 238,276 238,276 237,276 237,276 236,276 236,276 236,277 236,277 235,277 235,277 234,278 234,278 233,279 233,279 232,280 232,280 231,280 231,280 230,280 230,280 230,280 229,280 229,280'
    

    更新

    使用xml解析数据更安全,这里有一种方法(xml.etree包含在标准库中):

    In [32]: import xml.etree.ElementTree as ET
    In [33]: root = ET.fromstring(txt)
    

    由于您的数据已经被格式化为根标签,您不需要进一步提取:

    In [35]: root.tag
    Out[35]: 'polyline'
    

    而且所有的属性实际上都是 XML 属性,转换成字典:

    In [37]: root.attrib
    Out[37]:
    {'points': '239,274 239,274 239,274 239,275 239,275 238,276 238,276 237,276 237,276 236,276 236,276 236,277 236,277 235,277 235,277 234,278 234,278 233,279 233,279 232,280 232,280 231,280 231,280 230,280 230,280 230,280 229,280 229,280', 'style': 'fill: none; stroke: #000000; stroke-width: 1; stroke-linejoin: round; stroke-linecap: round; stroke-antialiasing: false; stroke-antialias: 0; opacity: 0.8'}
    

    所以你有它:

    In [38]: root.attrib['points']
    Out[38]: '239,274 239,274 239,274 239,275 239,275 238,276 238,276 237,276 237,276 236,276 236,276 236,277 236,277 235,277 235,277 234,278 234,278 233,279 233,279 232,280 232,280 231,280 231,280 230,280 230,280 230,280 229,280 229,280'
    

    如果您想进一步根据逗号和空格将其拆分为组,我会这样做:

    使用不带参数的split 以空格分隔所有组:

    >>> p = g.group(1).split()
    >>> p
    ['239,274', '239,274', '239,274', '239,275', '239,275', '238,276', '238,276', '237,276', '237,276', '236,276', '236,276', '236,277', '236,277', '235,277', '235,277', '234,278', '234,278', '233,279', '233,279', '232,280', '232,280', '231,280', '231,280', '230,280', '230,280', '230,280', '229,280', '229,280']
    

    现在对于每个字符串,用逗号将其拆分,这将返回一个字符串列表。我使用map 将每个这样的列表转换为ints 的列表:

    >>> p2 = [list(map(int, numbers.split(','))) for numbers in p]
    >>> p2
    [[239, 274], [239, 274], [239, 274], [239, 275], [239, 275], [238, 276], [238, 276], [237, 276], [237, 276], [236, 276], [236, 276], [236, 277], [236, 277], [235, 277], [235, 277], [234, 278], [234, 278], [233, 279], [233, 279], [232, 280], [232, 280], [231, 280], [231, 280], [230, 280], [230, 280], [230, 280], [229, 280], [229, 280]]
    

    这会带来更多启示:

    >>> '123,456'.split(',')
    ['123', '456']
    >>> list(map(int, '123,456'.split(',')))
    [123, 456]
    

    【讨论】:

    • 不要使用正则表达式来解析 XML。
    • @IsraelUnterman 很好地编辑您的答案以使用适当的 XML 解析器,我会很高兴地支持它。
    【解决方案2】:

    下面

    import xml.etree.ElementTree as ET
    from collections import namedtuple
    import requests
    import re
    
    Point = namedtuple('Point', 'x y')
    
    all_points = []
    r = requests.get('http://colorillo.com/bx0l.inline.svg')
    if r.status_code == 200:
        data = re.sub(' xmlns="[^"]+"', '', r.content.decode('utf-8'), count=1)
        root = ET.fromstring(data)
        poly_lines = root.findall('.//polyline')
        for poly_line in poly_lines:
            tmp = []
            _points = poly_line.attrib['points'].split(' ')
            for _p in _points:
                tmp.append(Point(*[int(z) for z in _p.split(',')]))
            all_points.append(tmp)
    
    for points in all_points:
        tmp = [str([p.x, p.y]).replace(' ','') for p in points]
        line = ','.join(tmp)
        print('[' + line + ']')
    

    【讨论】:

    • @Ecks [210, 240], [123, 424][210, 240],[123, 424] 有什么问题 - 点之间的空间?
    • @Ecks 代码已更新。试一试。输出如下:[[95,394],[96,394],[96,394],[99,394],...
    猜你喜欢
    • 1970-01-01
    • 2019-06-30
    • 2014-08-06
    • 1970-01-01
    • 2016-11-08
    • 2014-11-19
    • 2019-01-03
    • 1970-01-01
    相关资源
    最近更新 更多