Python BeautifulSoup извлекает текст сразу после определенного тега

#python #python-3.x #web-scraping #beautifulsoup

#python #python-3.x #веб-очистка #beautifulsoup

Вопрос:

Я пытаюсь извлечь информацию с веб-страницы, используя beautifulsoup и python. Я хочу извлечь информацию прямо под определенным тегом. Чтобы узнать, правильный ли это тег, я хотел бы сравнить его текст, а затем извлечь текст в следующем непосредственном теге.
Скажем, например, если следующее является частью HTML-страницы-источника,

 <div class="row">
    ::before
    <div class="four columns">
        <p class="title">Procurement type</p>
        <p class="data strong">Services</p>
    </div>
  <div class="four columns">
      <p class="title">Reference</p>
      <p class="data strong">ANAJSKJD23423-Commission</p>
  </div>
  <div class="four columns">
      <p class="title">Funding Agency</p>
      <p class="data strong">Health Commission</p>
  </div>
  ::after
</div>
<div class="row">
    ::before
    ::after
</div>
<hr>
<div class="row">
    ::before
    <div class="twelve columns">
        <p class="title">Countries</p>
        <p class="data strong">
            <span class>Belgium</span>
            ", "
            <span class>France</span>
            ", "
            <span class>Luxembourg</span>
        </p>
        <p></p>
    </div>
    ::after
</div>
  

Я хочу проверить, имеет ли значение <p class="title"> text, так как Procurement type тогда я хочу распечатать сервисы
Аналогично, если <p class="title"> имеет текстовое значение as Reference , то я хочу распечатать ANAJSKJD23423-Commission, и если <p class="title"> имеет значение as Countries , то распечатайте все страны, то есть Бельгию, Францию, Люксембург.

Я знаю, что могу извлечь все тексты <p class="data strong"> и добавить их в список, а затем извлечь все значения с помощью индексации. Но дело в том, что порядок их появления <p class="title> не fixed….at в некоторых местах страны могут быть упомянуты перед типом закупок. Поэтому я хочу выполнить проверку текстовых значений, а затем извлечь текстовое значение следующего непосредственного тега. Я все еще новичок в BeautifulSoup, поэтому любая помощь приветствуется. Спасибо

Ответ №1:

Вы можете сделать это многими способами.Вот так.

 from bs4 import BeautifulSoup
htmldata='''<div class="row">
    ::before
    <div class="four columns">
        <p class="title">Procurement type</p>
        <p class="data strong">Services</p>
    </div>
  <div class="four columns">
      <p class="title">Reference</p>
      <p class="data strong">ANAJSKJD23423-Commission</p>
  </div>
  <div class="four columns">
      <p class="title">Funding Agency</p>
      <p class="data strong">Health Commission</p>
  </div>
  ::after
</div>
<div class="row">
    ::before
    ::after
</div>
<hr>
<div class="row">
    ::before
    <div class="twelve columns">
        <p class="title">Countries</p>
        <p class="data strong">
            <span class>Belgium</span>
            ", "
            <span class>France</span>
            ", "
            <span class>Luxembourg</span>
        </p>
        <p></p>
    </div>
    ::after
</div>'''

soup=BeautifulSoup(htmldata,'html.parser')

items=soup.find_all('p', class_='title')
for item in items:
    if ('Procurement type' in item.text) or ('Reference' in item.text):
        print(item.findNext('p').text)
  

Ответ №2:

Вы также можете использовать :contains псевдокласс с bs4 4.7.1. Хотя я передал его в виде списка, вы можете выделить каждое условие

 from bs4 import BeautifulSoup as bs
import re

html = 'yourHTML'   
soup = bs(html, 'lxml')
items=[re.sub(r'ns ','', item.text.strip()) for item in soup.select('p.title:contains("Procurement type")   p, p.title:contains(Reference)   p, p.title:contains(Countries)   p')]
print(items)
  

Вывод:

введите описание изображения здесь

Ответ №3:

Вы можете добавить аргумент для проверки наличия определенного текста при использовании .find() или .find_all() затем использовать .next_sibling или findNext() для захвата следующих тегов с содержимым

Ie:

 soup.find('p', {'class':'title'}, text = 'Procurement type')
  

Учитывая:

 html = '''<div class="row">
    ::before
    <div class="four columns">
        <p class="title">Procurement type</p>
        <p class="data strong">Services</p>
    </div>
  <div class="four columns">
      <p class="title">Reference</p>
      <p class="data strong">ANAJSKJD23423-Commission</p>
  </div>
  <div class="four columns">
      <p class="title">Funding Agency</p>
      <p class="data strong">Health Commission</p>
  </div>
  ::after
</div>
<div class="row">
    ::before
    ::after
</div>
<hr>
<div class="row">
    ::before
    <div class="twelve columns">
        <p class="title">Countries</p>
        <p class="data strong">
            <span class>Belgium</span>
            ", "
            <span class>France</span>
            ", "
            <span class>Luxembourg</span>
        </p>
        <p></p>
    </div>
    ::after
</div>'''
  

вы могли бы сделать что-то вроде:

 from bs4 import BeautifulSoup     

soup = BeautifulSoup(html, 'html.parser')

alpha = soup.find('p', {'class':'title'}, text = 'Procurement type')
for sibling in alpha.next_siblings:
    try:
        print (sibling.text)
    except:
        continue
  

Вывод:

 Services
  

или

 ref = soup.find('p', {'class':'title'}, text = 'Reference')
for sibling in ref.next_siblings:
    try:
        print (sibling.text)
    except:
        continue
  

Вывод:

 ANAJSKJD23423-Commission    
  

или

 countries = soup.find('p', {'class':'title'}, text = 'Countries')
names = countries.findNext('p', {'class':'data strong'}).text.replace('", "','').strip().split('n')
names = [name.strip() for name in names if not name.isspace()]

for country in names:
    print (country)
  

Вывод:

 Belgium
France
Luxembourg