python - 使用 beautiful soup 的基本网页抓取 : scrape a table

标签 python web-scraping beautifulsoup wikipedia

我正在尝试学习一些基本的网络抓取。我最初设置了 scrapy 并发现它有点令人畏惧,所以我决定在开始爬行之前首先使用 beautifulsoup 进行一些单页抓取练习。我的项目想法是抓取下表并将信息输出到 Excel 文件。

该表位于维基百科的此页面: http://en.wikipedia.org/wiki/List_of_largest_corporate_profits_and_losses

我得到的输出非常成功!但是,我不确定我的代码是否非常“Pythonic”。我有点暴力地使用一些正则表达式来获取数据,我觉得肯定有一种更简单、更快的方法来获取表数据并删除一些讨厌的 u'Name' 格式和图像链接。 table 。将来,我想知道除了我的黑客方法之外,抓取表格和删除格式的标准方法是什么。

具体来说,在表格的第3列中,我们看到有一个国家国旗的图像以及我关心的信息(国家名称)。因此,我不能只做单元格[3 ].find(文本=True)。我通过仅获取单元格 3 中的所有 a 标签,然后使用正则表达式仅获取标题中包含的国家/地区名称来解决此问题:

for j,cell in enumerate(cells):
            if j%3 == 0:
                text = (cell.findAll('a'))

感谢并抱歉发了这么长的帖子!

from bs4 import BeautifulSoup
import urllib2
import re

wiki = "http://en.wikipedia.org/wiki/List_of_largest_corporate_profits_and_losses"
header = {'User-Agent': 'Mozilla/5.0'} #Needed to prevent 403 error on Wikipedia
req = urllib2.Request(wiki,headers=header)
page = urllib2.urlopen(req)
soup = BeautifulSoup(page)

table = soup.find("table", { "class" : "wikitable sortable" })

f = open('output.csv', 'w')

num = []; company = []; industry = []; country = []; year = []; reportdate = [];          
earnings = []; usdinflation = []; usdrealearnings = []; cunts = [];

for i,row in enumerate(table.findAll("tr")):
    cells = row.findAll("td")
    if len(cells) == 9:
        num.append(cells[0].find(text=True))
        company.append(cells[1].findAll(text=True))
        industry.append(cells[2].find(text=True))
        country.append(cells[3].find(text=True))
        year.append(cells[4].find(text=True))
        reportdate.append(cells[5].find(text=True))
        earnings.append(cells[6].find(text=True))
        usdinflation.append(cells[7].find(text=True))
        usdrealearnings.append(cells[8].find(text=True))
    for j,cell in enumerate(cells):
        if j%3 == 0:
            text = (cell.findAll('a'))
            newstring = re.search(r'(title="\w+\s\w+")|(title="\w+")',str(text))
            if not(newstring is None):
                newstring2 = re.search(r'("\w+")|("\w+\s\w+")',newstring.group())
                cunts.append(newstring2.group())


for i in range(len(num)):
    s = str(company[i])
    newstring = re.search(r'\w+\s|\w+\w+', s).group(); 
    write_to_file = str(num[i])+ "," + newstring + "," + str(industry[i]) + "," +      cunts[i].encode('utf-8') + ","+ str(year[i]) + ","+ str(reportdate[i])+ ","+     earnings[i].encode('utf-8') + "," + str(usdinflation[i]) + "," + str(usdrealearnings[i]) +     "\n";
    f.write(write_to_file)

f.close()

最佳答案

这个怎么样:

from bs4 import BeautifulSoup
import urllib2
import re

wiki = "http://en.wikipedia.org/wiki/List_of_largest_corporate_profits_and_losses"
header = {'User-Agent': 'Mozilla/5.0'} #Needed to prevent 403 error on Wikipedia
req = urllib2.Request(wiki,headers=header)
page = urllib2.urlopen(req)
soup = BeautifulSoup(page)
table = soup.find("table", { "class" : "wikitable sortable" })
f = open('output.csv', 'w')
for row in table.findAll('tr'):
    f.write(','.join(''.join([str(i).replace(',','') for i in row.findAll('td',text=True) if i[0]!='&']).split('\n')[1:-1])+'\n')

f.close()

输出到文件:

#,Company,Industry,Country,Year,Report Date,Earnings (Billion),USD Inflation to December 2012[1],USD "Real" Earnings (Billion)
1,ExxonMobil,Oil and gas,United States,2008,31 December 2008,$45.22[2],9.40%,$49.50
2,ExxonMobil,Oil and gas,United States,2006,31 December 2006,$39.5[2],13.95%,$45.01
3,ExxonMobil,Oil and gas,United States,2007,31 December 2007,$40.61[2],9.50%,$44.47
4,ExxonMobil,Oil and gas,United States,2005,31 December 2005,$36.13[3],16.85%,$42.22
5,ExxonMobil,Oil and gas,United States,2011,31 December 2011,$41.06[4],1.90%,$41.84
6,Apple,Consumer electronics,United States,2012,29 September 2012,$41.73 [5],-0.63%,$41.47
-,Industrial & Commercial Bank of China,Banking,China,2012,31 December 2012,RMB 238.7[6],-,$38.07
7,Nestlé,Food processing,Switzerland,2010,31 December 2010,$37.88[7],4.92%,$39.74
.....and so on

解释一下~

关于 Python,需要记住一些事情。

  • 使 u'foo' str(u'foo') 删除 unicode 文字表示法
  • 不要低估在列表推导式中使用 if/else 语句或比较 (!=) 的值(value)。这是过滤掉垃圾的 killer 级方法,而无需编写其他部分的代码。

好吧,在表上使用 prettify() 后,您会发现格式做得相当好,并且 csv 的每一行上所需的每一位数据都被分成 <tr> 。标签。

使用 row.findAll(tag='tr', text=True) 我所做的是将所有数据(尚未过滤)拆分为行列表。 soup.findAll 将列出指定标签的每个实例。在这种情况下,每个 <tr\>包含在表中。

我们只想要表格文本,而不是格式带来的任何额外垃圾,因此 text=True 只获取表格单元格中显示的文本。

我将其嵌套在列表理解中,该列表理解将搜索返回的任何数据转换为字符串(删除 u'foo'),并用 ',' 分隔行中的每个元素,以使用所需的 csv 格式进行 jive并添加了一些 if 要求来过滤掉任何剩余的垃圾,例如括号。

关于python - 使用 beautiful soup 的基本网页抓取 : scrape a table,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23420533/

相关文章:

python - 使用 sublime 在终端中运行 python

python - 如何使用 pandas 和 beautiful soup 来抓取多个网页地址上的表格?

python - 如何从带有索引的二维数组中获取值

python - 将属性名称传递给 Python 中的函数

python - 继续基于错误的 Python 脚本

python - 通过 Python 中的网页抓取工具登录网站

html - 基于正则表达式 attr 从 read_html 过滤表

python - 当有另一个类似的 div 类时如何处理特定的 div 类?

python - 如何将图像转换为 dicom 图像?

python - 如何使用 scrapy 合约?