【问题标题】:Beautiful Soup and scraping wikipedia entries:美丽的汤和刮维基百科条目:
【发布时间】:2020-07-03 14:46:32
【问题描述】:

BeautifulSoup 的初学者,我正在尝试提取

来自此维基百科链接的公司名称、排名和收入。

https://en.m.wikipedia.org/wiki/List_of_largest_Internet_companies

我目前使用的代码是:

from bs4 import BeautifulSoup 
import requests 
url = "https://en.wikiepdia.org" 
req = requests.get(url) 
bsObj = BeautifulSoup(req.text, "html.parser") 
data = bsObj.find('table',{'class':'wikitable sortable mw-collapsible'})
revenue=data.findAll('data-sort-value')

我意识到即使是“数据”也无法正常工作,因为当我将它传递给烧瓶网站时它没有任何值。

是否有人可以提出解决方案和实现上述目标的最优雅方式,以及对我们在抓取时在 HTML 中寻找的内容(和格式)的最佳方法提出一些建议。

在此链接上,https://en.m.wikipedia.org/wiki/List_of_largest_Internet_companies 我不确定要使用什么来提取 - 是表类、div 类还是正文类。此外,如何进一步提取链接和收入。

我也试过了:

data = bsObj.find_all('table', class_='wikitable sortable mw-collapsible')

它运行服务器没有错误。但是,网页“[]”上只显示一个空列表

基于以下一个答案:我将代码更新为以下内容:

url = "https://en.wikiepdia.org" 
req = requests.get(url) 
bsObj = BeautifulSoup(req.text, "html.parser") 
mydata=bsObj.find('table',{'class':'wikitable sortable mw-collapsible'})
table_data=[]
rows = mydata.findAll(name=None, attrs={}, recursive=True, text=None, limit=None, kwargs='')('tr')
for row in rows:
    cols=row.findAll('td')
    row_data=[ele.text.strip() for ele in cols]
    table_data.append(row_data)

data=table_data[0:10]

持续的错误是:

 File "webscraper.py", line 15, in <module>
    rows = mydata.findAll(name=None, attrs={}, recursive=True, text=None, limit=None, kwargs='')('tr')
AttributeError: 'NoneType' object has no attribute 'findAll'

根据下面的回答,它现在正在抓取数据,但不是上面要求的格式:

我有这个:

url = 'https://en.m.wikipedia.org/wiki/List_of_largest_Internet_companies' 
req = requests.get(url) 
bsObj = BeautifulSoup(req.text, 'html.parser')
data = bsObj.find('table',{'class':'wikitable sortable mw-collapsible'})

table_data = []
rows = data.find_all('tr')
for row in rows:
    cols = row.find_all('td')
    row_data = [ele.text.strip() for ele in cols]
    table_data.append(row_data)

# First element is header so that is why it is empty
data=table_data[0:5]

for in in range(5):
    rank=data[i]
    name=data[i+1]

为了完整性(和完整的答案),我希望它能够显示

-表中前五家公司 - 公司名称、排名、收入

目前显示如下:

维基百科

[[], ['1', '亚马逊', '$280.5', '2019', '798,000', '$920.22', '西雅图', '1994', '[1][2]'], ['2', '谷歌', '$161.8', '2019', '118,899', '$921.14', '山景', '1998', '[3][4]'], ['3', '京东', '$82.8', '2019', '220,000', '$51.51', '北京', '1998', '[5][6]'], ['4', 'Facebook', '$70.69 ', '2019', '45,000', '$585.37', '门洛帕克', '2004', '[7][8]']]

['1', '亚马逊', '$280.5', '2019', '798,000', '$920.22', '西雅图', '1994', '[1][2]']

['2', 'Google', '$161.8', '2019', '118,899', '$921.14', '山景', '1998', '[3][4]']

【问题讨论】:

  • 您正在抓取的 URL 是维基百科主页。这是代码的url = "https://en.wikiepdia.org" 部分。该页面上没有表格,所以 BeautifulSoup 没有给你任何返回索引。这就是你收到错误的原因。您需要将该 URL 替换为一个带有您引用的表的表 en.m.wikipedia.org/wiki/List_of_largest_Internet_companies
  • 啊,谢谢...但还是 findall 错误?
  • 应该是.find_all() 而不是.findAll()

标签: python web-scraping beautifulsoup wikipedia


【解决方案1】:

通常(并非总是)在处理 Wikipedia 表格时,您不必费心使用 beautifulsoup。只需使用熊猫:

import pandas as pd
table = pd.read_html('https://en.m.wikipedia.org/wiki/List_of_largest_Internet_companies')
table[0]

输出:

    Rank    Company     Revenue ($B)    F.Y.    Employees   Market cap. ($B)    Headquarters    Founded     Refs
0   1   Amazon  $280.5  2019    798000  $920.22     Seattle     1994    [1][2]
1   2   Google  $161.8  2019    118899  $921.14     Mountain View   1998    [3][4]

等等。 然后,您可以使用标准 pandas 方法选择或删除列等。

编辑: 仅显示前 5 名公司的名称、排名和收入:

table[0][["Rank", "Company","Revenue ($B)"]].head(5)

输出:

    Rank Company    Revenue ($B)
0   1   Amazon      $280.5
1   2   Google      $161.8
2   3   JD.com     $82.8
3   4   Facebook    $70.69
4   5   Alibaba     $56.152

