Как использовать Python CSV для записи нескольких строк таблицы Beautifulsoup только для двух конкретных столбцов? - PullRequest
0 голосов
/ 10 апреля 2019

Я хочу использовать beautifulsoup для очистки HTML, чтобы вытащить только два столбца из каждой строки в одной таблице. Тем не менее, каждая строка «tr» имеет 10 ячеек «td», и я хочу только ячейки «td» [1] и [8] из каждой строки. Какой самый питонный способ сделать это?

Из моего ввода ниже у меня есть одна таблица, одно тело, три строки и 10 ячеек на строку.

Input

<table id ="tblMain">
 <tbody>
  <tr>
   <td "text"</td>
   <td "data1"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "data2"</td>
   <td "text"</td>
  <tr>
   <td "text"</td>
   <td "data1"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "data2"</td>
   <td "text"</td>
  <tr>
   <td "text"</td>
   <td "data1"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "text"</td>
   <td "data2"</td>
   <td "text"</td>

Вещи, которые я пробовал

Я понимаю, как использовать индекс ячеек для циклического прохождения и получения «td» в [1] и [8]. Тем не менее, я все путаюсь, когда пытаюсь получить эти данные в одной строке, записанной обратно в CSV.

table = soup.find('table', {'id':'tblMain'} )
table_body = table.find('tbody')
rows = table_body.findAll('tr')
data1_columns = []
data2_columns = []
for row in rows[1:]:
    data1 = row.findAll('td')[1]
    data1_columns.append(data1.text)
    data2 = row.findAll('td')[8]
    data2_columns.append(data2.text)

Это мой текущий код , который находит таблицу, строки и все ячейки "td" и печатает их правильно в .csv. Однако вместо записи всех десяти ячеек "td" в строке обратно в строку csv я просто хочу взять "td" [1] и "td" [8].

html = browser.page_source
soup = BeautifulSoup(html, 'html.parser')
table = soup.find('table', {'id':'tblMain'} )
table_body = table.find('tbody')
rows = table_body.findAll('tr')
filename = '%s.csv' % reportname
with open(filename, "wt+", newline="") as f:
    writer = csv.writer(f)
    for row in rows:
        csv_row = []
        for cell in row.findAll("td"):
            csv_row.append(cell.get_text())
        writer.writerow(csv_row)

Ожидаемые результаты

Я хочу иметь возможность записать «td» [1] и «td» [8] обратно в мой csv_row, чтобы записать каждый список обратно в csv writer.writerow.

Запись строки обратно в csv_row, которая затем записывает в мой файл csv:

['data1', 'data2']
['data1', 'data2']
['data1', 'data2']

Ответы [ 3 ]

1 голос
/ 11 апреля 2019

Ты почти сделал это

for row in rows:
    row = row.findAll("td")
    csv_row = [row[1].get_text(), row[8].get_text()]
    writer.writerow(csv_row)

Полный код

html ='''<table id ="tblMain">
 <tbody>
  <tr>
   <td>text</td>
   <td>data1</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>data2</td>
   <td>text</td>
  <tr>
   <td>text</td>
   <td>data1</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>data2</td>
   <td>text</td>
  <tr>
   <td>text</td>
   <td>data1</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>text</td>
   <td>data2</td>
   <td>text</td>
'''

from bs4 import BeautifulSoup
import csv

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

table = soup.find('table', {'id':'tblMain'} )
table_body = table.find('tbody')

rows = table_body.findAll('tr')

reportname = 'output'
filename = '%s.csv' % reportname

with open(filename, "wt+", newline="") as f:
    writer = csv.writer(f)
    for row in rows:
        row = row.findAll("td")
        csv_row = [row[1].get_text(), row[8].get_text()]
        writer.writerow(csv_row)
0 голосов
/ 11 апреля 2019

Всякий раз, когда мне нужно вытащить таблицу с тегом <table>, я позволяю Пандам делать всю работу за меня, а затем просто манипулирую кадром данных, который он возвращает при необходимости.Вот что я бы сделал здесь:

html = '''<table id ="tblMain">
 <tbody>
  <tr>
   <td> text</td>
   <td> data1</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> data2</td>
   <td> text</td>
  <tr>
   <td> text</td>
   <td> data1</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> data2</td>
   <td> text</td>
  <tr>
   <td> text</td>
   <td> data1</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> text</td>
   <td> data2</td>
   <td> text</td>'''


import pandas as pd

# .read_html() returns a list of dataframes
tables = pd.read_html(html)[0]

# we want the dataframe from that list in position [0]
df = tables[0]

# Use .iloc to say I want all the rows, and columns 1, 8
df = df.iloc[:,[1,8]]

# Write the dataframe to file
df.to_csv('path.filename.csv', index=False)
0 голосов
/ 11 апреля 2019

Вы должны иметь возможность использовать псевдокласс n-го типа css selector

from bs4 import BeautifulSoup as bs
import pandas as pd
html = 'actualHTML'
soup = bs(html, 'lxml')
results = []
for row in soup.select('#tblMain tr'):
    out_row = [item.text.strip() for item in row.select('td:nth-of-type(2), td:nth-of-type(9)')]
    results.append(out_row)
df = pd.DataFrame(results)
print(df)
df.to_csv(r'C:\Users\User\Desktop\data.csv', sep=',', encoding='utf-8-sig',index = False )
...