Я пытаюсь получить данные из таблицы 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.
Вы уверены, что очищаете правильную таблицу? Я понял, что вам нужна вторая таблица с 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()
, чтобы удалить любые начальные (пробелы в начале) и конечные (пробелы в конце) символы (пробел — это удаляемый начальный символ по умолчанию), т. е. очистить текст.@Psychotron Пожалуйста. Рад помочь!
Вы можете использовать тот факт, что нечетные строки — это районы, а четные строки — это районы, чтобы обойти нечетные строки и использовать 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().
Большое спасибо за этот ответ с объяснением. У меня была немного другая концепция для этого фрейма данных, но она сработала бы, если бы у меня был список почтовых индексов для каждого района. В любом случае, ваш вариант лучше, спасибо. Честно говоря, я впервые работаю с несколькими таблицами на одной странице и не уверен, как они индексируются. Я думал, что они начинаются с 0, но какой-то пример в сети меня немного смутил.