Повторяйте теги div с помощью l xml и извлекайте текст для словаря в python - PullRequest
0 голосов
/ 02 февраля 2020

Я только что узнал lxmlx в python, и мне нужна помощь, так как у меня нет опыта работы с XPath. Я хочу получить текстовые данные с веб-страницы в словарь.

Я имею в виду фрагмент кода html, который я разместил ниже. На исходной странице html есть элемент div класса general-info, который я извлекаю, используя следующую строку:

general_info = document_tree.xpath("//div[contains(concat(' ', normalize-space(@class), ' '), 'general-info')]")

С этого момента я хочу перебирать вложенные div s и получать теги 2 <p> как ключ и значение. Текст внутри <strong> является ключом. Также могут быть пустые теги div, и может быть особый случай, когда ключ и значение словаря могут находиться в одном и том же элементе div (см. Последний элемент).

EDIT:

Количество элементов может изменяться, поэтому было бы лучше использовать теги <strong> в качестве отправной точки, а затем искать следующий тег <p>. Это код, который я смог написать с помощью BeautifulSoup:

generalinfo = documentSoup.findAll("div", {"class": "general-info"})
if generalinfo:
   strongs = generalinfo[0].find_all('strong')
   for descr in strongs:
        p = descr.find_next_sibling("p")
        if p:
            key = descr.text.strip().rstrip(':')
            details_dict[key] = p.text.strip()

        else:
            nextdiv = descr.parent.parent.find_next_sibling("div")
            if nextdiv:
                child = nextdiv.findChild()
                if child:
                    key = descr.text.strip()[:-1]
                    details_dict[key] = child.text.strip()

Я собираюсь сделать следующий вывод:

['Title:' : 'This is a title', 
'Owner:' : 'This is an owner',
'Category:' : 'This is a categroy',
'Type:' : 'This is a type',
'Special case:' : 'This is a special case']

Если кто-то может помочь мне здесь, я буду признателен!

html код:

   <body>
      <main>
       <div>
       ...
        <div class="general-info margin-bottom-20 margin-top-20">
            <div class="row padding-x-20">
                <div class="col-sm-4">
                    <p class="margin-0">
                        <strong>Title:</strong> 
                    </p>
                </div>
                <div class="col-sm-8">
                    <p class="margin-0">This is a title</p>
                </div>
            </div>
            <div class="row padding-x-20">
                <div class="col-sm-4">
                    <p class="margin-0">
                        <strong>Owner:</strong> 
                    </p>
                </div>
                <div class="col-sm-8">
                    <p class="margin-0">This is an owner</p>
                </div>
            </div>
            <h2 class="h3 margin-top-10 margin-bottom-10 padding-x-20">Validity</h2>
            <div class="row padding-x-20">
                <div class="col-sm-4">
                    <p class="margin-0">
                        <strong>Category:</strong> 
                    </p>
                </div>
                <div class="col-sm-8">
                    <p class="margin-0">This is a category</p>
                </div>
            </div>
            <div class="row padding-x-40"></div>
            <div class="row padding-x-20">
                <div class="col-sm-4">
                    <p class="margin-0">
                        <strong>Type:</strong> 
                    </p>
                </div>
                <div class="col-sm-8">
                    <p class="margin-0">This is a type</p>
                </div>
            </div>
            <div class="row padding-x-40">
                <div>
                    <strong>Special case:</strong>
                    <p>This is a special case</p>
                </div>
           </div>
        </div>
...

Ответы [ 2 ]

0 голосов
/ 04 февраля 2020

Я рекомендую другое решение, которое очень подходит для извлечения данных из XML.

from simplified_scrapy.spider import SimplifiedDoc 
html='''
 <body>
      <main>
        <div class="general-info margin-bottom-20 margin-top-20">
            <div class="row padding-x-20">
                <div class="col-sm-4">
                    <p class="margin-0">
                        <strong>Title:</strong> 
                    </p>
                </div>
                <div class="col-sm-8">
                    <p class="margin-0">This is a title</p>
                </div>
            </div>
            <div class="row padding-x-20">
                <div class="col-sm-4">
                    <p class="margin-0">
                        <strong>Owner:</strong> 
                    </p>
                </div>
                <div class="col-sm-8">
                    <p class="margin-0">This is an owner</p>
                </div>
            </div>
            <h2 class="h3 margin-top-10 margin-bottom-10 padding-x-20">Validity</h2>
            <div class="row padding-x-20">
                <div class="col-sm-4">
                    <p class="margin-0">
                        <strong>Category:</strong> 
                    </p>
                </div>
                <div class="col-sm-8">
                    <p class="margin-0">This is a category</p>
                </div>
            </div>
            <div class="row padding-x-40"></div>
            <div class="row padding-x-20">
                <div class="col-sm-4">
                    <p class="margin-0">
                        <strong>Type:</strong> 
                    </p>
                </div>
                <div class="col-sm-8">
                    <p class="margin-0">This is a type</p>
                </div>
            </div>
            <div class="row padding-x-40">
                <div>
                    <strong>Special case:</strong>
                    <p>This is a special case</p>
                </div>
           </div>
        </div>
'''
data={}
doc = SimplifiedDoc(html) # create doc
divs = doc.selects('div.general-info')
# First way
for div in divs:
  strongs = div.strongs
  for strong in strongs:
    p = strong.next
    if not p:
      p=strong.parent.next
    data[strong.text]=p.text
print(data)
data={}
# Second way
for div in divs:
  ds = div.selects('strong|p>text()')
  for i in range(0,len(ds),2):
    data[ds[i]]=ds[i+1]
print(data)

Результат:

{'Title:': 'This is a title', 'Owner:': 'This is an owner', 'Category:': 'This is a category', 'Type:': 'This is a type', 'Special case:': 'This is a special case'}
{'Title:': 'This is a title', 'Owner:': 'This is an owner', 'Category:': 'This is a category', 'Type:': 'This is a type', 'Special case:': 'This is a special case'}

Вот еще примеры: https://github.com/yiyedata/simplified-scrapy-demo/blob/master/doc_examples/

0 голосов
/ 03 февраля 2020

Я полагаю, что это примерно настолько обобщенно, насколько я могу получить при условии html:

general_info  = doc.xpath("//div[contains(concat(' ', normalize-space(@class), ' '), 'general-info')]//p[@class='margin-0']")
for i in general_info :
    if len(i.xpath('./strong/text()'))>0:        
        topic = i.xpath('./strong/text()')[0]
    if len(i.text.strip())>0:       
        entry += i.text.replace('\n','').strip()
        print(topic+'   '+i.text.replace('\n','').strip())
special = general_info[0].xpath('./ancestor::div[@class="general-info margin-bottom-20 margin-top-20"]//div/div/strong')[0]
print(special.text+"  ",special.xpath('./following-sibling::p/text()')[0])

Вывод:

('Title:   This is a title',
 'Owner:   This is an owner',
 'Category:   This is a category',
 'Type:   This is a type',
 'Special case:   This is a special case')
...