python #web-scraping #beautifulsoup
#python #веб-очистка #beautifulsoup
Вопрос:
Мне нужно написать скрипт, который суммирует значения из каждого столбца (каждый столбец — отдельный день). Кроме того, я хочу разделить значения на запланированные (синий цвет) и незапланированные (красный цвет). В HTML-коде я обнаружил, что незапланированные значения имеют имя класса как «colBox cal-unplanned», а запланированные значения имеют имя класса как «colBox cal-planned».
Мой код:
import pandas as pd
import requests
from bs4 import BeautifulSoup
URL = 'http://gpi.tge.pl/zestawienie-ubytkow'
page = requests.get(URL)
soup = BeautifulSoup(page.content, 'html.parser')
# Here I tried to convert the data into a dataframe, but then you don't know which values are planned and which are unplanned
table = soup.find_all('table')
df = pd.read_html(str(table),header=2)[0]
# Here the values are correct, but they are collected from the whole table
sum = 0
for tr in soup.find_all('td', class_='colBox cal-unplanned'):
val = int(tr.text)
sum = val
print(sum)
for tr in soup.find_all('td', class_='colBox cal-planned'):
print(tr.text)
И вот мой вопрос. Как я могу выбирать значения из каждого столбца отдельно
Комментарии:
1. Итак, вы хотите получить сумму синего, а затем сумму красного для каждого столбца?
Ответ №1:
Не уверен, что есть лучший способ, но вы можете выполнить итерацию по таблице и сохранить запланированные и незапланированные в отдельные значения под ключом имени столбца. Затем суммируйте эти значения, а затем используйте этот словарь для преобразования в фрейм данных.
Но вы правы, вы теряете этот атрибут при его разборе .read_html()
.
Это работает, но не уверен, насколько это надежно для вашей ситуации.
import pandas as pd
import requests
from bs4 import BeautifulSoup
URL = 'http://gpi.tge.pl/zestawienie-ubytkow'
page = requests.get(URL)
soup = BeautifulSoup(page.content, 'html.parser')
table = soup.find('table')
data = {}
headers = [x.text.strip() for x in table.find_all('tr')[2].find_all('th')]
for header in headers:
data[header] = {'planned':[],
'unplanned':[]}
rows = table.find_all('tr')[3:]
for row in rows:
tds = row.find_all('td')[3:len(headers) 3]
for idx, value in enumerate(tds):
if value.has_attr("class"):
if 'cal-planned' in value['class']:
data[headers[idx]]['planned'].append(int(value.text.strip()))
elif 'cal-unplanned' in value['class']:
data[headers[idx]]['unplanned'].append(int(value.text.strip()))
sum_of_columns = {}
for col, values in data.items():
planned_sum = sum(values['planned'])
unplanned_sum = sum(values['unplanned'])
sum_of_columns[col] = {'planned':planned_sum,
'unplanned':unplanned_sum}
df = pd.DataFrame.from_dict(sum_of_columns,orient="columns" )
Вывод:
print(df.to_string())
Cz 14 Pt 15 So 16 N 17 Pn 18 Wt 19 Śr 20 Cz 21 Pt 22 So 23 N 24 Pn 25 Wt 26 Śr 27
planned 8808 8301 7750 6863 6069 6199 6069 5627 5627 5695 5695 5235 5235 5376
unplanned 2320 2020 2313 2783 950 950 950 950 950 950 950 910 910 910
Комментарии:
1. Это отлично работает. Большое вам спасибо за ваш ответ
Ответ №2:
Итак, если я правильно понял, вы хотите работать с отдельными столбцами вашего фрейма данных? Вы можете попытаться использовать это df['column_name']
для доступа к определенному столбцу df, а затем отфильтровать этот столбец для значения, которое вы хотите использовать, например
df['column_name'] == filter_value
Но опять же, я не уверен, что понимаю вашу проблему.
Это помогло мне справиться с выбором значения фрейма данных.
Комментарии:
1. Это не решает мою проблему с разделением значений на запланированные значения (те, которые имеют синий фон на странице) и незапланированные значения (те, которые имеют красный фон на странице). После создания фрейма данных я теряю возможность разделения. Мне нужно разделить значения с помощью html-тегов — colBox cal-незапланированный и colBox cal-запланированный
Ответ №3:
Не уверен, обязательно ли это проблема для bs4, потому что я думаю, что информация уже находится в DataFrame в виде суммы.
Как получить доступ?
Взгляните на tail()
свой фрейм данных:
df.tail(3)
Пример
import pandas as pd
URL = 'http://gpi.tge.pl/zestawienie-ubytkow'
df = pd.read_html(URL,header=2)[0]
df.tail(3).iloc[:,2:]
Вывод
Moc Osiągalna (MW) Cz 14 Pt 15 So 16 N 17 Pn 18 Wt 19 Śr 20 Cz 21 Pt 22 So 23 N 24 Pn 25 Wt 26 Śr 27
219 Planowane 11279 10604 8391 6863 6069 6432 6069 5627 5627 5695 5695 5235 5235 5376
220 Nieplanowane 5520 5620 2313 2783 950 950 950 950 950 950 950 910 910 910
221 Łącznie ubytki 16799 16224 10704 9646 7019 7382 7019 6577 6577 6645 6645 6145 6145 6286
Комментарии:
1. Спасибо за ваш ответ. К сожалению, сводка в таблице отличается от реальных результатов. Если мы посчитаем это вручную, результаты будут меньше
2. Это была бы альтернатива, и, надеюсь, отдельные значения, по крайней мере, будут правильными 😉 Такая информация должна быть включена в вопрос в следующий раз, это было бы здорово.
3. Вы правы. Я запомню это в следующий раз