【问题标题】:Basic web scraping using beautiful soup: scrape a table使用漂亮的汤进行基本的网页抓取:刮一张桌子
【发布时间】:2014-05-02 04:03:27
【问题描述】:

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

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

我得到的输出相当成功!但是,我不确定我的代码是否非常“pythonic”。我有点粗暴地强迫我使用一些正则表达式来抓取数据,我觉得肯定有一种更简单、更快捷的方法来抓取表格数据并删除一些讨厌的 u'Name' 格式和图像链接,这些链接放置在整个桌子。将来,我想知道除了我的hacky方式之外,刮桌子和删除格式的标准方法是什么。

具体来说,在表格的第 3 列中,我们看到有一个国家国旗的图像以及我关心的信息(国家名称)。因此,我不能只做单元格[3 ].find(文本=真)。我通过仅抓取单元格 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()

【问题讨论】:

  • 是的,您可以进行一些更改来清理它。对于初学者,一旦您定义了“表”,您可以使用 print table.prettify() 打印出该数据以查看表节点的子父关系,这使得在编码每个步骤时更容易知道导航到什么。我会尽快发布完整的答案并提出一些建议

标签: python web-scraping beautifulsoup wikipedia


【解决方案1】:

这是怎么回事:

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 语句或比较 (!=) 的价值。它是一种过滤垃圾的杀手级方法,无需编写其他部分。

好的,在表格上使用 prettify() 之后,您会注意到格式做得相当好,并且您想要在 csv 的每一行上的每一位数据都被分隔为 <tr> 标签。

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

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

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

【讨论】:

  • 那肯定是更少的代码行,但对于像我这样的 python 新手来说,它的可读性不是很好。您介意解释一下 row.findAll('th',text=True) 的作用吗?编辑:我刚刚运行了您的代码,但它并没有输出它以使我擅长。我刚刚得到:# 公司 行业 国家 年份 报告日期 收益(十亿) 美元“实际”收益(十亿)
  • 非常感谢您的解释!我想我什么都懂,除了如何在表格中使用 prettify() 函数。当我尝试打印 table.prettify() 时,我收到“unicode 错误:编解码器无法编码字符。这与我之前尝试从表中打印欧元符号时遇到的错误相同。我之前解决了它通过将字符编码为 utf-8 但我不能在这里这样做。
猜你喜欢
  • 2013-11-08
  • 2017-12-23
  • 2022-01-08
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 2018-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多