オープンデータとプログラミング

Python

urlencodeでUnicodeEncodeErrorがでるときの原因と対処方法

事象

以下のような辞書に格納されたデータ

person_j1 = {“name”: u”山田 太郎”, “gender”: “male”, “age”: 18}

を次のようにurlエンコードした場合があります。

‘gender=male&age=18&name=%E5%B1%B1%E7%94%B0+%E5%A4%AA%E9%83%8E’

このときにurllibのurlencodeを使用すると次のようなエラーが発生する場合があります。

UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-1: ordinal not in range(128)

原因

“name”: u”山田 太郎”のようにunicode文字列が含まれているとエラーになります。

実際の例

 
import urllib

person_e = {"name": "Taro Yamada", "gender": "male", "age": 18}
person_j1 = {"name": u"山田 太郎", "gender": "male", "age": 18}      #nameがunicode
person_j2 = {"name": "山田 太郎", "gender": "male", "age": 18}        #nameが文字列

urllib.urlencode(person_e)   #OK
urllib.urlencode(person_j1)  #NG
urllib.urlencode(person_j2)  #OK
 
 

以下のようにエラーになります。


UnicodeEncodeErrorTraceback (most recent call last)
<ipython-input-38-d6c34797cf92> in <module>()
      6 
      7 urllib.urlencode(person_e)   #OK
----> 8 urllib.urlencode(person_j1)  #NG
      9 urllib.urlencode(person_j2)  #OK
     10 

C:\Anaconda2\lib\urllib.pyc in urlencode(query, doseq)
   1341         for k, v in query:
   1342             k = quote_plus(str(k))
-> 1343             v = quote_plus(str(v))
   1344             l.append(k + '=' + v)
   1345     else:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

対処方法

unicode文字列だけ’utf-8’だけエンコードしてやります
数字に対しては.encode(‘utf-8’)できないので、unicode文字列だけencodeしてあげるのがポイントです。

 
 
 

import urllib

person_j1 = {"name": u"山田 太郎", "gender": "male", "age": 18}

person_j1 = dict([k, v.encode('utf-8') if isinstance(v, unicode) else v] for k, v in person_j1.items())
urllib.urlencode(person_j1)  #OK



 
 
 

Pythonでディープラーニングを始めるなら以下の本がおすすめです。

アマゾンならこちら

楽天ならこちら

python: pandasでnull値を判定する

python

pandasでnull値を判定する方法のメモです。
isnull()やnotnull()を使用します。
ちなみに、データフレームにnull値を設定するときはNoneを入れます。

import pandas as pd

df = pd.DataFrame({
        'A' : [1, 2, 2, 3, 3,None,5],
        'B' : [1, 1, 2, 2, None,4,5]
    })

print df
print '------------------------'
print df.loc[df.A.isnull(), :]     #Aがnullの行を表示
print '------------------------'
print df.loc[df.B.isnull(), :]     #Bがnullの行を表示
print '------------------------'
print df.loc[df.A.notnull(), :]    #Aがnull以外の行を表示
print '------------------------'
print df.loc[df.B.notnull(), :]    #Bがnull以外の行を表示

実行結果は以下のようになります。

     A    B
0  1.0  1.0
1  2.0  1.0
2  2.0  2.0
3  3.0  2.0
4  3.0  NaN
5  NaN  4.0
6  5.0  5.0
------------------------
    A    B
5 NaN  4.0
------------------------
     A   B
4  3.0 NaN
------------------------
     A    B
0  1.0  1.0
1  2.0  1.0
2  2.0  2.0
3  3.0  2.0
4  3.0  NaN
6  5.0  5.0
------------------------
     A    B
0  1.0  1.0
1  2.0  1.0
2  2.0  2.0
3  3.0  2.0
5  NaN  4.0
6  5.0  5.0

pandasについての詳しく知りたい方は書籍もおすすめです。

pythonでXMLをパースするときに出る2つのエラーの解決方法

python

pythonでXMLをパースしようとしたときに出くわすエラー2つについて修正方法をメモしておきます。

エラー1
IOError: [Errno 2] No such file or directory: u'<?xml version=”1.0″ encoding=”UTF-8″?> …

エラー2
root = tree.getroot()
AttributeError: ‘Element’ object has no attribute ‘getroot’…

次のソースはよくネットにサンプルとしてよく見かけるコードですが、5行目のところでエラー1がでます。

import xml.etree.ElementTree as ET

req = …(省略) #postした結果XMLが返却されるとする

tree = ET.parse(req.text)  #エラー1
root = tree.getroot() 

#hogehogeを検索
ret=root.find(".//hogehoge").text

req.textにはXMLが入っていますが、これがファイル名だと思われてしまうからですね。
そのため、No such file or directoryと怒られるわけです。
なのでエラーメッセージには、u'<?xml version=”1.0″ encoding=”UTF-8″?> …のようにXMLの内容が表示されています。
parseには、ファイルのパスを渡す必要があります。

IOError: [Errno 2] No such file or directory: u'<?xml version=”1.0″ encoding=”UTF-8″?> …

