【问题标题】:Python Returning An Empty List Using Beautiful Soup HTML ParsingPython 使用 Beautiful Soup HTML 解析返回一个空列表
【发布时间】:2020-05-18 15:17:35
【问题描述】:

我目前正在从事一个涉及网页抓取房地产网站的项目(用于教育目的)。我正在从房屋列表中获取数据,例如地址、价格、卧室等。

在构建和测试打印功能(它成功!)之后,我现在正在为列表中的每个数据点构建一个字典。我将该字典存储在一个列表中,以便最终使用 Pandas 创建一个表并发送到 CSV。

这是我的问题。我的列表显示一个没有错误的空字典。请注意,我已经成功抓取了数据,并且在使用打印功能时看到了数据。现在,在将每个数据点添加到字典并将其放入列表后,它什么也不显示。这是我的代码:

import requests
from bs4 import BeautifulSoup

r=requests.get("https://www.century21.com/real-estate/colorado-springs-co/LCCOCOLORADOSPRINGS/")
c=r.content

soup=BeautifulSoup(c,"html.parser")

all=soup.find_all("div", {"class":"infinite-item"})
all[0].find("a",{"class":"listing-price"}).text.replace("\n","").replace(" ","")

l=[]
for item in all:
    d={} 
    try: 
        d["Price"]=item.find("a",{"class":"listing-price"}.text.replace("\n","").replace(" ",""))
        d["Address"]=item.find("div",{"class":"property-address"}).text.replace("\n","").replace(" ","")
        d["City"]=item.find_all("div",{"class":"property-city"})[0].text.replace("\n","").replace(" ","")
        try: 
            d["Beds"]=item.find("div",{"class":"property-beds"}).find("strong").text
        except: 
            d["Beds"]=None
        try: 
            d["Baths"]=item.find("div",{"class":"property-baths"}).find("strong").text
        except: 
            d["Baths"]=None
        try: 
            d["Area"]=item.find("div",{"class":"property-sqft"}).find("strong").text
        except: 
             d["Area"]=None
    except: 
        pass
    l.append(d)

当我调用l(包含我的字典的列表)时 - 这就是我得到的:

[{},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {},
 {}]

我正在使用 Python 3.8.2 和 Beautiful Soup 4。任何想法或帮助将不胜感激。谢谢!

【问题讨论】:

  • 考虑删除您的Pokemon exceptions,它会不加选择地抑制错误并让人难以分辨出什么是失败的。
  • 您的代码每次都进入 except 块,因此在第一次尝试时看起来像是出错了。你在这里有很多尝试,有更好的方法来处理这个
  • 如果你取出所有的 try 块,你会得到错误AttributeError: 'dict' object has no attribute 'text'
  • 存在例外,因为我会收到大量 attributeError: 'NoneType' 错误。一些房地产列表缺少数据点并且不包含卧室数量的数据,因此我添加了例外以处理该问题并在没有相关信息时显示 None。
  • 那么除了特定的错误:except AttributeError:。否则,您将抑制任何和所有错误,包括您没有预料到的错误,这些错误会告诉您如何解决问题。或者写一个条件if foo is None:

标签: python python-3.x list dictionary beautifulsoup


【解决方案1】:

这可以更简洁地执行您想要的操作,并且更 Pythonic(使用嵌套列表理解):

import requests
from bs4 import BeautifulSoup

r = requests.get("https://www.century21.com/real-estate/colorado-springs-co/LCCOCOLORADOSPRINGS/")
c = r.content

soup = BeautifulSoup(c, "html.parser")

css_classes = [
    "listing-price",
    "property-address",
    "property-city",
    "property-beds",
    "property-baths",
    "property-sqft",
]

pl = [{css_class.split('-')[1]: item.find(class_=css_class).text.strip() # this shouldn't error if not found
       for css_class in css_classes} # find each class in the class list
       for item in soup.find_all('div', class_='property-card-primary-info')] # find each property card div

print(pl)

输出:

[{'address': '512 Silver Oak Grove',
  'baths': '6 baths',
  'beds': '4 beds',
  'city': 'Colorado Springs CO 80906',
  'price': '$1,595,000',
  'sqft': '6,958 sq. ft'},
 {'address': '8910 Edgefield Drive',
  'baths': '5 baths',
  'beds': '5 beds',
  'city': 'Colorado Springs CO 80920',
  'price': '$499,900',
  'sqft': '4,557 sq. ft'},
 {'address': '135 Mayhurst Avenue',
  'baths': '3 baths',
  'beds': '3 beds',
  'city': 'Colorado Springs CO 80906',
  'price': '$420,000',
  'sqft': '1,889 sq. ft'},
 {'address': '7925 Bard Court',
  'baths': '4 baths',
  'beds': '5 beds',
  'city': 'Colorado Springs CO 80920',
  'price': '$405,000',
  'sqft': '3,077 sq. ft'},
 {'address': '7641 N Sioux Circle',
  'baths': '3 baths',
  'beds': '4 beds',
  'city': 'Colorado Springs CO 80915',
  'price': '$389,900',
  'sqft': '3,384 sq. ft'},
 ...
]

【讨论】:

  • 谢谢!这是一个很大的帮助,尤其是对于仍在学习 Python 的人。 :)
  • 希望它适合您!这种方法不那么直接/明显,因为它使用嵌套列表理解,但是一旦你掌握了这些,它们就会非常强大。它还遵循 DRY 原则(不要重复自己),这样做的最大优点是您可以通过修改 css_classes 列表来添加/删除搜索的项目(但设置方式必须遵循<item>-<name> 格式,你可以用字典来改进它{<css_class>: <output_label>}
【解决方案2】:

您应该使用函数来完成重复性工作。这将使您的代码更清晰。 我已经管理了这段代码,它正在工作:

import requests
from bs4 import BeautifulSoup

def find_div_and_get_value(soup, html_balise, attributes):
    return soup.find(html_balise, attrs=attributes).text.replace("\n","").strip()

def find_div_and_get_value2(soup, html_balise, attributes):
    return soup.find(html_balise, attrs=attributes).find('strong').text.replace("\n","").strip()


r=requests.get("https://www.century21.com/real-estate/colorado-springs-co/LCCOCOLORADOSPRINGS/")
c=r.content
soup = BeautifulSoup(c,"html.parser")
houses = soup.findAll("div", {"class":"infinite-item"})

l=[]
for house in houses:
    try:
        d = {}
        d["Price"] = find_div_and_get_value(house, 'a', {"class": "listing-price"})
        d["Address"] = find_div_and_get_value(house, 'div', {"class": "property-address"})
        d["City"] = find_div_and_get_value(house, 'div', {"class":"property-city"})
        d["Beds"] = find_div_and_get_value2(house, 'div', {"class":"property-beds"})
        d["Baths"] = find_div_and_get_value2(house, 'div', {"class":"property-baths"})
        d["Area"] = find_div_and_get_value2(house, 'div', {"class":"property-sqft"})
        l.append(d)
    except:
        break

for house in l:
    print(house)

【讨论】:

  • 谢谢!这确实使代码更清晰,我真的很喜欢有助于格式化并减少重复性的函数。再次感谢!编辑:漏了一个字。
猜你喜欢
  • 2013-03-27
  • 2020-07-27
  • 1970-01-01
  • 1970-01-01
  • 2011-09-27
  • 2014-12-16
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
相关资源
最近更新 更多