У меня есть 4 вложенных тега div, и когда я печатаю текст с помощью find_all, он печатает текст 4 раза - PullRequest
2 голосов
/ 09 июня 2019

Я извлекаю текст из HTML-файла, который содержит много тегов div. Однако в некоторых местах есть, скажем, 4 вложенных тега div, и когда я печатаю текст, он печатает его 4 раза.

<div>
    <div id="PGBRK" style="TEXT-INDENT: 0pt; WIDTH: 100%; MARGIN-LEFT: 0pt; MARGIN-RIGHT: 0pt">
        <div id="PN" style="PAGE-BREAK-AFTER: always; WIDTH: 100%">
            <div style="TEXT-ALIGN: center; WIDTH: 100%"><font style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 10pt">27</font></div> 
        </div>
    </div>
</div>

Например, вот если я делаю:

for item in page_soup.find_all('div'):
    if "27" in item.text:
            print(item)

Он печатает число 27 четыре раза и поэтому портит весь текст. Как я могу получить свой код, чтобы печатать вложенный текст только один раз?

РЕДАКТИРОВАТЬ 1: Это хорошо работает для этой части кода. Но, как я уже сказал, в некоторых местах это верно. Например, когда я делаю:

for item in page_soup.find_all('div', recursive = False):
    print(item)

Он ничего не печатает. Для справки это - документ, который я пытаюсь очистить.

РЕДАКТИРОВАТЬ 2: Из данного html я пытаюсь извлечь раздел «ПУНКТ 1А. ФАКТОРЫ РИСКА».

should_print = False

for item in page_soup.find_all('div'):
    if "ITEM 1A." in item.text:
        should_print = True
    elif "ITEM 1B." in item.text:
        break
    if should_print:
        print(item)

Итак, я печатаю все, начиная с пункта 1А. пока не найдет пункт 1B. Здесь в некоторых местах есть вложенные теги div, которые печатаются с этим фрагментом кода несколько раз.

Если я это сделаю, recursive = False, он ничего не печатает.

Ответы [ 5 ]

0 голосов
/ 11 июня 2019

Я отвечу на свой вопрос, так как наконец-то заставил его работать.

Решение было простым, я просто думал, что слишком сложно.Я просто добавил условие, что родительский элемент не должен быть "div".Теперь программа не печатает текст несколько раз.

should_print = False

for item in page_soup.find_all('div'):
    if item.name == "div" and item.parent.name != "div"
        if "ITEM 1A." in item.text:
            should_print = True
        elif "ITEM 1B." in item.text:
            break
        if should_print:
            print(item)

Спасибо всем за ваш вклад.Оценил ...

0 голосов
/ 10 июня 2019

Ну, я думаю, что это крутой вопрос, и я не вижу простого ответа, если вы хотите обобщить его, чтобы выяснить, какой текст есть на каждом уровне, не прибегая к поиску определенного числа, такого как 27. Красивый суп похоже, не имеет функции для показа только текста в верхней части, а recursive = False просто предотвращает погружение поиска ниже первого уровня, но все равно будет содержать все содержимое ниже первого уровня в качестве содержимого, поэтому если на верхнем уровне теги, то он будет захватывать его и все, что ниже

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

from bs4 import BeautifulSoup
soup = BeautifulSoup('<div>1A<div>2A</div>1B<div>2B<div>3A</div><div>3A</div>2C</div>1C</div>', 'html.parser')

def mangle(node):
    divs = node.find_all('div')
    if len(divs):
        result = [divs[0]] + [n for n in divs[0].next_siblings if n.__class__.__name__ == 'Tag']
        txt = []
        for r in result:
            txt.append(r.__repr__())
            for c in mangle(r):
                txt[-1] = txt[-1].replace(c.__repr__(), '')

        print(''.join(BeautifulSoup(t, 'html.parser').text for t in txt))
        return result
    else:
        return []    

if __name__ == '__main__':
    mangle(soup)

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

Выход из html 1A2A1B2B3A3A2C1C был

3A3A
2A2B2C
1A1B1C

3-й, 2-й и 1-й уровни вложенности соответственно. Надеюсь, это поможет.

0 голосов
/ 09 июня 2019

Вот один вариант

import bs4, re

html = '''<div>
<div id="PGBRK" style="TEXT-INDENT: 0pt; WIDTH: 100%; MARGIN-LEFT: 0pt; MARGIN-RIGHT: 0pt">

<div id="PN" style="PAGE-BREAK-AFTER: always; WIDTH: 100%">

<div style="TEXT-ALIGN: center; WIDTH: 100%"><font style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 10pt">27</font></div>

</div>
</div>
</div>
</div>'''

