1

このアフガニスタンのページをスクレイピングすると、次のようなエラーが表示されました。

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

しかし、アルゼンチンのページをスクレイピングすると、コードは正常に実行されます。

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
4

2 に答える 2

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>

これが、奇数をペアにチャンクアップする理由です。その結果、偶数になったとしても、数字を無関係な名前にマングリングすることになります。

アルゼンチンは、そこに余分な幅の属性がないため、うまく機能します。

正気な人のようにテンプレートからこれらのテーブルにデータを入力するだけではないことがわかったので、これは苦痛です。誰かがそれらの少なくともいくつかを手でいじっています。

これらのタイプのページを解析しようとするときは、より防御的にコーディングする必要があります。

于 2013-06-07T05:26:44.437 に答える
1

厳密に言えば、filterリストを返さないことは問題の原因ではありません (フィルターで除外したくないアイテムを除外している可能性があるという事実は別として)、chunks関数のバグです。コンストラクターは、長さ 2dictiterable の iterable を取ります。関数が常にペアを返すとは限りません (リストの項目数が奇数の場合)。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
于 2013-06-07T05:12:19.830 に答える