XMLの文字列をパースする場合には、以下のようにfromstringを使用します。

import xml.etree.ElementTree as ET

req = …(省略) #postした結果XMLが返却されるとする

tree = ET.fromstring(req.text.encode('utf-8'))  #エラー1が解消します
root = tree.getroot()                           #今度はここでエラー2

#hogehogeを検索
ret=root.find(".//hogehoge").text

5行目のエラーが解消されてメデタシメデタシなのですが、今度は6行目でエラーになります。

root = tree.getroot()
AttributeError: ‘Element’ object has no attribute ‘getroot’…

今度は、getrootがないと怒られます。
こちらは次のように修正します。

import xml.etree.ElementTree as ET

req = …(省略) #postした結果XMLが返却されるとする

root = ET.fromstring(req.text.encode('utf-8'))

#hogehogeを検索
ret=root.find(".//hogehoge").text

以上でおしまいです。

pipでPIL(画像ライブラリ)のインストールがうまくいかない場合の解決方法(メモ)

python

pipでPIL(画像ライブラリ)をインストールしようとしてうまくいかなかった場合の対処方法に関するメモです。

PILは古い(2009年開発終了)のでPillowの使用をお勧めします。PIL向けのソースはほぼそのままで動くと思います。
環境:
python 2.7.11
CentOS release 6.7 (Final)

いろいろネットの情報を参考にしてpipを実行しましたがエラーがでてうまくいきません。

$pip install PIL --allow-external PIL --allow-unverified PIL

エラー内容は以下のとおりです。

DEPRECATION: --allow-external has been deprecated and will be removed in the future. Due to changes in the repository protocol, it no longer has any effect.
DEPRECATION: --allow-unverified has been deprecated and will be removed in the future. Due to changes in the repository protocol, it no longer has any effect.
Collecting PIL
  Could not find a version that satisfies the requirement PIL (from versions: )
No matching distribution found for PIL

このような場合は、以下のサイトからソースをダウンロードしてコンパイルします。

最新版をDLします。

Python Imaging Library 1.1.7 Source Kit (all platforms) (November 15, 2009)

適当な場所に解凍したら、ディレクトリに降りてsetup.pyを実行。

$python setup.py install

途中、freetypeのヘッダまわりでエラーになる場合があります。

_imagingft.c:73:31: error: freetype/fterrors.h: そのようなファイルやディレクトリはありません
_imagingft.c:78: error: expected expression before ‘static’
_imagingft.c: In function ‘getfont’:
_imagingft.c:132: error: ‘library’ undeclared (first use in this function)
_imagingft.c:132: error: (Each undeclared identifier is reported only once
_imagingft.c:132: error: for each function it appears in.)
_imagingft.c:144: 警告: passing argument 1 of ‘FT_New_Face’ from incompatible pointer type

この解決方法は、シンボリックリンクを作成してあげればOKです。
※freetypeのインストール場所は環境によって異なる場合があるかもしれませんのでよく確認してください

ln -s /usr/include/freetype2/freetype /usr/local/include/freetype

シンボリックリンクを作成したら再度、setup.pyを実行。

$python setup.py install

以上で完了です。

Py2exeでエラー:ImportError: cannot import name RAND_egd

python

Pythonを2.7.10にアップデートしたら、py2exeでパッケージングしたEXEで以下のエラー。対処方法のメモを残しておく。

Traceback (most recent call last):
  File "price_check.py", line 13, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "openpyxl\__init__.pyo", line 26, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "openpyxl\workbook\__init__.pyo", line 5, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "openpyxl\workbook\workbook.pyo", line 13, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "openpyxl\writer\write_only.pyo", line 17, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "openpyxl\writer\excel.pyo", line 30, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "openpyxl\packaging\manifest.pyo", line 7, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "mimetypes.pyo", line 29, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "urllib.pyo", line 26, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "socket.pyo", line 68, in <module>
ImportError: cannot import name RAND_egd

py2exeはとてもありがたいのだが、この手のエラーが多いのが困る。

暫定的な対応だがsocket.pyRAND_egdをimportしているところをコメントアウトしたらエラーが解消された。

    # we need to import the same constants we used to...
    from _ssl import SSLError as sslerror
    from _ssl import \
         RAND_add, \
         RAND_status, \
         SSL_ERROR_ZERO_RETURN, \
         SSL_ERROR_WANT_READ, \
         SSL_ERROR_WANT_WRITE, \
         SSL_ERROR_WANT_X509_LOOKUP, \
         SSL_ERROR_SYSCALL, \
         SSL_ERROR_SSL, \
         SSL_ERROR_WANT_CONNECT, \
         SSL_ERROR_EOF, \
         SSL_ERROR_INVALID_ERROR_CODE

''' ↓★コメントアウトする
   try:
        from _ssl import RAND_egd
    except ImportError:
        # LibreSSL does not provide RAND_egd
        pass
'''

Pythonでメールクライアント(IMAP)でエラーになる原因

python

こんにちは。

Pythonでメールクライアントを作成し、実行すると以下のメッセージがでる場合があります。