【讨论】:

  • 这很有用。它是否也涉及使用 pip 下载熊猫,或者只是如您所展示的那样导入?不幸的是,出于学习/教学目的,我需要能够使用 BeautifulSoup 来做到这一点。您能否添加使用 BeautifulSoup 修复现有代码的答案?
  • @MissComputing 是的,不幸的是它需要pip install pandas。让我看看如何用 bs 来做。
  • 另外,使用熊猫。您能否为特定问题编写代码,例如显示公司名称、排名和收入的所有结果。
  • @Eric Leung 打败了我!
  • 这对我不起作用,也不符合要求的格式吗? :)
【解决方案2】:

这是一个使用 BeautifulSoup 的示例。以下很多内容都是基于https://stackoverflow.com/a/23377804/6873133这里的答案。

from bs4 import BeautifulSoup 
import requests

url = 'https://en.m.wikipedia.org/wiki/List_of_largest_Internet_companies' 
req = requests.get(url) 

bsObj = BeautifulSoup(req.text, 'html.parser')
data = bsObj.find('table',{'class':'wikitable sortable mw-collapsible'})

table_data = []
rows = data.find_all('tr')
for row in rows:
    cols = row.find_all('td')
    row_data = [ele.text.strip() for ele in cols]
    table_data.append(row_data)

# First element is header so that is why it is empty
table_data[0:5]
# [[],
#  ['1', 'Amazon', '$280.5', '2019', '798,000', '$920.22', 'Seattle', '1994', '[1][2]'],
#  ['2', 'Google', '$161.8', '2019', '118,899', '$921.14', 'Mountain View', '1998', '[3][4]'],
#  ['3', 'JD.com', '$82.8', '2019', '220,000', '$51.51', 'Beijing', '1998', '[5][6]'],
#  ['4', 'Facebook', '$70.69', '2019', '45,000', '$585.37', 'Menlo Park', '2004', '[7][8]']]

所以隔离这个列表的某些元素,你只需要注意内部列表的数字索引。在这里,让我们看看亚马逊的前几个值。

# The entire row for Amazon
table_data[1]
# ['1', 'Amazon', '$280.5', '2019', '798,000', '$920.22', 'Seattle', '1994', '[1][2]']

# Rank
table_data[1][0]
# '1'

# Company
table_data[1][1]
# 'Amazon'

# Revenue
table_data[1][2]
# '$280.5'

因此,要仅隔离前几列(排名、公司和收入),您可以运行以下列表解析。

iso_data = [tab[0:3] for tab in table_data]

iso_data[1:6]
# [['1', 'Amazon', '$280.5'], ['2', 'Google', '$161.8'], ['3', 'JD.com', '$82.8'], ['4', 'Facebook', '$70.69'], ['5', 'Alibaba', '$56.152']]

然后,如果你想把它放入一个pandas数据框,你可以这样做。

import pandas as pd

# The `1` here is important to remove the empty header
df = pd.DataFrame(table_data[1:], columns = ['Rank', 'Company', 'Revenue', 'F.Y.', 'Employees', 'Market cap', 'Headquarters', 'Founded', 'Refs'])

df
#    Rank     Company  Revenue  F.Y. Employees Market cap   Headquarters Founded        Refs
# 0     1      Amazon   $280.5  2019   798,000    $920.22        Seattle    1994      [1][2]
# 1     2      Google   $161.8  2019   118,899    $921.14  Mountain View    1998      [3][4]
# 2     3      JD.com    $82.8  2019   220,000     $51.51        Beijing    1998      [5][6]
# 3     4    Facebook   $70.69  2019    45,000    $585.37     Menlo Park    2004      [7][8]
# 4     5     Alibaba  $56.152  2019   101,958    $570.95       Hangzhou    1999     [9][10]
# ..  ...         ...      ...   ...       ...        ...            ...     ...         ...
# 75   77    Farfetch    $1.02  2019     4,532      $3.51         London    2007  [138][139]
# 76   78        Yelp    $1.01  2019     5,950      $2.48  San Francisco    1996  [140][141]
# 77   79   Vroom.com     $1.1  2020     3,990       $5.2  New York City    2003       [142]
# 78   80  Craigslist     $1.0  2018     1,000          -  San Francisco    1995       [143]
# 79   81    DocuSign     $1.0  2018     3,990     $10.62  San Francisco    2003       [144]
# 
# [80 rows x 9 columns]

【讨论】:

  • 谢谢 - 所以我可以尝试一下,作为答案,它是否可以准确提取:公司名称、排名、收入(前 10 条记录)
  • 这一行也出现错误“rows = mydata.find_all('tr')” > AttributeError: 'NoneType' object has no attribute 'find_all'
  • 修复了!为了保持一致性并帮助其他将参考此内容的人(我的学生也会),您能否更新答案以显示正确的索引,例如隔离名称、排名和收入。然后会接受...谢谢一百万
  • 很高兴有帮助。 “隔离”是什么意思?索引应该是什么?
  • data=table_data[0:5] for in in range(5): rank=data[i] name=data[i+1] .. 我的意思是,我想要的唯一数据是公司名称、收入和排名。 (打印时删除所有其他数据)。 AND 前十条记录。我试过这个循环-
【解决方案3】:

这是另一个,这次只有 beautifulsoup,它打印了前 5 家公司的排名、名称和收入:

table_data=[]
trs = soup.select('table tr')
for tr in trs[1:6]:
    row = []
    for t in tr.select('td')[:3]:    
        row.extend([t.text.strip()])
    table_data.append(row)
table_data

输出:

[['1', 'Amazon', '$280.5'],
 ['2', 'Google', '$161.8'],
 ['3', 'JD.com', '$82.8'],
 ['4', 'Facebook', '$70.69'],
 ['5', 'Alibaba', '$56.152']]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    • 2020-12-13
    • 2019-03-13
    • 2014-05-28
    相关资源
    最近更新 更多