如何判断filter()是否返回一个新列表

时间:2013-06-07 04:50:27

标签: python beautifulsoup

在抓取此Afghanistan page时,我收到错误消息:

Traceback (most recent call last):                                                                                                                                                                                 
  File "extract_table.py", line 23, in <module>                                                                                                                                                                    
    li = dict(chunks([i.text for i in all_td], 2))                                                                                                                                                                 
ValueError: dictionary update sequence element #28 has length 1; 2 is required

但是在抓取Argentina page时,代码运行正常。

如果all_td已返回新列表,有没有办法告诉我们?我想知道python中要使用哪些函数。

像这样的伪代码:

if all_td is new list,
    execute dict(chunks([i.text for i in all_td], 2))
else
    execute dict(chunks([i.text for i in areatable.findAll('td')], 2))

我想要完成的是将代码运行到阿富汗和阿根廷这两个国家。

这是我的代码

from bs4 import BeautifulSoup                                                                                                                                                                                       
import urllib2                                                                                                                                                                                                      
import re                                                                                                                                                                                                           

url = "http://www.howtocallabroad.com/afghanistan" # argentina works fine
html_page = urllib2.urlopen(url)
soup = BeautifulSoup(html_page)

areatable = soup.find('table',{'id':'codes'})
if areatable is None:
    print "areatable is None"
else:
    d = {}

    def chunks(l, n):
            return [l[i : i + n] for i in range(0, len(l), n)]


    all_td = areatable.findAll('td')
    all_td = filter(lambda x: x.attrs == {}, all_td)
    print ">>>>> all_td=", all_td

    li = dict(chunks([i.text for i in all_td], 2))
    print ">>>>> li=", li

2 个答案:

答案 0 :(得分:2)

您的过滤器正在删除这3个名称,因为.attrs != {}

    <tr>
      <td width="25%">Badghis</td>
      <td>41</td>
      <td width="25%">Kabul</td>
      <td>20</td>
      <td width="25%">Panjshar</td>
      <td>28</td>
    </tr>

这就是为什么你得到一个奇怪的数字来成对成对。结果就是将数字修改为不相关的名字,即使它最终有一个偶数。

阿根廷工作正常,因为他们没有额外的宽度属性。

这很痛苦,因为现在你知道他们不仅仅是像任何理智的人那样从模板中填充这些表。有人手动摆弄至少其中一些。

在尝试解析这些类型的页面时,您必须更加防御性地编写代码。

答案 1 :(得分:1)

严格地说,filter没有返回列表不是你的问题的根源(除了事实,它可能过滤掉你不想被过滤掉的项目),但是一个错误你的chunks功能。 dict构造函数采用可迭代的 length 2 的迭代。您的函数chunks并不总是返回对(如果列表具有奇数项目)。


示例:

In [1]: def chunks(l, n):
   ...:     return [l[i : i + n] for i in range(0, len(l), n)]

In [2]: a = chunks(range(4), 2)  # even number of elements

In [3]: b = chunks(range(5), 2)  # odd number of elements

In [4]: a
Out[4]: [[0, 1], [2, 3]]

In [5]: b
Out[5]: [[0, 1], [2, 3], [4]]  # <-- note the trailing [4] at position 2

In [6]: dict(b)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-6-57f7c289a3e5> in <module>()
----> 1 dict(b)

ValueError: dictionary update sequence element #2 has length 1; 2 is required