Извлечение значений таблиц из HTML с одинаковыми именами тегов с использованием Beautiful Soup в Python

#python #html #beautifulsoup

#python #HTML #beautifulsoup

Вопрос:

Я пытаюсь получить все td text для приведенной ниже таблицы, используя Beautiful Soup, к сожалению, имена тегов совпадают, и я могу либо получить только первый элемент, либо некоторые элементы повторно печатаются. Следовательно, не совсем уверен, как это сделать.

Ниже приведен фрагмент таблицы HTML:

 <div>Table</div>
<table class="Auto" width="100%">
    <tr>
       <td class="Auto_head">Address</td>
       <td class="Auto_head">Name</td>
       <td class="Auto_head">Type</td>
       <td class="Auto_head">Value IN</td>
       <td class="Auto_head">AUTO Statement</td>
       <td class="Auto_head">Value OUT</td>
       <td class="Auto_head">RESULT</td>
       <td class="Auto_head"></td>
    </tr>
    <tr>
           <td class="Auto_body">1</td>
           <td class="Auto_body">abc</td>
           <td class="Auto_body">yes</td>
           <td class="Auto_body">abc123</td>
           <td class="Auto_body">jar</td>
           <td class="Auto_body">123abc</td>
           <td class="Auto_body">PASS</td>
           <td class="Auto_body">na</td>
    </tr>
 

Я хочу, чтобы все текстовое содержимое внутри этих тегов, например, первое auto_head соответствует первому auto_body , т.Е. Address = 1 Аналогично должны быть извлечены все значения.

Я использовал find, findall, FindNext и next_sibling, но безуспешно. Вот мой текущий код на python:

 self.table = self.soup_file.findAll(class_="Table")
self.headers = [tab.find(class_="Auto_head").findNext('td',class_="Auto_head").contents[0] for tab in self.table]
self.data = [data.find(class_="Auto_body").findNext('td').contents[0] for data in self.table]
 

Ответ №1:

Сначала получите заголовки, затем используйте zip(...) для объединения

 from bs4 import BeautifulSoup

data = '''
<table class="Auto" width="100%">
    <tr>
       <td class="Auto_head">Address</td>
       <td class="Auto_head">Name</td>
       <td class="Auto_head">Type</td>
    </tr>
    <tr>
           <td class="Auto_body">1</td>
           <td class="Auto_body">abc</td>
           <td class="Auto_body">yes</td>
    </tr>
    <tr>
           <td class="Auto_body">2</td>
           <td class="Auto_body">def</td>
           <td class="Auto_body">no</td>
    </tr>
    <tr>
           <td class="Auto_body">3</td>
           <td class="Auto_body">ghi</td>
           <td class="Auto_body">maybe</td>
    </tr>
</table>
'''

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

for table in soup.select('table.Auto'):
    # get rows
    rows = table.select('tr')
    # get headers
    headers = [td.text for td in rows[0].select('td.Auto_head')]
    # get details
    for row in rows[1:]:
        values = [td.text for td in row.select('td.Auto_body')]
        print(dict(zip(headers, values)))
 

Мой вывод:

 {'Address': '1', 'Name': 'abc', 'Type': 'yes'}
{'Address': '2', 'Name': 'def', 'Type': 'no'}
{'Address': '3', 'Name': 'ghi', 'Type': 'maybe'}
 

Ответ №2:

Сначала получите каждую категорию, затем выполните итерацию, используя zip

 s = '''<div>Table</div>
<table class="Auto" width="100%">
    <tr>
       <td class="Auto_head">Address</td>
       <td class="Auto_head">Name</td>
       <td class="Auto_head">Type</td>
       <td class="Auto_head">Value IN</td>
       <td class="Auto_head">AUTO Statement</td>
       <td class="Auto_head">Value OUT</td>
       <td class="Auto_head">RESULT</td>
       <td class="Auto_head"></td>
    </tr>
    <tr>
           <td class="Auto_body">1</td>
           <td class="Auto_body">abc</td>
           <td class="Auto_body">yes</td>
           <td class="Auto_body">abc123</td>
           <td class="Auto_body">jar</td>
           <td class="Auto_body">123abc</td>
           <td class="Auto_body">PASS</td>
           <td class="Auto_body">na</td>
    </tr></table>'''

soup = BeautifulSoup(s,features='html')
head = soup.find_all(name='td',class_='Auto_head')
body = soup.find_all(name='td',class_='Auto_body')
for one,two in zip(head,body):
    print(f'{one.text}={two.text}')
 

 Address=1
Name=abc
Type=yes
Value IN=abc123
AUTO Statement=jar
Value OUT=123abc
RESULT=PASS
=na
 

Поиск по классу CSS

Ответ №3:

Самое простое решение — добавить метод find_all в конце find, чтобы ваш код был

 source = requests.get('YOUR URL')
soup=BeautifulSoup(source.text,'html.parser')

data = soup.find('tr').find_all('td')[0]
data = soup.find('tr').find_all('td')[1]
 

и так далее, просто измените последний номер списка 0,1,2 … или используйте цикл for для того же