#python #html #python-3.x #beautifulsoup
Вопрос:
Моя цель здесь-извлечь все содержимое из тегов «td» под colspan. Я только начинаю работать с bs4. До сих пор я могу извлечь все «trs» со страницы, однако я хотел бы получить информацию только в классе info_row с именем Диски. любая помощь с логикой и / или кодом очень ценится.
Это выдержка из HTML
<tbody>
<tr>
<td colspan="100%" class="info_row">Disks</td>
</tr>
<tr>
<td> sda </td>
<td> 123456 </td>
<td> abcdefg </td>
</tr>
<tr>
<td> sdb </td>
<td> 123456 </td>
<td> abcdefg </td>
</tr>
</tbody>
Желаемый результат:
sda 123456 abcdefg
sbd 123456 abcdefg
до сих пор у меня есть следующее:
src = open("my_page.html").read()
soup = BeautifulSoup(src, "html.parser")
tbody = soup.findAll("tbody")
for tr in tbody:
tds = tr.findAll('td')
for td in tds:
print(td.text)
Комментарии:
1. Я изменил код, чтобы проверить, имеет ли тег td определенный класс и текст, упомянутый в вашем вопросе
Ответ №1:
Начальный цикл for находит индекс тега tr , в котором есть тег td class="info_row"
, и текст как Disks
, используя этот индекс, вы можете просто найти индекс следующего тега tr, текст которого вы хотите извлечь, и использовать его в качестве индекса списка, чтобы применить get_text()
метод для извлечения текста внутри тегов:
from bs4 import BeautifulSoup
src = '''<tbody>
<tr>
<td colspan="100%" class="info_row">Disks</td>
</tr>
<tr>
<td> sda </td>
<td> 123456 </td>
<td> abcdefg </td>
</tr>
<tr>
<td> sdb </td>
<td> 123456 </td>
<td> abcdefg </td>
</tr>
</tbody>'''
soup = BeautifulSoup(src, "html.parser")
trs = soup.findAll("tr")
for i in range(len(trs)):
if trs[i].td:
if 'class' in trs[i].td.attrs and trs[i].td.text == 'Disks':
if "info_row" in trs[i].td.attrs['class']:
idx = i
break
print(' '.join(trs[idx 1].get_text(' ').split()))
print(' '.join(trs[idx 2].get_text(' ').split()))
Выход
sda 123456 abcdefg
sdb 123456 abcdefg
Чтобы получить отдельные элементы внутри тегов, вы можете использовать этот код, потому trs[idx 1].get_text(' ').split()
что на самом деле это список:
for item in trs[idx 1].get_text(' ').split():
print(item)
for item in trs[idx 2].get_text(' ').split():
print(item)
Выход
sda
123456
abcdefg
sdb
123456
abcdefg
Комментарии:
1. Это отлично работает и очень легко понять! я получал «AttributeError: объект ‘NoneType’ не имеет атрибута ‘attrs'», но я смог обойти это, добавив блок try/except. Еще раз спасибо
2. один вопрос, если ты не против. можно ли также получить доступ к текстам td по отдельности? например, если бы я просто хотел» sda » или «123456», моя цель-сохранить эти значения в словаре.
3. @mondragonfx Да, безусловно,
trs[idx 1].get_text(' ').split()
это список, и вы можете получить отдельный элемент из этого списка в соответствии с вашими требованиями4. @mondragonfx Я изменил код, чтобы решить проблему «Ошибка атрибута: объект ‘NoneType’ не имеет атрибута ‘attrs'».
Ответ №2:
В этом примере из таблицы выбираются только строки, отличные от»colspan» :
from bs4 import BeautifulSoup
html_doc = """<tbody>
<tr>
<td colspan="100%" class="info_row">Disks</td>
</tr>
<tr>
<td> sda </td>
<td> 123456 </td>
<td> abcdefg </td>
</tr>
<tr>
<td> sdb </td>
<td> 123456 </td>
<td> abcdefg </td>
</tr>
</tbody>"""
soup = BeautifulSoup(html_doc, "html.parser")
for tr in soup.select("tr:not(:has([colspan]))"):
print(*[td.get_text(strip=True) for td in tr.select("td")])
С принтами:
sda 123456 abcdefg
sdb 123456 abcdefg
Или: вы можете выбрать все строки, которые находятся после строки, содержащей ячейку «Диски».:
for tr in soup.select('tr:has(> td:contains("Disks")) ~ tr'):
print(*[td.get_text(strip=True) for td in tr.select("td")])
РЕДАКТИРОВАТЬ: Использование lambda
:
for tr in soup.find(lambda tag: tag.name == "tr" and tag.text.strip() == "Disks").find_next_siblings("tr"):
print(*[td.get_text(strip=True) for td in tr.select("td")])
Комментарии:
1. Спасибо за ваш ответ, похоже, это работа, как и ожидалось. возможно ли, чтобы td:содержит(«Диски») учитывал регистр/слово? у меня есть другие tds на HTML-странице, в которых есть слово «диски», и это, похоже, тоже их печатает. в противном случае это в точку. я действительно ценю это.
2. @mondragonfx, которым вы можете воспользоваться
lambda
, я обновил свой ответ.