【问题标题】:How to read specific html lines with python (bs4)如何使用 python (bs4) 读取特定的 html 行
【发布时间】:2019-02-06 10:40:09
【问题描述】:

首先我是 python 和 beautifulsoup 的新手。

我无权访问在 html 代码中链接的 css、js 文件。我也无法修改 html 页面。
我在 linux 上,并且正在使用 python3,如果这很重要的话。

我有以下页面:https://pastebin.com/VqRRe02P
托管的实际 html 代码未格式化,我通过在线 html 代码格式化程序运行代码。因此,我将在下面说明的行不会 100% 正确。

这是我目前正在使用的代码(并非所有功能都已实现):

import requests
import csv
from bs4 import BeautifulSoup, element
from operator import itemgetter

# ermöglicht schnelles Wechseln des Hosts (IP über die, das Interface lokal erreichbar ist)
a = 'http://192.168.68.128' # IP der Wärmepumpe
b = 'http://localhost' # für Entwicklungszwecke

# beziehe Daten vom Host
data = requests.get(b)

# lade Daten in BeautifulSoup
soup = BeautifulSoup(data.text, 'html.parser')

# Liste 'data' wird erstellt
data = []
var_name = []

# Alle Tabellen werden gesucht und in die Variable 'row' gespeichert
    for tr in soup.table.find_all('tr'):
        row = [td.text for td in tr.find_all('td')]
        var_name.append(row[0])
        if not row[1].startswith('\n') and row[2] in ['°C', 'bar']: # hier werden Filter angewendet, um nur relevante Daten zu speichern
        data.append(itemgetter(1)(row)) # die gefilterten Daten werden in die Liste 'data' gespeichert

print(var_name[2])


# die Strings von 'data' werden in den Datentyp float umgewandelt
data = list(map(float, data))

# hier werden die Unter- und Obergrenze festgelegt
 min_value = 0
max_value = 100

# Funktion überprüft, ob ein Wert die Untergrenze überschreitet
def check1():
    if data[1] < min_value:
        return(1)
    else:
        return(0)

    # Funktion überprüft, ob ein Wert die Obergrenze überschreitet
    def check2():
    if data[1] > max_value:
        return(1)
    else:
        return(0)

# Funktion überprüft, ob ein Fehler vorliegt
def check():
    if check1() + check2() is 2:
        return('Fehlercode: 2')
    if check1() + check2() is 1:
        return('Fehlercode: 1')
    else:
        return('OK')

if check() in 'Fehlercode: 2':
print('Email mit Fehlercode 2 senden')  # Platzhalter für Email Skript ausführen
if check() in 'Fehlercode: 1':
    print('Email mit Fehlercode 1 senden') # Platzhalter für Email Skript ausführen

 # Daten werden in eine CSV Datei namens 'auslesen.csv' gespeichert
with open('auslesen.csv', 'w') as auslesen:
    writer = csv.writer(auslesen)
    writer.writerow(data)
    auslesen.close()

/* 我需要从以下行中的 td 元素中读取数据并将它们保存到变量中,然后将它们输出到文本文件中,例如“var1、var2、var3、..”。 这些线路是 158、204、264、339、557、579、920、937、954、1023、1042、1114、1168。 */

