Как заставить массивы иметь одинаковую длину в пандах - PullRequest
1 голос
/ 17 апреля 2019

Я новичок - и я могу собирать данные с нескольких веб-страниц на веб-сайте, используя BeautifulSoup, и я использую панды для составления таблицы данных.Проблема в том, что я не могу получить все массивы одинаковой длины и получаю следующее: ValueError: все массивы должны быть одинаковой длины

Вот код, который я пробовал:

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.Я знаю, что json может быть решением, но я пока не знаю, как использовать json (но это следующая вещь, которую я собираюсь изучить).Если JSON является единственным решением, пожалуйста, дайте мне знать.

Заранее благодарю за всю вашу помощь, этот форум неоценим.

Ответы [ 2 ]

1 голос
/ 17 апреля 2019

Выполняет ли это то, что вы хотите?

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)

В случае удаления, лучше сначала поместить сгенерированную запись из каждой итерации во временную dict, а затем поместить ее в list, добавивэто как я продемонстрировал выше.

1 голос
/ 17 апреля 2019

Добро пожаловать в StackOverflow. Отлично MCVE.

    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()]))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...