BeautifulSoup, a dictionary from an HTML table

五迷三道 提交于 2019-12-29 05:18:08

问题


I am trying to scrape table data from a website.

Here is a simple example table:

t = '<html><table>' +\
    '<tr><td class="label"> a </td> <td> 1 </td></tr>' +\
    '<tr><td class="label"> b </td> <td> 2 </td></tr>' +\
    '<tr><td class="label"> c </td> <td> 3 </td></tr>' +\
    '<tr><td class="label"> d </td> <td> 4 </td></tr>' +\
    '</table></html>'

Desired parse result is {' a ': ' 1 ', ' b ': ' 2 ', ' c ': ' 3 ', ' d ' : ' 4' }


This is my closest attempt so far:

for tr in s.findAll('tr'):
  k, v = BeautifulSoup(str(tr)).findAll('td')
  d[str(k)] = str(v)

Result is:

{'<td class="label"> a </td>': '<td> 1 </td>', '<td class="label"> d </td>': '<td> 4 </td>', '<td class="label"> b </td>': '<td> 2 </td>', '<td class="label"> c </td>': '<td> 3 </td>'}

I'm aware of the text=True parameter of findAll() but I'm not getting the expected results when I use it.

I'm using python 2.6 and BeautifulSoup3.


回答1:


Try this:

from BeautifulSoup import BeautifulSoup, Comment

t = '<html><table>' +\
    '<tr><td class="label"> a </td> <td> 1 </td></tr>' +\
    '<tr><td class="label"> b </td> <td> 2 </td></tr>' +\
    '<tr><td class="label"> c </td> <td> 3 </td></tr>' +\
    '<tr><td class="label"> d </td> <td> 4 </td></tr>' +\
    '</table></html>'

bs = BeautifulSoup(t)

results = {}
for row in bs.findAll('tr'):
    aux = row.findAll('td')
    results[aux[0].string] = aux[1].string

print results



回答2:


If you're scraping a table has an explicit "thead" and "tbody" such as:

<table>
    <thead>
        <tr>
            <th>Total</th>
            <th>Finished</th>
            <th>Unfinished</th>
        </tr>
    </thead>
    <tbody>
        <tr> <td>63</td> <td>33</td> <td>2</td> </tr>
        <tr> <td>69</td> <td>29</td> <td>3</td> </tr>
        <tr> <td>57</td> <td>28</td> <td>1</td> </tr>
    </tbody>
</table>

You can use the following:

headers = [header.text_content() for header in table.cssselect("thead tr th")]
results = [{headers[i]: cell.text_content() for i, cell in enumerate(row.cssselect("td"))} for row in table.cssselect("tbody tr")]

This will produce:

[
  {"Total": "63", "Finished": "33", "Unfinished": "2"},
  {"Total": "69", "Finished": "29", "Unfinished": "3"},
  {"Total": "57", "Finished": "28", "Unfinished": "1"}
]

P.S. This is using lxml.html. If you are using BeautifulSoup replace ".text_content()" with ".string" and ".cssselect" with ".findAll".




回答3:


You can follow the same approach as mvillaress, but improve it a bit, using List Comprehensions:

from BeautifulSoup import BeautifulSoup

t = '<html><table>' +\
    '<tr><td class="label"> a </td> <td> 1 </td></tr>' +\
    '<tr><td class="label"> b </td> <td> 2 </td></tr>' +\
    '<tr><td class="label"> c </td> <td> 3 </td></tr>' +\
    '<tr><td class="label"> d </td> <td> 4 </td></tr>' +\
    '</table></html>'

bs = BeautifulSoup(t)
tds = [row.findAll('td') for row in bs.findAll('tr')]
results = { td[0].string: td[1].string for td in tds }
print results



回答4:


BeautifulSoup and Python have evolved, so if someone comes here with newer versions:

Python>=3.7
BeautifulSoup>=4.7

Here's updated code that works:

# import bs4 and create your 'soup' object

table = soup.find('table')

headers = [header.text for header in table.find_all('th')]
results = [{headers[i]: cell for i, cell in enumerate(row.find_all('td'))}
           for row in table.find_all('tr')]


来源:https://stackoverflow.com/questions/11901846/beautifulsoup-a-dictionary-from-an-html-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!