【问题标题】:How can I webscrape a Wikipedia table with lists of data instead of rows?如何使用数据列表而不是行来抓取维基百科表格?
【发布时间】:2021-03-23 08:18:16
【问题描述】:

我正在尝试从位于 Wikipedia https://en.wikipedia.org/wiki/Districts_of_Warsaw 页面上的 Localities 表中获取数据。

我想收集这些数据并将其放入包含两列 ["Districts"] 和 ["Neighbourhoods"] 的数据框中。

到目前为止,我的代码如下所示:

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)

这给出了以下数据框:

Dataframe

当然,抓取 Neighborhood 列是不正确的,因为它们包含在列表中,但我不知道应该怎么做,所以很高兴有任何提示。

除此之外,我会感谢任何提示,为什么抓取只给我 10 个区而不是 18 个区。

【问题讨论】:

    标签: python dataframe web-scraping beautifulsoup


    【解决方案1】:

    你确定你在刮正确的桌子吗?我知道您需要第二张桌子,其中包含 18 个区和列出的社区。​​p>

    另外,我不确定您希望如何在 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 不客气。很高兴能帮上忙!
    【解决方案2】:

    您可以使用奇数行是 Districts 并且偶数行是 Neighborhoods 的事实来遍历奇数行并使用 FindNext 从下面的行中抓取社区,同时在奇数行中迭代 District 列:

    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() 方法一起使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-16
    • 2019-07-20
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多