#python-3.x #pandas #numpy #beautifulsoup
#python-3.x #pandas #numpy #beautifulsoup
Вопрос:
Я могу собирать данные с нескольких веб-страниц на веб-сайте с помощью BeautifulSoup, и я использую pandas для создания таблицы данных. Проблема в том, что я не могу получить все массивы одинаковой длины, и я получаю:
Ошибка значения: все массивы должны быть одинаковой длины
Вот код, который я пробовал:
import requests
from bs4 import BeautifulSoup
import numpy as np
import pandas as pd
# Lists to store the scraped data in
addresses = []
geographies = []
rents = []
units = []
availabilities = []
# Scraping all pages
pages_url = requests.get('https://www.rent.com/new-york/tuckahoe-apartments')
pages_soup = BeautifulSoup(pages_url.text, 'html.parser')
list_nums = pages_soup.find('div', class_='_1y05u').text
print(list_nums)
pages = [str(i) for i in range(0,6)]
for page in pages:
response = requests.get('https://www.rent.com/new-york/tuckahoe-apartments?page=' page).text
html_soup = BeautifulSoup(response, 'html.parser')
# Extract data from individual listing containers
listing_containers = html_soup.find_all('div', class_='_3PdAH')
print(type(listing_containers))
print(len(listing_containers))
print("Page " str(page))
for container in listing_containers:
address = container.a
if address is not None:
addresses.append(address.text)
elif address is None:
addresses.append('None')
else:
address.append(np.nan)
geography = container.find('div', class_='_1dhrl')
if geography is not None:
geographies.append(geography.text)
elif geography is None:
geographies.append('None')
else:
geographies.append(np.nan)
rent = container.find('div', class_='_3e12V')
if rent is None:
rents.append('None')
elif rent is not None:
rents.append(rent.text)
else:
rents.append(np.nan)
unit = container.find('div', class_='_2tApa')
if unit is None:
rents.append('None')
elif rent is not None:
units.append(unit.text)
else:
rents.append(np.nan)
availability = container.find('div', class_='_2P6xE')
if availability is None:
availabilities.append('None')
elif availability is not None:
availabilities.append(availability.text)
else:
availabilities.append(np.nan)
print(len(addresses))
print(len(geographies))
print(len(rents))
print(len(units))
print(len(availabilities))
minlen = min(len(addresses), len(geographies), len(rents), len(units), len(availabilities))
print('Minimum Array Length on this Page = ' str(minlen))
test_df = pd.DataFrame({'Street' : addresses,
'City-State-Zip' : geographies,
'Rent' : rents,
'BR/BA' : units,
'Units Available' : availabilities
})
print(test_df)
Вот вывод с ошибкой, и я напечатал длину каждого массива для каждой веб-страницы, чтобы показать, что проблема впервые возникает на «Странице 5»:
236 Properties
<class 'bs4.element.ResultSet'>
30
Page 0
30
30
30
30
30
Minimum Array Length on this Page = 30
<class 'bs4.element.ResultSet'>
30
Page 1
60
60
60
60
60
Minimum Array Length on this Page = 60
<class 'bs4.element.ResultSet'>
30
Page 2
90
90
90
90
90
Minimum Array Length on this Page = 90
<class 'bs4.element.ResultSet'>
30
Page 3
120
120
120
120
120
Minimum Array Length on this Page = 120
<class 'bs4.element.ResultSet'>
30
Page 4
150
150
150
150
150
Minimum Array Length on this Page = 150
<class 'bs4.element.ResultSet'>
30
Page 5
180
180
188
172
180
Minimum Array Length on this Page = 172
Traceback (most recent call last):
File "renttucktabletest.py", line 103, in <module>
'Units Available' : availabilities
...
ValueError: arrays must all be same length
В результате я либо хочу сократить массив, чтобы остановиться на минимальной длине массивов, чтобы все они были одинаковой длины (в данном случае min = 172), либо заполнить все остальные массивы с помощью NaN или ‘None’, чтобы получить максимальную длину массиватаким образом, все они имеют одинаковую длину (в данном случае максимум — 188).
Я бы предпочел найти решение, которое не включает более продвинутое кодирование, чем BeautifulSoup и pandas.
Ответ №1:
d = {'Street' : addresses,
'City-State-Zip' : geographies,
'Rent' : rents,
'BR/BA' : units,
'Units Available' : availabilities
}
test_df = pd.DataFrame(dict([(k,pd.Series(v)) for k,v in d.items()]))
Ответ №2:
В случае очистки лучше сначала поместить сгенерированную запись из каждой итерации во временную dict
, а затем поместить ее в a list
, добавив ее, как я продемонстрировал ниже:
import numpy as np
import requests
import pandas as pd
from bs4 import BeautifulSoup
# Scraping all pages
pages_url = requests.get("https://www.rent.com/new-york/tuckahoe-apartments")
pages_soup = BeautifulSoup(pages_url.text, "html.parser")
list_nums = pages_soup.find("div", class_="_1y05u").text
pages = [str(i) for i in range(0, 6)]
records = []
for page in pages:
response = requests.get(
"https://www.rent.com/new-york/tuckahoe-apartments?page=" page
).text
html_soup = BeautifulSoup(response, "html.parser")
# Extract data from individual listing containers
listing_containers = html_soup.find_all("div", class_="_3PdAH")
print("Scraping page " str(page))
for container in listing_containers:
# Dict to hold one record
result = {}
address = container.a
if address is None:
result["Street"] = np.nan
else:
result["Street"] = address.text
geography = container.find("div", class_="_1dhrl")
if geography is None:
result["City-State-Zip"] = np.nan
else:
result["City-State-Zip"] = geography.text
rent = container.find("div", class_="_3e12V")
if rent is None:
result["Rent"] = np.nan
else:
result["Rent"] = rent.text
unit = container.find("div", class_="_2tApa")
if unit is None:
result["BR/BA"] = np.nan
else:
result["BR/BA"] = unit.text
availability = container.find("div", class_="_2P6xE")
if availability is None:
result["Units Available"] = np.nan
else:
result["Units Available"] = availability.text
print("Record: ", result)
records.append(result)
test_df = pd.DataFrame(records)
print(test_df)