2012-10-15 152 views
3

我目前有一個問題試圖解析一個表到一個數組。美麗的湯,html表解析

我有一個簡單的表(HERE),我需要用BS4解析並將單元格內容放入數組中。這裏的難點在於單元格不包含文本,而是包含具有以下標題的圖像: 「確認」或「網站」 - 這只是用戶權利的內容。

如果你看一下上面的小提琴[其中包含的複選框我跳過一行一個,那些我可以毫無問題摘錄],我需要做的是分析它以這樣的方式所產生的陣列變成:

Array1[0] = User1,Confirm,Confirm,Site,Confirm 
Array1[1] = User2,Confirm,Confirm,Confirm,Confirm 
Array1[2] = User3,Confirm,Confirm,Confirm,Confirm 
Array1[3] = User4,Confirm,Site,Site,Confirm 

然後我可以按我的意願去做。 另一個複雜因素是,有時行數會有所不同,所以腳本應該能夠適應這一點,並遞歸地從表中創建數組。

目前StackOverflow是我唯一的希望..我花了最後10個小時來做​​這件事,自己幾乎沒有成功,坦率地說我失去了希望。最近我得到的東西是提取封閉標籤,但不能進一步解析一些奇怪的原因,也許這是bs4的嵌套限制?任何人都可以看看,看看他們是否能找到一種方法來做到這一點?或者至少解釋如何到達那裏?

var解釋: rightml - 湯的表。

allusers = [] 
rows = rightml.findAll('tr') 
for tr in rows: 
    cols = tr.findAll('td') 
    for td in cols: 
     if (td.find(title="Group")) or (td.find(title="User")): 
      text = ''.join(td.text.strip()) 
      allusers.append(text) 
print allusers 

gifrights = [] 

rows7 = rightml.findAll('td') 
#print rows7 
for tr7 in rows: 
    cols7 = tr7.findAll('img') 
    for td7 in cols7: 
     if (td7.find(title="Confirm")) or (td7.find(title="Site")): 
      text = ''.join(td7.text.strip()) 
      text2 = text.split(' ') 
      print text2 
      gifrights.append(text2) 

我可能是遙遠,此代碼..但我把它醇」學院嘗試。

回答

5

會是這樣的工作:

rows = soup.find('tbody').findAll('tr') 

for row in rows: 
    cells = row.findAll('td') 

    output = [] 

    for i, cell in enumerate(cells): 
     if i == 0: 
      output.append(cell.text.strip()) 
     elif cell.find('img'): 
      output.append(cell.find('img')['title']) 
     elif cell.find('input'): 
      output.append(cell.find('input')['value']) 
    print output 

此輸出以下:

[u'Logged-in users', u'True', u'True', u'True', u'True'] 
[u'User 1', u'Confirm', u'Confirm', u'Site', u'Confirm'] 
[u'User 2', u'Confirm', u'Confirm', u'Confirm', u'Confirm'] 
[u'User 3', u'Confirm', u'Confirm', u'Confirm', u'Confirm'] 
[u'User 4', u'Confirm', u'Site', u'Site', u'Confirm'] 
+0

會檢查一次我是回家。但是,如果這種方法有效,你絕對可以擁有我所有的互聯網! – Meh

+0

工作得很好。謝謝! – Meh

4

我覺得它的速度更快了行這樣使用列表理解。

rows = soup.find('tbody').findAll('tr') 

for i in rows[1:]: # the first row is thrown out 
    [j['title'] for j in i.findAll('img')] 

,讓你

['User', 'Confirm', 'Confirm', 'Site', 'Confirm'] 
['User', 'Confirm', 'Confirm', 'Confirm', 'Confirm'] 
['User', 'Confirm', 'Confirm', 'Confirm', 'Confirm'] 
['User', 'Confirm', 'Site', 'Site', 'Confirm'] 

您可以使用嵌套列表理解切出更加步驟:

# superpythonic 
[[j['title'] for j in i.findAll('img')] for i in rows[1:]] 

# all together now, but not so pythonic 
[[j['title'] for j in i.findAll('img')] for i in soup.find('tbody').findAll('tr')[1:]] 

你並不真的需要一個用戶#,因爲用戶#是索引號+1。

[[j['title'] for j in i.findAll('img') if j['title'] != 'User'] for i in rows[1:]] 

但是,如果你有-must-一個...

for i in xrange(len(users)): 
    users[i].append("User " + str(i+1)) 

但是,如果你堅持這樣做,我會用一個namedtuple作爲數據結構,而不是一個列表。namedtuple

from collections import namedtuple 
# make these actual non-obfuscated names, not column numbers 
User = namedtuple('User', ('num col_1 col_2 col_3 col_4') 

然後,一旦你有namedtuple,比如說,用戶1的實例作爲user,你可以...

>>> user.num 
... 1 
>>> user.col_1 
... 'Confirm' 
>>> user.col_2 
... 'Confirm' 
>>> user.col_3 
... 'Site' 
>>> user.col_4 
... 'Confirm' 
+0

我已經嘗試過您的方法以及上面的方法,兩者都很好。非常感謝您的解釋和建議! – Meh