soup = bs4.BeautifulSoup(html,'html.parser')
elements = soup.find_all(text=re.compile('27'))
print(elements)

выход

[u'27']
0 голосов
/ 09 июня 2019

печать всего, начиная с ITEM 1A.пока он не найдет атрибут ITEM 1B

Корыто .string (https://www.crummy.com/software/BeautifulSoup/bs4/doc/#string)

import requests
from bs4 import BeautifulSoup

url = 'https://www.sec.gov/Archives/edgar/data/4904/000000490412000013/ye11aep10k.htm'
html_doc = requests.get(url).content
page_soup = BeautifulSoup(html_doc, 'html.parser')

do_print = False
for el in page_soup.find_all('div'):
    if el.string:
        if "ITEM 1A" in el.string:
            do_print = True
        elif "ITEM 1B" in el.string:
            break
    if do_print:
        print(el)

Выход (я покажу репрезентативные начальный и конечный блоки без средней части,сделать короткий дамп):

<div align="justify" style="TEXT-INDENT: 0pt; DISPLAY: block; MARGIN-LEFT: 0pt; MARGIN-RIGHT: 0pt"><font style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 12pt; FONT-WEIGHT: bold"><font style="DISPLAY: inline; TEXT-DECORATION: underline">ITEM 1A.   RISK FACTORS</font></font></div>
<div style="TEXT-INDENT: 0pt; DISPLAY: block"><br/>
</div>
<div align="justify" style="TEXT-INDENT: 0pt; DISPLAY: block; MARGIN-LEFT: 0pt; MARGIN-RIGHT: 0pt"><font style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 12pt; FONT-WEIGHT: bold">GENERAL RISKS OF OUR REGULATED OPERATIONS</font></div>
<div style="TEXT-INDENT: 0pt; DISPLAY: block">
<div align="justify" style="TEXT-INDENT: 0pt; DISPLAY: block; MARGIN-LEFT: 0pt; MARGIN-RIGHT: 0pt"><font style="FONT-STYLE: italic; DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 12pt; FONT-WEIGHT: bold"> </font></div>
<div align="justify" style="TEXT-INDENT: 0pt; DISPLAY: block; MARGIN-LEFT: 0pt; MARGIN-RIGHT: 0pt"><font style="FONT-STYLE: italic; DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 12pt; FONT-WEIGHT: bold">The regulatory environment in Ohio has recently become unpredictable and increasingly uncertain. – Affecting AEP and OPCo</font></div>
<div style="TEXT-INDENT: 0pt; DISPLAY: block"><br/>
.....
<div style="TEXT-ALIGN: center; WIDTH: 100%"><font style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 10pt">37</font></div>
<div style="TEXT-ALIGN: center; WIDTH: 100%">
<hr noshade="" size="2" style="COLOR: black"/>
</div>
<div id="HDR">
<div align="right" id="GLHDR" style="WIDTH: 100%"><font style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 8pt">  </font></div>
</div>
<div align="right" id="GLHDR" style="WIDTH: 100%"><font style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 8pt">  </font></div>
<div style="TEXT-INDENT: 0pt; DISPLAY: block"> </div>
0 голосов
/ 09 июня 2019

Вы можете предоставить опцию text = "27" для поиска элементов div по тексту и определения только этого точного элемента div. Приведенный ниже код должен работать нормально. Если вы хотите получить все элементы div, просто удалите text = "27" или замените его тем текстом, который вы хотите найти. Вы также можете использовать recursive = False, чтобы получить только div верхнего уровня.

Редактировать 1:

from bs4 import BeautifulSoup

t = '''
<div>
27
</div>
<div>
<div id="PGBRK" style="TEXT-INDENT: 0pt; WIDTH: 100%; MARGIN-LEFT: 0pt; MARGIN-RIGHT: 0pt">

<div id="PN" style="PAGE-BREAK-AFTER: always; WIDTH: 100%">

<div style="TEXT-ALIGN: center; WIDTH: 100%"><font style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 10pt">27</font></div>

</div>
</div>
</div>
</div>
'''

page_soup = BeautifulSoup(t, 'html.parser')

for item in page_soup.find_all('div', text="27"):
    print(item.text)

Редактировать 2:

Я добавил специальный код, который подходит именно для вашей проблемы. Попробуйте приведенный ниже код. Ожидаемый диапазон div от 567 - 715 с удаленными номерами страниц.

import requests
from bs4 import BeautifulSoup

resp = requests.get(
    r'https://www.sec.gov/Archives/edgar/data/4904/000000490412000013/ye11aep10k.htm')
t = resp.text

page_soup = BeautifulSoup(t, 'html.parser')

s = 'body > div:not(#PGBRK)'

for i in page_soup.select(s)[567:715]:
   print(i.get_text(strip=True))

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