代码之家  ›  专栏  ›  技术社区  ›  tailor

python:将带有UNNESTED div标记的html文档解析为数据帧(使用beautifulsoup)

  •  1
  • tailor  · 技术社区  · 2 年前

    长期用户,但从未问过我自己的问题。

    我想使用python将一个表从html文档解析为数据帧。这个表不是html表,我认为它是javascript创建的html,只是使用了一堆带有奇怪名称类的div来创建格式和布局。

    数据是按工作区域排序的工人及其工作时间。问题是,div没有嵌套,因此我无法轻松地为每个工人分配他们的工作区域。我正在使用美容组。

    以下是一个简化的示例:

    <html>
    <body>
    <div class="workarea">construction
    </div>
      <div class="name">Anna
      </div>
      <div class="Muell">w23f84md2o
      </div>
      <div class="time">8:23
      </div>
        <div class="name">Tom
      </div>
      <div class="Muell">w23f84md2o
      </div>
      <div class="time">10:20
      </div>
     <div class="workarea">cleaning
    </div>
      <div class="name">Max
      </div>
      <div class="Muell">w23f84md2o
      </div>
      <div class="time">9:30
      </div>
    </body>
    </html>
    

    以下是我想要的数据帧:

    工作区 名称 时间
    建设 安娜 8:23
    建设 汤姆 10:20
    打扫 马克斯 9:30

    注意:实际数据有数千个div用于格式化和布局,这就是为什么我想使用适当的解析器,而不仅仅是将文档逐行读取到python中并自己进行解析。

    我没走多远:

    ### read html with bs4
    with open("testdoc1.html") as fp:
         soup=BeautifulSoup(fp,"html.parser")
    
    wa = soup.find_all("div",class="workarea")
    ## here I wanted to add a for loop through wa, but wa doesnt actually contain the info
    

    我无法循环通过 wa 以获取详细信息,因为它只包含构造和清理div,两者之间没有任何内容。

    有没有一种解决方案可以逐行解析,但实际上是逐个div?

    我能使find_all找到所有具有as类的div吗 工作区域、时间或名称 ? 并按阅读顺序保存?

    我知道已经有很多关于美化组和解析html文档的stackoverflow问题,但我真的找不到解决方案,因为原始表实际上不仅仅是一个表,而且遗憾的是,html中没有保留层次结构。

    非常感谢你的帮助!如有任何提示,不胜感激!

    1 回复  |  直到 2 年前
        1
  •  2
  •   Andrej Kesely    2 年前

    尝试

    import pandas as pd
    from bs4 import BeautifulSoup
    
    html_text = """\
    <html>
    <body>
    <div class="workarea">construction
    </div>
      <div class="name">Anna
      </div>
      <div class="Muell">w23f84md2o
      </div>
      <div class="time">8:23
      </div>
        <div class="name">Tom
      </div>
      <div class="Muell">w23f84md2o
      </div>
      <div class="time">10:20
      </div>
     <div class="workarea">cleaning
    </div>
      <div class="name">Max
      </div>
      <div class="Muell">w23f84md2o
      </div>
      <div class="time">9:30
      </div>
    </body>
    </html>"""
    
    soup = BeautifulSoup(html_text, "html.parser")
    
    data = []
    for name in soup.select(".name"):
        workarea = name.find_previous(class_="workarea")
        data.append(
            {
                "workarea": workarea.text.strip(),
                "name": name.text.strip(),
                "time": name.find_next(class_="time").text.strip(),
            }
        )
    
    df = pd.DataFrame(data)
    print(df)
    

    打印:

           workarea  name   time
    0  construction  Anna   8:23
    1  construction   Tom  10:20
    2      cleaning   Max   9:30