我现在可以检查列表数据的元素是否超过了最小值或最大值。
问题不在于所有值都以度(°C)为单位,有些以压力(bar)为单位,因此我还需要获取 bar 的最小值或最大值。我该怎么做?
而且我还想弄清楚哪个值完全超过了最小值或最大值,并包括它的名称和度数或条形(名称在列表 var_name 中找到,但索引不一样,因为列表行/数据中的一些数据获取过滤。还尝试删除 document.write(); 以仅使用 .text.strip() 获取实际名称不起作用。 不过需要过滤,否则我无法将字符串转换为浮点数。
例如,如果我们说“Aussentemperatur”(html 代码第 158 行)是 200.0 而不是 1.4,则希望输出到 csv 文件中的是:
Aussentemperatur, 200, °C
如果有更多的值超出,请保持输出。
由于我不知道盐水热泵的行为如何,因此在构建 html 页面时,我希望它会写一些字符串。在这种情况下,我还想输出给定的字符串:
Aussentemperatur, unknownstring, °C

编辑:我将代码编辑为当前状态并添加了一个新段落

【问题讨论】:

  • 如果线条不一定准确,也许提供预期值? html中有很多错误。这是从源代码完全复制(格式化除外)吗?上面的 td 元素集合会发生什么?
  • 是的,这是完全复制的(除了我提到的格式)。期望值是动态的,而不是静态的。这是来自公司dimplex的盐水热泵。您可以检查它的网络界面上的值(我链接的 html 代码)。我想用 python 读取这些值。
  • 你上面的代码有什么问题?
  • 它输出所有 td 元素,而我只想要特定行中 td 元素的值。例如,第 158 行中的第一个值是 1.4(摄氏度),这个值一直在变化,因为我们想随时知道准确的温度
  • 我不认为 bs4 支持像 nth-of-type 这样的伪选择器,因为我会使用它来按数字定位行。您能否在循环中使用计数器来代替适当的 trs。

标签: javascript python html web-scraping beautifulsoup


【解决方案1】:

您可以根据是否是包含°Cbar 条目的正确格式条目来决定要包含哪些行。可以使用正则表达式从脚本文本中提取传感器类型。

from collections import defaultdict
from bs4 import BeautifulSoup
import csv
import re

with open('index.html') as f_html:
    html = f_html.read()

soup = BeautifulSoup(html, "html.parser")
readings = defaultdict(list)    # Hold per sensor readings in a dictionary

with open('output.csv', 'w', newline='') as f_output:
    csv_output = csv.writer(f_output)
    csv_output.writerow(['Sensor', 'Value', 'Unit'])

    for tr in soup.table.find_all('tr'):
        row = [td.text for td in tr.find_all('td')]

        if not row[1].startswith('\n') and row[2] in ['°C', 'bar']:
            sensor = re.search(r'\((.*?)\)', row[0]).group(1)   # Extract sensor name from script text
            value = float(row[1])
            unit = row[2]

            readings[sensor].append(value)
            csv_output.writerow([sensor, value, unit])

for sensor in sorted(readings):
    data = readings[sensor]
    print(f'{sensor}:\n  Min {min(data)}, Max {max(data)}, {data}')

Python CSV library 可用于轻松地将格式正确的数据行写入文件。

这将为您提供一个总结如下的 CSV 文件:

Sensor,Value,Unit
Aussentemperatur,1.4,°C
Vorlauftemperatur,28.0,°C
Vorlauftemperatur,28.0,°C
Vorlauftemperatur,27.1,°C
Vorlauftemperatur,28.0,°C
Vorlauftemperatur,0.0,°C
Ruecklauftemperatur,27.1,°C
Ruecklauftemperatur,27.1,°C
Ruecklauftemperatur,28.0,°C
Ruecklauftemperatur,27.1,°C
Ruecklaufsolltemperatur,18.0,°C
Temperatur,0.0,°C
Kollektortemperatur,28.3,°C
MiniTempGKZwei,0.0,°C
Temperatur,16.3,°C
Temperatur,-999.9,°C
Solltemperatur,25.8,°C
MiniTempGKDrei,0.0,°C
Temperatur,35.1,°C
Temperatur,28.3,°C
Temperatur,0.0,°C
Solltemperatur,25.8,°C
Abtauendefuehler,17.6,°C
TempSpeicherReg,35.1,°C
TempSpeicherReg,28.3,°C
TempSpeicherReg,0.0,°C
RLTempKp,0.0,°C
VlTempKp,0.0,°C
Heissgastemperatur,0.0,°C
Raumtemperatur,35.1,°C
Raumtemperatur,28.3,°C
Raumtemperatur,0.0,°C
Raumtemperatur,0.0,°C
Raumtemperatur,0.0,°C
Temperatur,41.6,°C
Warmwasser,45.0,°C
Temperatur,0.0,°C
Wuelleneintritt,16.3,°C
Wuellenaustritt,17.6,°C
Niederdrucksensor,9.6,bar
Vorlauftemperatur,0.0,°C

defaultdict(list) 可用于为每个传感器创建所有传感器读数的列表。然后,这可用于显示所有值,并显示为每个传感器找到的最小值和最大值。例如,输出将是:

Abtauendefuehler:
  Min 17.6, Max 17.6, [17.6]
Aussentemperatur:
  Min 1.4, Max 1.4, [1.4]
Heissgastemperatur:
  Min 0.0, Max 0.0, [0.0]
Kollektortemperatur:
  Min 28.3, Max 28.3, [28.3]
MiniTempGKDrei:
  Min 0.0, Max 0.0, [0.0]
MiniTempGKZwei:
  Min 0.0, Max 0.0, [0.0]
Niederdrucksensor:
  Min 9.6, Max 9.6, [9.6]
RLTempKp:
  Min 0.0, Max 0.0, [0.0]
Raumtemperatur:
  Min 0.0, Max 35.1, [35.1, 28.3, 0.0, 0.0, 0.0]
Ruecklaufsolltemperatur:
  Min 18.0, Max 18.0, [18.0]
Ruecklauftemperatur:
  Min 27.1, Max 28.0, [27.1, 27.1, 28.0, 27.1]
Solltemperatur:
  Min 25.8, Max 25.8, [25.8, 25.8]
TempSpeicherReg:
  Min 0.0, Max 35.1, [35.1, 28.3, 0.0]
Temperatur:
  Min -999.9, Max 41.6, [0.0, 16.3, -999.9, 35.1, 28.3, 0.0, 41.6, 0.0]
VlTempKp:
  Min 0.0, Max 0.0, [0.0]
Vorlauftemperatur:
  Min 0.0, Max 28.0, [28.0, 28.0, 27.1, 28.0, 0.0, 0.0]
Warmwasser:
  Min 45.0, Max 45.0, [45.0]
Wuellenaustritt:
  Min 17.6, Max 17.6, [17.6]
Wuelleneintritt:
  Min 16.3, Max 16.3, [16.3]

查看此输出,这意味着您可能需要根据每个传感器的值过滤最小值和最大值。

如果您不想处理0-100 范围之外的值,请更改为使用以下行:

        if 0 <= value <= 100:
            readings[sensor].append(value)
            csv_output.writerow([sensor, value, unit])

【讨论】:

  • 我已经更新了答案以显示如何添加传感器类型并保留每个传感器信息。完成后不要忘记单击向上/向下按钮下方的灰色勾号以选择答案作为接受的解决方案。
猜你喜欢
  • 1970-01-01
  • 2015-01-29
  • 1970-01-01
  • 2020-02-23
  • 2018-12-03
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多