2016-06-04 2 views
0

Я пытаюсь извлечь информацию из таблицы с помощью bs4 и python. , когда я использую следующий код для извлечения информации из заголовка таблицы:Извлечение информации из таблицы, кроме заголовка таблицы с помощью bs4

tr_header=table.findAll("tr")[0] 
    tds_in_header = [td.get_text() for td in tr_header.findAll("td")] 
    header_items= [data.encode('utf-8') for data in tds_in_header] 
    len_table_header = len (header_items) 

Он работает, но для следующих кодов, которые я пытаюсь извлечь информацию из первой строки в конец таблицы:

tr_all=table.findAll("tr")[1:] 
    tds_all = [td.get_text() for td in tr_all.findAll("td")] 
    table_info= [data.encode('utf-8') for data in tds_all] 

Существует следующая ошибка:

AttributeError: 'list' object has no attribute 'findAll' 

Может кто-нибудь помочь мне, чтобы изменить его.

Это таблица информация:

<table class="codes"><tr><td><b>Code</b> 
</td><td><b>Display</b></td><td><b>Definition</b></td> 
</tr><tr><td>active<a name="active"> </a></td> 
<td>Active</td><td>This account is active and may be used.</td></tr> 
<tr><td>inactive<a name="inactive"> </a></td> 
<td>Inactive</td><td>This account is inactive 
and should not be used to track financial information.</td></tr></table> 

Это выход для tr_all:

[<tr><td><b>Code</b></td><td><b>Display</b></td><td><b>Definition</b></td></tr>, <tr><td>active<a name="active"> </a></td><td>Active</td><td>This account is active and may be used.</td></tr>, <tr><td>inactive<a name="inactive"> </a></td><td>Inactive</td><td>This account is inactive and should not be used to track financial information.</td></tr>] 
+0

Возможно, вам стоит написать html-код. Вы пытаетесь разобрать. Более того, поскольку 'tr_header' является единственным элементом bs4, вы можете вызвать findAll на нем. Но для списка строк (и это то, что вы, вероятно, получаете из 'tr_all'), вам нужно вызвать findAll для каждого элемента, не входящего в весь список (используя двойное понимание списка или лучше - отдельно для цикла - для чтения) – JustMe

+0

@JustMe, благодаря вы ! Даже для этого кода tr_all = table.findAll («tr») я все равно получаю список, но для этого: tr_header = table.findAll («tr») [0] Я не получаю список. Я совершенно смущен. У меня есть еще один вопрос. Возможно ли отредактировать этот код, чтобы добавить информацию таблицы из первой строки в конец таблицы: table_information = [td.get_text() для td в table.findAll ("td")]. Благодаря ! – Mary

ответ

1

для вашего первого вопроса,

import bs4 

text = """ 
<table class="codes"><tr><td><b>Code</b> 
</td><td><b>Display</b></td><td><b>Definition</b></td> 
</tr><tr><td>active<a name="active"> </a></td> 
<td>Active</td><td>This account is active and may be used.</td></tr> 
<tr><td>inactive<a name="inactive"> </a></td> 
<td>Inactive</td><td>This account is inactive 
and should not be used to track financial information.</td></tr></table>""" 

table = bs4.BeautifulSoup(text) 
tr_all = table.findAll("tr")[1:] 
tds_all = [] 
for tr in tr_all: 
    tds_all.append([td.get_text() for td in tr.findAll("td")]) 
    # if You prefer double list comprefension instead... 
table_info = [data[i].encode('utf-8') for data in tds_all 
             for i in range(len(tds_all))] 
print(table_info) 

дает

['active ', 'Active', 'inactive ', 'Inactive'] 

А что касается второго вопроса

tr_header=table.findAll("tr")[0] i do not get a list

Правда, [] является операция индексации, которая выбирает первый элемент из списка, таким образом, Вы получаете один элемент. [1:] - оператор нарезки (см. Хороший tutorial, если вам нужна дополнительная информация).

На самом деле, вы получаете список два раза для каждого вызова table.findAll ("tr") - для заголовка и остальной части строк. Конечно, это довольно избыточно. Если Вы хотите отделить маркеры из заголовка и отдыха, я думаю, что Вы, вероятно, хотите что-то вроде этого

