0

Python 2.7.3 と BeuatofulSoup を使用して Web サイトのテーブルからデータを取得し、codecsコンテンツをファイルに書き込むために使用しています。私が収集する変数の 1 つに、時々文字化けがあります。たとえば、Web サイトのテーブルが次のようになっているとします。

 Year    Name   City             State
 2000    John   D’Iberville    MS
 2001    Steve  Arlington        VA

したがって、City変数を生成するときは、常に次のようにエンコードしますutf-8

 Year = foo.text
 Name = foo1.text
 City = foo3.text.encode('utf-8').strip()
 State = foo4.text

 RowsData = ("{0},{1},{2},{3}").format(Year, Name, City, State)

私が作成したカンマ区切りの文字列のリストの内容が呼び出されRowDataRowHeadersこのように見えるように

 RowHeaders = ['Year,Name,City,State']

 RowsData = ['2000, John, D\xc3\xa2\xe2\x82\xac\xe2\x84\xa2Iberville, MS', 
            '2001, Steve, Arlington, VA']

次に、次のコードを使用してこれをファイルに書き込もうとします

 file1 = codecs.open(Outfile.csv,"wb","utf8")
 file1.write(RowHeaders + u'\n')
 line = "\n".join(RowsData)
 file1.write(line + u'\r\n')
 file1.close()

次のエラーが表示されます

 Traceback (most recent call last):  
     File "HSRecruitsFBByPosition.py", line 141, in <module>
       file1.write(line + u'\r\n')

 UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 6879: ordinal not in range(128)

私は csv ライター パッケージを使用でき、RowsData正常に動作します。入りたくない理由により、コーデックを使用して csv ファイルを出力する必要があります。何が起こっているのかわかりません。誰でもこの問題を解決するのを手伝ってもらえますか? 前もって感謝します。

4

2 に答える 2

1

codecs.open() あなたのためにエンコードします。エンコードされたデータを渡さないでください。Python がデータを再度デコードして UTF-8 にエンコードできるようにするためです。その暗黙のデコードは ASCII コーデックを使用しますが、エンコードされたバイト文字列に非 ASCII データがあるため、これは失敗します。

>>> u'D’Iberville'.encode('utf8')
'D\xc3\xa2\xe2\x82\xac\xe2\x84\xa2Iberville'
>>> u'D’Iberville'.encode('utf8').encode('utf8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)

解決策は、*手動でエンコードしないことです:

Year = foo.text
Name = foo1.text
City = foo3.text.strip()
State = foo4.text

codecs.open()は、ファイル ストリームの最も効率的な実装ではないことに注意してください。Python 2.7 では、io.open()代わりに;を使用します。同じ機能を提供しますが、より堅牢に実装されています。このioモジュールは Python 3 のデフォルトの I/O 実装ですが、上位互換性のために Python 2 でも利用できます。

ただし、CSV 処理を再発明しているようです。Python には、 CSV ファイルを生成できる優れたcsvモジュールがあります。ただし、Python 2 では Unicode を処理できないため、手動でエンコードする必要があります。

import csv

# ...

year = foo.text
name = foo1.text
city = foo3.text.strip()
state = foo4.text

row = [year, name, city, state]

with open(Outfile.csv, "wb") as outf:
    writer = csv.writer(outf)
    writer.writerow(['Year', 'Name', 'City', 'State'])
    writer.writerow([c.encode('utf8') for c in row])

最後になりましたが、HTML ページがテキストD’Ibervilleを生成した場合は、Mojibakeを生成しました。UTF-8 を CP-1252 と誤解した場合:

>>> u'D’Iberville'.encode('cp1252').decode('utf8')
u'D\u2019Iberville'
>>> print u'D’Iberville'.encode('cp1252').decode('utf8')
D’Iberville

これは通常、BeautifulSoup のエンコーディング検出 (Unicode ではなくバイト文字列を渡す) をバイパスすることによって発生します。

事後にこれらを試して「修正」することができます:

try:
    City = City.encode('cp1252').decode('utf8')
except UnicodeError:
    # Not a value that could be de-mojibaked, so probably
    # not a Mojibake in the first place.
    pass
于 2014-08-20T07:27:09.407 に答える
0

これ'D\xc3\xa2\xe2\x82\xac\xe2\x84\xa2Iberville'は通常の文字列で、たまたま文字を表すビットがエスケープされています。

したがって、それを書き出すには、まずデコードする必要があります。デコードを指定していないため、Python は ASCII を試行して失敗しています。

>>> s
'D\xc3\xa2\xe2\x82\xac\xe2\x84\xa2Iberville'
>>> type(s)
<type 'str'>
>>> type(s.decode('utf-8'))
<type 'unicode'>
>>> print(s.decode('utf-8'))
D’Iberville

このプロセスを理解する方法は次のとおりです。

  1. まず、文字は人間用、バイトはコンピュータ用であることを理解してください。コンピュータは、私たちがデータを理解できるように、バイトを文字に変換してくれるだけです。

  2. したがって、コンピューターの利益のために何かを保存する必要があるときはいつでも、文字からバイトに変換する必要があります。これはコンピューターが知っていることだからです。すべてのファイル (テキスト ファイルも含む) はバイトです。開くとすぐに、このバイトデータが文字に変換され、その内容を理解できるようになります。「バイナリ」ファイル (画像や Word 文書など) の場合、このプロセスは少し異なります。

  3. 「テキスト」コンテンツを書き込んでいる場合は、グリフ (文字) を取得して、ファイルを書き込めるようにバイトに変換する必要があります。このプロセスはデコードと呼ばれます。

  4. テキスト ファイルを「読み取る」場合、つまりバイトをグリフ (文字またはアルファベット) に変換する場合は、ビットをエンコードする必要があります。つまり、ビットを変換します。格納されたビットに対応するグリフを知るために、ルックアップ テーブルを使用します。このテーブル名 (utf-8) が渡されます。

于 2014-08-20T07:36:06.970 に答える