Как я могу сделать, чтобы все массивы были одинаковой длины в Pandas?

#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)