【问题标题】:Parsing webpage table with BeautifulSoup4用 BeautifulSoup4 解析网页表格
【发布时间】:2021-08-03 09:00:23
【问题描述】:

所以,我正在尝试使用 BeautifulSoup4 解析网页中的表格,它能够获取网页并解析内容,但是当我继续寻找要放入 pandas 数据框的表格时,我得到了属性错误:“NONETYPE”对象没有属性“Find_all”

我在另一个网页上尝试了相同的过程,它能够正常工作,我只是想弄清楚我在这里做错了什么,一个工作,另一个不工作。

#Imports
import pandas as pd
import numpy as np
from bs4 import BeautifulSoup
import requests

#Load data
url = 'https://gisopendata.siouxfalls.org/datasets/7b0407feca3e4f47bfe54559b9c1dd5d_13/data'

#Get request
web_data = requests.get(url)

#Parse Content
soup = BeautifulSoup(web_data.text, 'lxml')
#print(soup.prettify())


table = soup.find('table', {'class':'table table-striped table-bordered table-hover'})

headers = []

for i in table.find_all('th'):
    title = i.text.strip()
    headers.append(title)

【问题讨论】:

标签: python pandas web-scraping beautifulsoup


【解决方案1】:

每个table 通常有一个theadtbody(可能还有一个tr),您需要先访问它们才能在find_all 上使用th

如果你检查源页面上的 html 确实是这样,你有

<table class="table table-striped table-bordered table-hover" role="grid">
    <thead role="rowgroup">
      <tr role="row">
          <th id="ember123" class="ember-view">

所以在table标签之后,你必须访问thead标签,然后是tr标签,然后你可以使用find_all来收集所有ths

你可以试试看这样的方法是否有效:

for i in table.find('thead').find('tr').find_all('th'):
    title = i.text.strip()
    headers.append(title)

这里的赠品是仔细观察源页面中的数据,AttributeError 清楚地告诉您BeautifulSoup 找不到带有您指定说明的标签,因此NoneType 参考。

【讨论】:

    【解决方案2】:

    数据是从 POST 请求中动态提取的。但是,该页面会显示您可以使用的 API 端点。以下是您可以向该 API 发出请求并从响应中生成 dataframe 的一种方式。

    最简单的就是使用指定的json作为输出:

    import requests
    import pandas as pd
    
    r = requests.get('https://gis2.siouxfalls.org/arcgis/rest/services/Data/Community/MapServer/13/query?where=1%3D1&outFields=*&outSR=4326&f=json').json()
    print(pd.DataFrame([i['attributes'] for i in r['features']]))
    

    否则,

    import requests
    from bs4 import BeautifulSoup as bs
    import pandas as pd
    
    r = requests.get('https://gis2.siouxfalls.org/arcgis/rest/services/Data/Community/MapServer/13/query?outFields=*&where=1%3D1')
    soup = bs(r.content, 'lxml')
    headers = ['OBJECTID', 'Id', 'DESCRIP', 'LOCATION', 'YEARBUILT', 'LOCAL_REGISTER', 'LOCAL_REG_DATE', 
               'NATIONAL_REGISTER', 'NATIONAL_REG_DATE', 'GlobalID', 'Shape_Length', 'Shape_Area']
    
    data = {}
    
    for header in headers:
        if header == 'OBJECTID':      
            data[header] = [i.next_sibling.next_sibling.text for i in soup.select(f'i:contains("{header}")')]
        else:
            data[header] = [i.next_sibling for i in soup.select(f'i:contains("{header}")')]
    
    df = pd.DataFrame(zip(*data.values()), columns = headers)
    
    print(df)
    

    【讨论】:

      猜你喜欢
      • 2018-08-28
      • 2018-12-18
      • 1970-01-01
      • 2019-03-30
      • 2020-02-25
      • 2020-04-05
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      相关资源
      最近更新 更多