2014-05-02 81 views
2

我試圖學習一些基本的網頁刮。我最初設置了scrapy,並注意到它有點令人生畏,所以我決定首先使用beautifulsoup進行單頁抓取練習,然後再進入爬行。我的項目想法是刮掉下面的表格並將信息輸出到excel文件。基本網頁刮美麗的湯:刮表

表位於此頁面上維基百科: http://en.wikipedia.org/wiki/List_of_largest_corporate_profits_and_losses

我得到的輸出是相當成功的!但是,我不確定我的代碼是非常「pythonic」。我有種野蠻人強迫我使用一些正則表達式來獲取數據,我覺得確實有一種更簡單快捷的方式來獲取表格數據並刪除一些討厭的u'Name'格式和圖像鏈接表。在未來,我想知道除了我的黑客方式之外,還有什麼標準方式來刪除表格並刪除格式。

具體而言,在表格的第3列中,我們看到有國旗的圖像以及我關心的信息(國名)。因此,我不能只做細胞[ 3] .find(文本=真)。我周圍這讓通過抓取僅小區3的所有標籤一個,然後使用正則表達式搶僅含標題中的國名:

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() 
+0

是的,你可以做一些改變來清理它。對於初學者,一旦你定義了「table」,你就可以使用print table.prettify()打印出這些數據來查看錶節點的子父母關係,這使得在編碼每一步時知道要導航到什麼時更容易。我會很快發佈一個完整的答案,並提供一些建議。 – Amazingred

回答

2

這個怎麼樣:

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語句或列表理解裏面比較(!=) 。它是一種無需編碼另一部分就可以過濾垃圾的殺手方式。在桌子上使用美化()

好了之後,你會注意到格式做得相當好,你想對你的csv的每一行數據的每一位被分成<tr>標籤。

使用row.findAll(tag ='tr',text = True)我所做的是將所有數據(尚未過濾)分割成行列表。 soup.findAll將列出指定標籤的每個實例。在這種情況下,每個<tr\>包含在表中。

我們只希望表格文本沒有任何格式化的額外垃圾,所以text = True只會獲取表格單元格中顯示的文本。

我將它嵌套在列表理解中,該列表理解將搜索返回的任何數據轉換爲字符串(移除u'foo),並將行中的每個元素用','分隔爲必需的csv格式,並添加了一些如果需要過濾掉任何剩餘的垃圾像括號。

+0

這肯定是少得多的代碼行,但對於像我這樣的python新手來說,它不太可讀。你介意解釋一下row.findAll('th',text = True)是做什麼的。 編輯:我只是跑你的代碼,它不輸出,爲我擅長。我剛開: # \t 公司 \t 行業 \t 國家 \t 年 \t 報告日期 \t 收入(億美元) \t 美元的 「真實」 收入(億美元) – gnicholas

+0

檢查再一次。我在轉移代碼的同時sm了幾條線...... – Amazingred

+0

非常感謝!我想我瞭解一切,除了如何在表格中使用prettify()函數。當我嘗試打印table.prettify()時,我得到一個「unicode錯誤:編解碼器無法編碼字符。這是我之前嘗試從表格中打印歐元符號時得到的錯誤。通過編碼字符爲UTF-8,但我不能這樣做。 – gnicholas