imaplib.error: b'[ALERT] Please log in via your web browser: http://support.google.com/mail/accounts/bin/answer.py?answer=78754 (Failure)’

http://support.google.com/mail/accounts/bin/answer.py?answer=78754

を見てみると、いろいろと原因がかかれていますが、この中で原因になるのが「安全性の低いアプリによるアカウントへのアクセス」です。

安全性の低いアプリがアカウントにアクセスするのを許可する

Google では、最新のセキュリティ標準に対応していないアプリや端末からのログイン操作をブロックする場合があります。このようなアプリや端末は不正使用される恐れが高くなるため、ブロックすることでアカウントの安全性を保つことができます。

たとえば次のようなアプリは、最新のセキュリティ標準に対応していません。
•iOS 6 以下を搭載する iPhone または iPad のメールアプリ
•Windows Phone 8.1 より前のメールアプリ
•一部のデスクトップ メール クライアント(Microsoft Outlook や Mozilla Thunderbird など)

GMailには、安全性の低いアプリのアクセスを制御する設定がありますので、こちらをオンにすればPythonで作成したメールクライアントからアクセスできるようになります。

安全性の低いアプリ

python2.7.9で謎のSSLエラー:CERTIFICATE_VERIFY_FAILED

python

またしても、突然SSLでエラーが出るようになったのでメモ。

urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:581)

python 2.7.9のOpenSSLが古いせいかもしれない。

C:\>python
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> print ssl.OPENSSL_VERSION
OpenSSL 1.0.1j 15 Oct 2014
>>>

Python 2.7.10にアップデートしたら、エラーは解消された。
ちなみにOpenSSLのバージョンは以下のとおり。

C:\>python
Python 2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> print ssl.OPENSSL_VERSION
OpenSSL 1.0.2a 19 Mar 2015
>>>

Pythonで”TypeError: argument of type ‘int’ is not iterable”が出てしまったときのチェックポイント

python

こんにちはPythonをいじっていて、以下のようなエラーに出てしまうことはありませんか?


”TypeError: argument of type ‘int’ is not iterable”

iterableといわれてもさっぱりですが、Python Japanのサイトに説明がありますので見てみましょう。

iterable
(反復可能オブジェクト) 要素を一つずつ返せるオブジェクトです。

反復可能オブジェクトの例には、(list, str, tuple といった) 全てのシーケンス型や、 dict や file といった幾つかの非シーケンス型、あるいは __iter__() か __getitem__() メソッドを実装したクラスのインスタンスが含まれます。

反復可能オブジェクトは for ループ内やその他多くのシーケンス (訳注: ここでのシーケンスとは、シーケンス型ではなくただの列という意味)が必要となる状況 (zip(), map(), …) で利用できます。

反復可能オブジェクトを組み込み関数 iter() の引数として渡すと、オブジェクトに対するイテレータを返します。このイテレータは一連の値を引き渡す際に便利です。反復可能オブジェクトを使う際には、通常 iter() を呼んだり、イテレータオブジェクトを自分で扱う必要はありません。 for 文ではこの操作を自動的に行い、無名の変数を作成してループの間イテレータを記憶します。

ここまで読んでお分かりだと思いますが、要するにintは反復可能オブジェクトではないということです。

具体的な例をみてみましょう。

よくはまる例としては、ある文字(列)が文字列中に含まれるか判定するときに使う、演算子”in”があります。

>>> "1" in "1234"
True
>>>

これはOKですが、ダブルクォーテーションを外すとNGです。

>>> 1 in 1234
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: argument of type 'int' is not iterable

このように直接、数値が記述されている場合は一目瞭然ですが、実際のプログラムでは変数で書かれている場合がほとんどです。
変数で記述されている場合は一見してわからない場合も多いのではないでしょうか。






Pythonでディープラーニングを学ぶならこの本がおすすめ(アマゾンで購入)

Pythonでディープラーニングを学ぶならこの本がおすすめ(楽天で購入)

PyQueryを使ったアプリをpy2exeしたときに動かなかったときのメモ

python

PyQueryを使ったアプリをpy2exeしたときに、実行時に「ImportError: No module named cssselect」がでることがあります。

ちょっとハマぅたのでメモを残しておきます。

Traceback (most recent call last):
  File "XXXXXXXXXXXXXX.py", line XX, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "f2.pyo", line 4, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "pyquery\__init__.pyo", line 11, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "pyquery\pyquery.pyo", line 6, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "pyquery\cssselectpatch.pyo", line 6, in <module>
ImportError: No module named cssselect

この問題の解決手順は次のとおりです。

githubからcssselectのZIPしてきて解凍します。

https://github.com/SimonSapin/cssselect

解凍したファイルの中に次のようなフォルダ・ファイルがありますので、
これをC:\Python27\Lib\site-packages配下に入れるとエラーがでなくなりました。

cssselect/__init__.py
cssselect/parser.py
cssselect/tests.py
cssselect/xpath.py

いかがでしたか?

py2exeのエラーには悩まされますね。