Как я могу очистить таблицу Википедии со списками данных вместо строк?

Я пытаюсь получить данные из таблицы Localities, расположенной на странице Википедии https://en.wikipedia.org/wiki/Districts_of_Warsaw.

Я хотел бы собрать эти данные и поместить их в фрейм данных с двумя столбцами [«Районы»] и [«Окрестности»].

Мой код пока выглядит так:

url = "https://en.wikipedia.org/wiki/Districts_of_Warsaw"
page = urllib.request.urlopen(url)
soup = BeautifulSoup(page, "html")

table = soup.find_all('table')[2]

A=[]
B=[]

for row in table.findAll('tr'):
    cells=row.findAll('td')
    if len(cells)==2:
        A.append(cells[0].find(text=True))
        B.append(cells[1].find(text=True))

df=pd.DataFrame(A,columns=['Neighbourhood'])
df['District']=B
print(df)

Это дает следующий фрейм данных:

Датафрейм

Конечно, парсить столбец Neighborhood неправильно, так как они содержатся в списках, но я не знаю, как это сделать, поэтому буду рад любым советам.

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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы уверены, что очищаете правильную таблицу? Я понял, что вам нужна вторая таблица с 18 районами и перечисленными районами.

Кроме того, я не уверен, как вы хотите, чтобы районы и районы были расположены в DataFrame, я установил районы как столбцы, а районы как строки. Вы можете изменить его, как хотите.

import requests
from bs4 import BeautifulSoup
import pandas as pd

url = "https://en.wikipedia.org/wiki/Districts_of_Warsaw"
page = requests.get(url)
soup = BeautifulSoup(page.text, "html.parser")

table = soup.find_all("table")[1]

def process_list(tr):
    result = []
    for td in tr.findAll("td"):
        result.append([x.string for x in td.findAll("li")])
    return result

districts = []
neighbourhoods = []
for row in table.findAll("tr"):
    if row.find("ul"):
        neighbourhoods.extend(process_list(row))
    else:
        districts.extend([x.string.strip() for x in row.findAll("th")])

# Check and arrange as you wish
for i in range(len(districts)):
    print(f'District {districts[i]} has neighbourhoods: {", ".join(neighbourhoods[i])}')

df = pd.DataFrame()
for i in range(len(districts)):
    df[districts[i]] = pd.Series(neighbourhoods[i])

Некоторые советы:

  • Используйте element.string, чтобы получить текст из элемента
  • Используйте string.strip(), чтобы удалить любые начальные (пробелы в начале) и конечные (пробелы в конце) символы (пробел — это удаляемый начальный символ по умолчанию), т. е. очистить текст.

Большое спасибо за этот ответ с объяснением. У меня была немного другая концепция для этого фрейма данных, но она сработала бы, если бы у меня был список почтовых индексов для каждого района. В любом случае, ваш вариант лучше, спасибо. Честно говоря, я впервые работаю с несколькими таблицами на одной странице и не уверен, как они индексируются. Я думал, что они начинаются с 0, но какой-то пример в сети меня немного смутил.

Psychotron 12.12.2020 20:16

@Psychotron Пожалуйста. Рад помочь!

vladsiv 12.12.2020 21:41

Вы можете использовать тот факт, что нечетные строки — это районы, а четные строки — это районы, чтобы обойти нечетные строки и использовать FindNext для захвата районов из строки ниже, при этом повторяя столбцы района в нечетных строках:

import requests
import pandas as pd
from bs4 import BeautifulSoup as bs
from itertools import zip_longest

soup = bs(requests.get('https://en.wikipedia.org/wiki/Districts_of_Warsaw').content, 'lxml')
table = soup.select_one('h2:contains("Localities") ~ .wikitable') #isolate table of interest
results = []

for row in table.select('tr')[0::2]: #walk the odd rows
    for i in row.select('th'): #walk the districts
        r = list(zip_longest([i.text.strip()] , [i.text for i in row.findNext('tr').select('li')], fillvalue=i.text.strip())) # zip the current district to the list of neighbourhoods in row below. Fill with District name to get lists of equal length
        results.append(r)
        
results = [i for j in results for i in j] #flatten list of lists
df = pd.DataFrame(results, columns= ['District','Neighbourhood'])
print(df)

Большое спасибо за ответ, особенно за код для выделения нужной мне таблицы. Сначала я попробовал этот подход, но не был уверен, какие параметры следует использовать с методом select_one().

Psychotron 12.12.2020 20:20

Другие вопросы по теме