Поиск тэга искомого текста в HTML - PullRequest
0 голосов
/ 11 ноября 2019

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

from bs4 import BeautifulSoup
import re

html_page1 = """
<div class='product-box'>
<h2 class='title'>Title Book</h2>
<p class='price>18.45</p>
</div>
"""

html_page2 = """
<div class='page-box'>
<h2 class='orange-heading'>Title Book</h2>
<p class='blue-price'>18.45</p>
</div>
"""

# turn page into soup
soup1 = BeautifulSoup(html_page1, 'html.parser')

# find book titles
names1 = soup1.find_all(string=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))"))

# print titles
print('Names1: ', names1)

# turn page into soup
soup2 = BeautifulSoup(html_page2, 'html.parser')

# find book titles
names2 = soup2.find_all(string=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))"))

# print titles
print('Names2: ', names2)

Возвращает:

Names1:  ['Title Book']
Names2:  ['Title Book']

Теперь я хочу использовать эту информацию, чтобы найти соответствующую цену. Я знаю, что когда элемент был выбран с помощью тегов и имен классов, можно использовать «next_sibling», однако это не работает для элемента, выбранного текстом:

select_title = soup1.find('h2', {"class": "title"})
next_sib = new_try.next_sibling
print(next_sib) # returns <p class='price>18.45

# now try the same thing on element selected by name, this will result in an error
next_sib = names1.next_sibling 

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

Подобный вопрос можно найти здесь: Найти данные в тегах HTML с использованием Python Однако, он все еще использует HTMLтеги.

РЕДАКТИРОВАТЬ Проблема в том, что у меня много страниц с разными макетами и именами классов. Из-за этого я не могу использовать имя тега / класса / идентификатора, чтобы найти элементы, и мне нужно найти названия книг с помощью регулярных выражений.

Ответы [ 2 ]

2 голосов
/ 11 ноября 2019

Чтобы получить цену Включите тег 'h2' при этом find_all () И затем используйте find_next ('p'). В первом примере тега p, где строка отсутствует для имени класса, я добавил строку class='price'.

from bs4 import BeautifulSoup
import re

html_page1 = """
<div class='product-box'>
<h2 class='title'>Title Book</h2>
<p class='price'>18.45</p>
</div>
"""

html_page2 = """
<div class='page-box'>
<h2 class='orange-heading'>Title Book</h2>
<p class='blue-price'>18.45</p>
</div>
"""


# turn page into soup
soup1 = BeautifulSoup(html_page1, 'html.parser')

# find book titles
names1 = soup1.find_all('h2',string=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))"))

# print titles
print('Names1: ', names1[0].find_next('p').text)


# turn page into soup
soup2 = BeautifulSoup(html_page2, 'html.parser')

# find book titles
names2 = soup2.find_all('h2',string=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))"))

# print titles
print('Names2: ', names2[0].find_next('p').text)

Или измените строку на текст

from bs4 import BeautifulSoup
import re

html_page1 = """
<div class='product-box'>
<h2 class='title'>Title Book</h2>
<p class='price'>18.45</p>
</div>
"""

html_page2 = """
<div class='page-box'>
<h2 class='orange-heading'>Title Book</h2>
<p class='blue-price'>18.45</p>
</div>
"""


# turn page into soup
soup1 = BeautifulSoup(html_page1, 'html.parser')

# find book titles
names1 = soup1.find_all(text=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))"))

# print titles
print('Names1: ', names1[0].find_next('p').text)


# turn page into soup
soup2 = BeautifulSoup(html_page2, 'html.parser')

# find book titles
names2 = soup2.find_all(text=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))"))

# print titles
print('Names2: ', names2[0].find_next('p').text)

EDITED Используйте текст, чтобы получить элемент без тега, и next_element, чтобы получитьзначение цены.

from bs4 import BeautifulSoup
import re

html_page1 = """
<div class='product-box'>
<h2 class='title'>Title Book</h2>
<p class='price'>18.45</p>
</div>
"""

html_page2 = """
<div class='page-box'>
<h2 class='orange-heading'>Title Book</h2>
<p class='blue-price'>18.45</p>
</div>
"""

# turn page into soup
soup1 = BeautifulSoup(html_page1, 'html.parser')
# find book titles
names1 = soup1.find_all(text=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))"))
# print titles
print('Names1: ', names1[0])
print('Price1: ', names1[0].next_element.next_element.next_element)
# turn page into soup
soup2 = BeautifulSoup(html_page2, 'html.parser')
# find book titles
names2 = soup2.find_all(text=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))"))
# print titles
print('Names2: ', names2[0])
print('Price2: ', names2[0].next_element.next_element.next_element)

Выход :

Names1:  Title Book
Price1:  18.45
Names2:  Title Book
Price2:  18.45
0 голосов
/ 11 ноября 2019

Вы пропустили запятую закрытия класса для p.price в html_page1.
С names1 = soup1.find_all(text=re.compile("[A-Z]([a-z]+,|\.|[a-z]+)(?:\s{1}[A-Z]([a-z]+,|\.|[a-z]+))")) вы получите NavigableString, поэтому вы получите None для next_sibling.

Вы можете найти решение с помощью регулярных выражений в ответе @Kunduk.
Альтернативное, более ясное и простое решение для html_page1 и html_page2:

soup = BeautifulSoup(html_page1, 'html.parser')
# or BeautifulSoup(html_page2, 'html.parser')

books = soup.select('div[class*=box]')
for book in books:
    book_title = book.select_one('h2').text
    book_price = book.select_one('p[class*=price]').text
    print(book_title, book_price)

div[class*=box] означает div где класс содержит box .

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