BeautifulSoup скрининг список неправильно вложенных <ul>с - PullRequest
3 голосов
/ 03 декабря 2011

Я (очень) новичок в BeautifulSoup и последние три дня пытаюсь получить список церквей из http://www.ucanews.com/diocesan-directory/html/ordinary-of-philippine-cagayandeoro-parishes.html.

Похоже, что данные неправильно вложены, а помечены только для целей презентации. Предположительно, иерархическая структура

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

Однако все, что я вижу, это то, что каждая церковь начинается с пули, и каждая запись разделяется двумя переносами строк. Имена полей, которые я ищу, выделены курсивом и отделены от фактических данных знаком «:». Каждая запись единицы (Район | Викариат | Приход) может иметь одно или несколько полей данных.

До сих пор я мог дразнить некоторые данные, но я не мог получить название сущности, чтобы показать.

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

Наконец, я надеюсь преобразовать данные по столбцам: district, vicariate, parish, address, phone, titular, parish priest, <field8>, <field9>, <field99>

Буду признателен за хороший толчок в правильном направлении.

1 Ответ

2 голосов
/ 03 декабря 2011

К сожалению, это будет немного сложно, потому что в этом формате есть некоторые данные, которые вам нужны, и они не сохраняются четкими маркерами.

Модель данных

Кроме того, ваше понимание вложенности не совсем верно. Фактическая структура католической церкви (не эта структура документа) больше похожа на:

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

Обратите внимание, что не требуется , чтобы приход попал под район / деканат, хотя они обычно это делают. Я думаю, что в документе говорится, что все, что перечислено после Района, принадлежит этому району, но вы не можете знать наверняка.

Там также есть запись, которая является не Церковью, а общиной (филиппинско-китайская община Сан-Лоренцо). Они не имеют четкой идентичности или управления в церкви (т. Е. Это не здание) - скорее, это не-территориальная группа людей, о которой капеллану поручено заботиться.

Синтаксический

Я думаю, что вы должны использовать пошаговый подход:

  1. найти все элементы li, каждый из которых является "элементом"
  2. название элемента - первый текстовый узел
  3. найти все элементы i: это ключи, значения атрибутов, строки столбцов и т. Д.
  4. весь текст до следующего i (разделенный br) является значением для этого ключа.

Одна особая проблема с этой страницей в том, что ее html настолько патологически плохой , что вам нужно использовать MinimalSoup для правильного его анализа. В частности, BeautifulSoup считает, что li элементы вложены, потому что в документе нет ol или ul!

Этот код даст вам список списков кортежей. Каждый кортеж представляет собой пару ('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)
...