Как преобразовать таблицу HTML в массив в python
У меня есть html-документ, и я хочу вытащить таблицы из этого документа и вернуть их как массивы. Я представляю две функции, которые обнаруживают все html-таблицы в документе, а вторую, которые превращают html-таблицы в двумерные массивы.
Что-то вроде этого:
htmltables = get_tables(htmldocument)
for table in htmltables:
array=make_array(table)
Там 2 уловы:
1. Таблицы номеров меняются день ото дня
2. В таблицах есть все виды сверхъестественного форматирования, например, смелые и мигающие теги, случайным образом вбрасываемые.
Спасибо!
Ответы
Ответ 1
Pandas может извлекать все таблицы в вашем html в список фреймов данных прямо из коробки, что избавляет вас от необходимости самостоятельно проанализировать страницу (изобретать колесо). A DataFrame является мощным типом двумерного массива.
Я рекомендую продолжать работать с данными через Pandas, так как это отличный инструмент, но вы также можете конвертировать в другие форматы (список, словарь, файл csv и т.д.).
Пример
"""Extract all tables from an html file, printing and saving each to csv file."""
import pandas as pd
df_list = pd.read_html('my_file.html')
for i, df in enumerate(df_list):
print df
df.to_csv('table {}.csv'.format(i))
Получение содержимого html непосредственно из Интернета, а не из файла, потребует лишь незначительной модификации:
import requests
html = requests.get('my_url').content
df_list = pd.read_html(html)
Ответ 2
Используйте BeautifulSoup (рекомендую 3.0.8
). Поиск всех таблиц тривиален:
import BeautifulSoup
def get_tables(htmldoc):
soup = BeautifulSoup.BeautifulSoup(htmldoc)
return soup.findAll('table')
Однако, в Python, array является одномерным и ограничен хорошими элементарными типами как элементы (целые числа, поплавки, эти элементарные). Таким образом, нет способа сжать таблицу HTML в Python array
.
Может быть, вы имеете в виду Python list
вместо этого? Это также одномерное, но все может быть элементом, поэтому у вас может быть список списков (по моему мнению, один подсчет за тег tr
, содержащий один элемент в теге td
).
Это даст:
def makelist(table):
result = []
allrows = table.findAll('tr')
for row in allrows:
result.append([])
allcols = row.findAll('td')
for col in allcols:
thestrings = [unicode(s) for s in col.findAll(text=True)]
thetext = ''.join(thestrings)
result[-1].append(thetext)
return result
Это может быть совсем не совсем то, что вы хотите (не пропускает HTML-комментарии, элементы подписок - строки юникода, а не байтовые строки и т.д.), но его нужно легко настроить.
Ответ 3
A +1 для вопросителя, а другой - к богу Питона.
Хотелось попробовать этот пример с помощью селекторов lxml и CSS.
Да, это в основном то же, что и пример Alex:
import lxml.html
markup = lxml.html.fromstring('''<html><body>\
<table width="600">
<tr>
<td width="50%">0,0,0</td>
<td width="50%">0,0,1</td>
</tr>
<tr>
<td>0,1,0</td>
<td>0,1,1</td>
</tr>
</table>
<table>
<tr>
<td>1,0,0</td>
<td>1,<blink>0,</blink>1</td>
<td>1,0,2</td>
<td><bold>1</bold>,0,3</td>
</tr>
</table>
</body></html>''')
tbl = []
rows = markup.cssselect("tr")
for row in rows:
tbl.append(list())
for td in row.cssselect("td"):
tbl[-1].append(unicode(td.text_content()))
pprint(tbl)
#[[u'0,0,0', u'0,0,1'],
# [u'0,1,0', u'0,1,1'],
# [u'1,0,0', u'1,0,1', u'1,0,2', u'1,0,3']]