beautifulSoup 不正确嵌套 <ul>s 的屏幕截图列表

Posted

技术标签:

【中文标题】beautifulSoup 不正确嵌套 <ul>s 的屏幕截图列表【英文标题】:beautifulSoup screenscraping list of improperly nested <ul>s 【发布时间】:2012-01-12 03:24:13 【问题描述】:

我(非常)是 BeautifulSoup 的新手,在过去的三天里,我试图从 http://www.ucanews.com/diocesan-directory/html/ordinary-of-philippine-cagayandeoro-parishes.html 获取教堂列表。

数据似乎没有正确嵌套,只是为了演示目的而标记。假设层次结构是

Parishes
    District
    (data)
        Vicariate
        (data)
            Church
            (data)

但是我看到的只是每个教堂都以子弹开头,每个条目都由两个换行符分隔。我所追求的字段名称是斜体的,并用“:”与实际数据分开。每个单元条目(District |Vicariate|Parish)可能有一个或多个数据字段。

到目前为止,我可以梳理出一些数据,但无法显示实体的名称。

soup=BeautifulSoup(page)
for e in soup.table.tr.findAll('i'):
    print e.string, e.nextSibling

最后,我希望按列转换数据:district, vicariate, parish, address, phone, titular, parish priest, &lt;field8&gt;, &lt;field9&gt;, &lt;field99&gt;

希望能向正确的方向轻推。

【问题讨论】:

【参考方案1】:

不幸的是,这会有点复杂,因为这种格式包含一些您需要的数据,而这些数据未包含在清晰的标记中。

数据模型

另外,您对嵌套的理解并不完全正确。实际的天主教堂结构(不是本文档结构)更像是:

District (also called deanery or vicariate. In this case they all seem to be Vicariates Forane.)
    Cathedral, Parish, Oratory

请注意,尽管他们通常这样做,但没有要求教区属于区/教区。我认为该文件是说,在 District 之后列出的所有内容都属于该地区,但您无法确定。

那里还有一个入口,不是教堂而是社区(圣洛伦索菲律宾华人社区)。这些人在教会中没有明显的身份或治理(即它不是一座建筑物)——相反,它是一个牧师被分配照顾的非领土群体。

解析

我认为你应该采取渐进的方法:

    找到所有li元素,每个元素都是一个“项目” 项目名称是第一个文本节点 找到所有i 元素:这些是键、属性值、列行等 直到下一个i(由br 分隔)之前的所有文本都是该键的值。

这个页面的一个特殊问题是它的 html非常糟糕,你需要使用 MinimalSoup 来正确解析它。 特别是 BeautifulSoup认为 li 元素是嵌套的,因为文档中的任何位置都没有 olul

这段代码会给你一个元组列表。每个元组是一个项目的 ('key','value') 对。

一旦你有了这个数据结构,你就可以随心所欲地规范化、变换、嵌套等,并且把 HTML 留在后面。

from BeautifulSoup import MinimalSoup
import urllib

fp = urllib.urlopen("http://www.ucanews.com/diocesan-directory/html/ordinary-of-philippine-cagayandeoro-parishes.html")
html = fp.read()
fp.close()

soup = MinimalSoup(html);

root = soup.table.tr.td

items = []
currentdistrict = None
# this loops through each "item"
for li in root.findAll(lambda tag: tag.name=='li' and len(tag.attrs)==0):
    attributes = []
    parishordistrict = li.next.strip()
     # look for string "district" to determine if district; otherwise it's something else under the district
    if parishordistrict.endswith(' District'):
        currentdistrict = parishordistrict
        attributes.append(('_isDistrict',True))
    else:
        attributes.append(('_isDistrict',False))

    attributes.append(('_name',parishordistrict))
    attributes.append(('_district',currentdistrict))

    # now loop through all attributes of this thing
    attributekeys = li.findAll('i')

    for i in attributekeys:
        key = i.string # normalize as needed. Will be 'Address:', 'Parochial Victor:', etc
        # now continue among the siblings until we reach an <i> again.
        # these are "values" of this key
        # if you want a nested key:[values] structure, you can use a dict,
        # but beware of multiple <i> with the same name in your logic
        next = i.nextSibling
        while next is not None and getattr(next, 'name', None) != 'i':
            if not hasattr(next, 'name') and getattr(next, 'string', None):
                value = next.string.strip()
                if value:
                    attributes.append((key, value))
            next = next.nextSibling
    items.append(attributes)

from pprint import pprint
pprint(items)

【讨论】:

谢谢弗朗西斯。请给我一些时间来研究你的代码,以便我可以从中学习。顺便说一句,当我提到层次结构时,我指的是在页面的上下文中。感谢您的澄清。 啊,在那种情况下,li 嵌套仅仅是因为BeautifulSoup 解析器如何解释糟糕的 html。使用MinimalSoup 解析器将嵌套的lis 转换为li 的平面列表,这是大多数浏览器构造DOM 树的方式。 弗朗西斯,我做了一些小的调整,但你的代码做了所有(非常)肮脏的工作。重新“病态” html。我自己也是这么想的,但这可能比我找到的第一页要好 claretianpublications.com/index.php/diocese/… 我感谢您对 BeautifulSoup 的努力和帮助。非常感谢。

以上是关于beautifulSoup 不正确嵌套 <ul>s 的屏幕截图列表的主要内容,如果未能解决你的问题,请参考以下文章

BeautifulSoup:如何从包含一些嵌套 <ul> 的 <ul> 列表中提取所有 <li>?

BeautifulSoup:抓取蒸汽愿望清单游戏 - .findAll 不返回在检查器中可见的嵌套 div

Beautifulsoup 将标签中的文本通过 <br/> 拆分

python beautifulsoup 怎么得到option的值

HTML 和 BeautifulSoup:当结构并不总是事先知道时如何迭代解析?

如何使用Python中的BeautifulSoup从HTML链接解析嵌套表?