tr_all = table.findAll("tr") 
header = tr_all[0] 
tr_rest = tr_all[1:] 
tds_rest = [] 
header_data = [td.get_text().encode('utf-8') for td in header] 

for tr in tr_rest: 
    tds_rest.append([td.get_text() for td in tr.findAll("td")]) 

и в отношении третьего вопроса

Is it possible to edit this code to add table information from the first row to the end of the table?

Учитывая Ваш желаемый результат в комментариях ниже:

rows_all = table.findAll("tr") 
header = rows_all[0] 
rows = rows_all[1:] 

data = [] 
for row in rows: 
    for td in row: 
     try: 
      data.append(td.get_text()) 
     except AttributeError: 
      continue 
print(data) 

# or more or less same as above, oneline 
data = [td.get_text() for row in rows for td in row.findAll("td")] 

[u'active', u'Active', u'This account is active and may be used.', u'inactive', u'Inactive', u'This account is inactive and should not be used to track financial information.'] 
+0

спасибо! мой желаемый результат: [u'active ', u'Active', u'Эту учетную запись активную и можно использовать. ', u'inactive', u'Inactive ', u'Эту учетную запись неактивны и не должны быть используется для отслеживания финансовой информации. '] – Mary

+0

Результат вашего кода включает в себя [' active ',' Active ',' inactive ',' Inactive '] – Mary

+0

Отличный код! Я высоко ценю ваше время – Mary

0

JustMe правильно ответил на этот вопрос. Другой эквивалентный вариант был бы:

import bs4 

text = """ 
<table class="codes"><tr><td><b>Code</b> 
</td><td><b>Display</b></td><td><b>Definition</b></td> 
</tr><tr><td>active<a name="active"> </a></td> 
<td>Active</td><td>This account is active and may be used.</td></tr> 
<tr><td>inactive<a name="inactive"> </a></td> 
<td>Inactive</td><td>This account is inactive 
and should not be used to track financial information.</td></tr></table>""" 

table = bs4.BeautifulSoup(text) 
tr_all = table.findAll("tr")[1:] 
# critical line: 
tds_all = [ td.get_text() for each_tr in tr_all for td in each_tr.findAll("td")] 
# and after that unchanged: 
table_info= [data.encode('utf-8') for data in tds_all] 

# for control: 
print(table_info) 

Это странное сооружение в критической линии служит уплощение списка списка «tds_all». lambda z: [x для y в z для x в y] выравнивает список списка z. Я заменил x и y и z в соответствии с этой конкретной ситуацией.

На самом деле я пришел к нему, потому что у меня был как промежуточный шаг как критическая строка: tds_all = [[td.get_text() для td в each_tr.findAll ("td")] для each_tr в tr_all] , который генерирует список списков для tds_all: [[u'active ', u'Active', u'Эту учетную запись активную и можно использовать. '], [ u'inactive ', u'Inactive', u 'Эта учетная запись неактивна \ n и не должна использоваться для отслеживания финансовой информации.']] Чтобы сгладить это, нужно это [x для y в z для x в y] состав. Но потом я подумал, почему бы не применить эту структуру прямо к критической линии и не сгладить ее?

z - список объектов bs4 (tr_all). В этом «for ... in ...»-construct каждый_tr (a bs4-object) берется из списка «tr_all», а каждый объект-объект генерирует взади «in-in» -конструкцию список всех 'td', по выражению each_tr.findAll ("td"), из которого каждое соответствие «td» изолируется позади «for ... in ...» - loop, и в самом начале этого списка стоит что должно быть затем собрано в конечном списке: текст, выделенный из этого объекта («td.get_text()»). И этот итоговый список будет присвоен td_all.

Результатом этого кода этот список результат:

['active ', 'Active', 'This account is active and may be used.', 'inactive ', 'Inactive', 'This account is inactive\n and should not be used to track financial information.'] 

Два больше элементов отсутствовали в примере из JustMe. Я думаю, Мэри, ты хочешь, чтобы их включили, не так ли?

Смежные вопросы