Перебирая HTML с красивым супом в Python - PullRequest
0 голосов
/ 12 января 2019

Я пытаюсь перебрать HTML-таблицу.

На странице, которую я просматриваю, есть только одна таблица. Так что это легко найти. В соответствии с этим есть несколько <tr> с, и я хочу рассмотреть их отдельно от некоторых заголовков, определенных как <th> вместо <td> с. Каждый <tr> состоит из нескольких различных классов <td>. Я только собираю два <td> с class = "table-name" и <td> с class = "table-Score".

Я пытался работать с:

rows = html.find("table", class_="table").find_all("tr")

for row in rows:
    if row.find("th") is None:
        td_names = row.findall("td")

for td_name in td_names:
    print(td_name)

Но у меня действительно есть какой-то успех.

Так что в основном HTML выглядит примерно так:

<table>
  <tr>
    <th>Header</th>
  </tr>
  <tr>
    <td class="table-rank">1</td>
    <td class="table-name">John</td>
    <td class="table-name">Jim</td>
    <td class="table-place">Russia</td>
    <td class="table-score">2-1</td>
  </tr>
</table>

Я ищу только "Джон", "Джим", "2-1".

Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 12 января 2019

В вашем конкретном примере .find("table", class_="table") ничего не вернет, потому что ищет таблицу с именем класса "table". Ваш <table> тег здесь просто <table>, а не <table class="table">.

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

from bs4 import BeautifulSoup

html = """
<table>
  <tr>
    <th>Header</th>
  </tr>
  <tr>
    <td class="table-rank">1</td>
    <td class="table-name">John</td>
    <td class="table-name">Jim</td>
    <td class="table-place">Russia</td>
    <td class="table-score">2-1</td>
  </tr>
</table>
"""

soup = BeautifulSoup(html, 'html.parser')
t = soup.find('table')

td_data = []

for row in t.find_all('tr'):
    # Ignore any rows containing a <th> cell.
    if not row.th:
        # Generate a list of any strings found inside <td class="table-name"> tags.
        # Concatenate this list with td_data.  Do the same with cells of the class "table-score".
        td_data += [ s.string for s in row.find_all('td', class_="table-name") ]
        td_data += [ s.string for s in row.find_all('td', class_="table-score") ]

print(td_data)

Причина, по которой я объявил td_data как пустой список, а затем просто добавил в него новые списки, заключается в том, что вы можете запустить этот алгоритм для таблиц, в которых есть несколько строк, которые могут иметь то, что вы ищете. Кроме того, есть несколько способов выполнить поиск типа «или», чтобы найти теги с любым из классов, которые вы хотите, но так как их всего два, я подумал, что было достаточно просто собрать полный список таблиц. именные значения и табличные значения. Если один из них окажется пустым, то td_data не изменится.

0 голосов
/ 12 января 2019

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

html = """
<table>
  <tr>
    <th>Header</th>
  </tr>
  <tr>
    <td class="table-rank">1</td>
    <td class="table-name">John</td>
    <td class="table-name">Jim</td>
    <td class="table-place">Russia</td>
    <td class="table-score">2-1</td>
  </tr>
</table>
"""

import pandas as pd


df = pd.read_html(html, skiprows=1)
results = df[0]

EDIT: Если вас больше волнуют фактические атрибуты класса, я могу предложить 2 варианта.

Опция: 1

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

import pandas as pd
import bs4

html = """
<table>
  <tr>
    <th>Header</th>
  </tr>
  <tr>
    <td class="table-rank">1</td>
    <td class="table-name">John</td>
    <td class="table-name">Jim</td>
    <td class="table-place">Russia</td>
    <td class="table-score">2-1</td>
  </tr>
</table>
"""

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

keep_list = ["table-name", "table-score"]

for data in soup.find_all('td'):
    class_attr = data['class'][0]
    if class_attr in keep_list:
        continue
    else:
        soup.select("td."+class_attr)[0].decompose()

df = pd.read_html(str(soup), skiprows=1)
results = df[0]

Выход:

print (results)
      0    1    2
0  John  Jim  2-1

Опция: 2

Подобно другим решениям, просто найдите определенные атрибуты класса.

import bs4

html = """
<table>
  <tr>
    <th>Header</th>
  </tr>
  <tr>
    <td class="table-rank">1</td>
    <td class="table-name">John</td>
    <td class="table-name">Jim</td>
    <td class="table-place">Russia</td>
    <td class="table-score">2-1</td>
  </tr>
</table>
"""

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

keep_list = ["table-name", "table-score"]
alpha = soup.find_all('td', class_=lambda x: x in keep_list)

for data in alpha:
    print (data.text)

# or if wanted in list
results = [ data.text for data in alpha ]

Выход:

John
Jim
2-1

В качестве альтернативы, список можно сделать в 3 строки:

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

keep_list = ["table-name", "table-score"]

results = [ data.text for data in soup.find_all('td', class_=lambda x: x in keep_list)]

Выход:

print (results)
['John', 'Jim', '2-1']
0 голосов
/ 12 января 2019

find_all () вернет список всех элементов, соответствующих фильтру. Вы можете использовать индекс списка, чтобы выбрать нужный элемент. 0 для первого, 1 для второго и т. Д.

from bs4 import BeautifulSoup
html="""
<table>
<tr>
<th>Header</th>
</tr>
<tr>
<td class="table-rank">1</td>
<td class="table-name">John</td>
<td class="table-name">Jim</td>
<td class="table-place">Russia</td>
<td class="table-score">2-1</td>
</tr>
</table>
"""
soup=BeautifulSoup(html,'html.parser')
our_tr=soup.find('table').find_all('tr')[1] #the second tr in the table - index starts at 0
#print all td's of seconf tr
our_tds=our_tr.find_all('td')
print(our_tds[1].text)
print(our_tds[2].text)
print(our_tds[4].text)

выход

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