Удаление из массива , когда у некоторых нет дочерних элементов

#python #html #beautifulsoup #html-parsing

Вопрос:

Я пытаюсь очистить данные в Интернете, некоторые из которых являются <li> элементами. Я думаю, проблема в том, что у некоторых <ul> родителей нет <li> детей.

Пример HTML-кода таков — =

 <div class="tab-pane predefined-carrier-DPDUK ">
    <img src="https://assets.easypost.com/assets/images/carriers/dpd-logo.c4b107116e903920a5794e69e1990827.svg" alt="DPD UK">
    <ul>
        <li>Parcel</li>
        <li>Pallet</li>
        <li>ExpressPak</li>
        <li>FreightParcel</li>
        <li>Freight</li>
    </ul>
</div>
<div class="tab-pane predefined-carrier-ChinaEMS ">
    <img src="https://assets.easypost.com/assets/images/carriers/china-ems-logo-ca.0c938786bd8d8f141e8fa9337a3362a4.png" alt="EMS">
    <p>No predefined packages for EMS.</p>
    <ul></ul>
</div>
<div class="tab-pane predefined-carrier-Estafeta ">
    <img src="https://assets.easypost.com/assets/images/carriers/estafeta-logo-ca.886242ba90c68a1d68f0e4e5a3a14419.png" alt="Estafeta">
    <ul>
        <li>ENVELOPE</li>
        <li>PARCEL</li>
    </ul>
</div>
 

Таким образом, некоторые из <ul> них не вернут никаких результатов, т. е. не <li> будут иметь детей. Я придумал пару «решений»

Этот должен повторяться через каждый <ul> , но он всегда терпит неудачу во втором try , поэтому не возвращает <li>

 import requests
from bs4 import BeautifulSoup

r = requests.get("https://www.easypost.com/docs/api#parcels", headers={'User-agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0'})
c = r.content

soup= BeautifulSoup(c, "html.parser")

all = soup.find_all("div", {"class":lambda L: L and L.startswith("tab-pane predefined-carrier")})

for item in all:
    print("n".join([img['alt'] for img in item.find_all('img', alt=True)]))   
    
    try:
        print(item.find("p").text)
    except:
        print("HAS PACKAGES")
    
    try:
        for ul in all.find_all("ul"):
            for litag in ultag.find_all("li"):
                print(litag.text)
    except:
        print("has no list items")
    
    print("")
 

Результирующий набор таков :

 DPD UK
HAS PACKAGES
has no list items

EMS
No predefined packages for EMS.
has no list items

Estafeta
HAS PACKAGES
has no list items
 

Второе решение заключается в том, что оно возвращает <li> , но я не могу найти способ, чтобы каждый <li> из них печатался в новой строке:

 import requests
from bs4 import BeautifulSoup

r = requests.get("https://www.easypost.com/docs/api#parcels", headers={'User-agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0'})
c = r.content

soup= BeautifulSoup(c, "html.parser")

all = soup.find_all("div", {"class":lambda L: L and L.startswith("tab-pane predefined-carrier")})

for item in all:
    print("n".join([img['alt'] for img in item.find_all('img', alt=True)]))   
    
    try:
        print(item.find("p").text)
    except:
        print("HAS PACKAGES")
    
    try:
            print(item.find_all("ul")[0].text)
    except:
        pass
    print("")
 

Результирующий набор аналогичен этому:

 DPD UK
HAS PACKAGES
ParcelPalletExpressPakFreightParcelFreight

EMS
No predefined packages for EMS.


Estafeta
HAS PACKAGES
ENVELOPEPARCEL
 

Надеюсь, кто-нибудь наставит меня на правильный путь, ТИА

Комментарии:

1. похоже, что первая ошибка в написании должна быть for ul in item.find_all("ul"):

2. Спасибо за ответ, я попытался это сделать, но затем вернул данные следующим образом: > DPD >>Нет предопределенных пакетов для DPD. > Обратитесь в службу поддержки >> Свяжитесь с отделом продаж > > > >>> > DPD UK >>>>>ЕСТЬ ПАКЕТЫ > > > > > > > Обратитесь в службу поддержки > > > > > > > > Свяжитесь с отделом продаж >>>>>>>> >>>>>>>>>EMS >>>>>>>>>>Нет предопределенных пакетов для EMS. > Обратитесь в службу поддержки >> Свяжитесь с отделом продаж

Ответ №1:

Это может вам помочь. Я попытался извлечь <ul> его и проверить, есть ли <li> в нем теги. Только тогда я печатаю этот <li> контент в новой строке.

 import requests
from bs4 import BeautifulSoup

r = requests.get("https://www.easypost.com/docs/api#parcels", headers={'User-agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0'})
c = r.content

soup= BeautifulSoup(c, "html.parser")

div_tag = soup.find_all("div", {"class":lambda L: L and L.startswith("tab-pane predefined-carrier")})

for i in div_tag:
    uls = i.find('ul')
    # Checks if <ul> is empty. That is no <li> tags present
    if uls.text != '':
        # Gets all the <li> from <ul>
        li_tags = uls.findAll('li')
        # print the text of <li> one after other in new line
        for item in li_tags:
            print(item.text)
        print('n')

 
 Sample Output:

Parcel
Pallet
ExpressPak
FreightParcel
Freight

ENVELOPE
PARCEL

Parcel
Satchel
 

Комментарии:

1. Это здорово, спасибо! Он хорошо работает как автономный, но когда я вставляю его в свой for item in all: блок кода, я получаю AttributeError: 'int' object has no attribute 'text' , что изменил первую строку в вашем коде, на for i in item: которую я получаю вышеуказанную ошибку. Если я изменю его на » для i во всех: , I get all the <li>», указанный для всех элементов в переменной all